|
| 1 | +import { |
| 2 | + isLaunchInsideApp, |
| 3 | + request, |
| 4 | + ResponseType, |
| 5 | + setTransparentBackground, |
| 6 | + showActionSheet, |
| 7 | + showModal, |
| 8 | + showNotification, |
| 9 | + showPreviewOptions, |
| 10 | + useStorage, |
| 11 | +} from '@app/lib/help' |
| 12 | + |
| 13 | +interface FundInfo { |
| 14 | + /**基金代码*/ |
| 15 | + FCODE: string |
| 16 | + |
| 17 | + /**基金名字*/ |
| 18 | + SHORTNAME: string |
| 19 | + |
| 20 | + /**日期*/ |
| 21 | + PDATE: string |
| 22 | + |
| 23 | + /**单位净值数值*/ |
| 24 | + NAV: string |
| 25 | + |
| 26 | + /**累计净值数值*/ |
| 27 | + ACCNAV: string |
| 28 | + |
| 29 | + /**单位净值涨跌百分比*/ |
| 30 | + NAVCHGRT: string |
| 31 | + |
| 32 | + /**单位净值估算数值*/ |
| 33 | + GSZ: string |
| 34 | + |
| 35 | + /**单位净值估算涨跌百分比*/ |
| 36 | + GSZZL: string |
| 37 | + |
| 38 | + /**更新时间*/ |
| 39 | + GZTIME: string |
| 40 | + NEWPRICE: string |
| 41 | + CHANGERATIO: string |
| 42 | + ZJL: string |
| 43 | + HQDATE: string |
| 44 | + ISHAVEREDPACKET: boolean |
| 45 | +} |
| 46 | + |
| 47 | +interface FundsData { |
| 48 | + Datas: FundInfo[] |
| 49 | + ErrCode: number |
| 50 | + Success: boolean |
| 51 | + ErrMsg: null | string |
| 52 | + Message: null | string |
| 53 | + ErrorCode: string |
| 54 | + ErrorMessage: null | string |
| 55 | + ErrorMsgLst: null | string |
| 56 | + TotalCount: number |
| 57 | + Expansion: { |
| 58 | + GZTIME: string |
| 59 | + FSRQ: string |
| 60 | + } |
| 61 | +} |
| 62 | + |
| 63 | +const {setStorage, getStorage} = useStorage('Funds') |
| 64 | +const transparentBg: Image | string = getStorage<Image>('transparentBg') || '#fff' |
| 65 | +const textColor = getStorage<string>('textColor') || (transparentBg === '#fff' ? '#000' : '#fff') |
| 66 | +const bgColor = getStorage<string>('bgColor') || '#ffffff00' |
| 67 | +const fundsCode = getStorage<string[]>('fundsCode') || [] |
| 68 | + |
| 69 | +/**生成表格列组件*/ |
| 70 | +function getFundColumn(fundsInfo: FundInfo[], title: string, keyName: keyof FundInfo) { |
| 71 | + // 数值个性化 |
| 72 | + function showValue(value: FundInfo[keyof FundInfo]): Partial<Record<keyof FundInfo, JSX.Element>> { |
| 73 | + return { |
| 74 | + // 涨跌幅文字特别处理(涨绿,跌红) |
| 75 | + GSZZL: ( |
| 76 | + <wtext font={Font.lightSystemFont(14)} textColor={Number(value) >= 0 ? '#4eff4e' : '#ff4e4e'}> |
| 77 | + {value + '%'} |
| 78 | + </wtext> |
| 79 | + ), |
| 80 | + } |
| 81 | + } |
| 82 | + return ( |
| 83 | + <wstack flexDirection="column"> |
| 84 | + <wtext font={14} textColor={textColor}> |
| 85 | + {title} |
| 86 | + </wtext> |
| 87 | + {fundsInfo.map(fundInfo => { |
| 88 | + const value = fundInfo[keyName] |
| 89 | + return ( |
| 90 | + <> |
| 91 | + <wspacer length={14}></wspacer> |
| 92 | + {showValue(value)[keyName] || ( |
| 93 | + <wtext font={Font.lightSystemFont(14)} textColor={textColor}> |
| 94 | + {value} |
| 95 | + </wtext> |
| 96 | + )} |
| 97 | + </> |
| 98 | + ) |
| 99 | + })} |
| 100 | + </wstack> |
| 101 | + ) |
| 102 | +} |
| 103 | + |
| 104 | +class Funds { |
| 105 | + async init() { |
| 106 | + if (isLaunchInsideApp()) { |
| 107 | + return await this.showMenu() |
| 108 | + } |
| 109 | + const widget = (await this.render()) as ListWidget |
| 110 | + Script.setWidget(widget) |
| 111 | + Script.complete() |
| 112 | + } |
| 113 | + |
| 114 | + //渲染组件 |
| 115 | + async render(): Promise<unknown> { |
| 116 | + let fundsInfo: FundInfo[] = [] |
| 117 | + try { |
| 118 | + const result = (await this.getFundsData(this.getFundsCode())).data as FundsData |
| 119 | + fundsInfo = result.Datas || [] |
| 120 | + } catch (err) {} |
| 121 | + |
| 122 | + return ( |
| 123 | + <wbox padding={[0, 0, 0, 0]} background={transparentBg} updateDate={new Date(Date.now() + 30 * 1000)}> |
| 124 | + <wstack padding={[16, 16, 16, 16]} flexDirection="column" background={bgColor}> |
| 125 | + <wstack> |
| 126 | + {getFundColumn(fundsInfo, '基金名字', 'SHORTNAME')} |
| 127 | + <wspacer></wspacer> |
| 128 | + {getFundColumn(fundsInfo, '估算净值', 'GSZ')} |
| 129 | + <wspacer></wspacer> |
| 130 | + {getFundColumn(fundsInfo, '涨跌幅', 'GSZZL')} |
| 131 | + </wstack> |
| 132 | + <wspacer></wspacer> |
| 133 | + <wstack> |
| 134 | + <wspacer></wspacer> |
| 135 | + <wtext font={Font.lightSystemFont(12)} opacity={0.5} textColor={textColor}> |
| 136 | + 更新时间: {new Date().toLocaleTimeString('chinese', {hour12: false})} |
| 137 | + </wtext> |
| 138 | + <wspacer></wspacer> |
| 139 | + </wstack> |
| 140 | + </wstack> |
| 141 | + </wbox> |
| 142 | + ) |
| 143 | + } |
| 144 | + |
| 145 | + // 显示菜单 |
| 146 | + async showMenu() { |
| 147 | + const selectIndex = await showActionSheet({ |
| 148 | + title: '菜单', |
| 149 | + itemList: ['设置基金代码', '预览组件', '设置透明背景', '设置文字和背景颜色'], |
| 150 | + }) |
| 151 | + switch (selectIndex) { |
| 152 | + case 0: |
| 153 | + const {texts: fundsCodeTexts} = await showModal({ |
| 154 | + title: '设置基金代码', |
| 155 | + content: '最多只能设置9个,在中尺寸下只显示前3个, 多个代码用逗号隔开。例如:002207, 002446, 161005', |
| 156 | + inputItems: [ |
| 157 | + { |
| 158 | + text: (getStorage<string[]>('fundsCode') || []).join(', '), |
| 159 | + placeholder: '例如:002207, 002446, 161005', |
| 160 | + }, |
| 161 | + ], |
| 162 | + }) |
| 163 | + if (fundsCodeTexts[0]) { |
| 164 | + const fundsCode = fundsCodeTexts[0].match(/[\d]{6}/g) || [] |
| 165 | + setStorage('fundsCode', fundsCode) |
| 166 | + } |
| 167 | + break |
| 168 | + case 1: |
| 169 | + await showPreviewOptions(this.render.bind(this)) |
| 170 | + break |
| 171 | + case 2: |
| 172 | + const img: Image | null = (await setTransparentBackground()) || null |
| 173 | + img && setStorage('transparentBg', img) |
| 174 | + img && (await showNotification({title: '设置透明背景成功', sound: 'default'})) |
| 175 | + break |
| 176 | + case 3: |
| 177 | + const {texts} = await showModal({ |
| 178 | + title: '设置文字和背景颜色', |
| 179 | + content: '黑色是#000,白色是#fff,半透明白是 #ffffff88, 半透明黑是 #00000088', |
| 180 | + inputItems: [ |
| 181 | + { |
| 182 | + placeholder: `文字颜色,${ |
| 183 | + getStorage('textColor') ? '当前是' + getStorage('textColor') + ',' : '' |
| 184 | + }默认黑色#000`, |
| 185 | + }, |
| 186 | + { |
| 187 | + placeholder: `背景颜色,${ |
| 188 | + getStorage('bgColor') ? '当前是' + getStorage('bgColor') + ',' : '' |
| 189 | + }默认白色#fff`, |
| 190 | + }, |
| 191 | + ], |
| 192 | + }) |
| 193 | + if (texts[0]) setStorage('textColor', texts[0]) |
| 194 | + if (texts[1]) setStorage('bgColor', texts[1]) |
| 195 | + break |
| 196 | + } |
| 197 | + } |
| 198 | + // 获取基金代码数组 |
| 199 | + getFundsCode(): string[] { |
| 200 | + // 大号组件显示9个 |
| 201 | + // 中号组件显示3个 |
| 202 | + const defaultFundsCode = ['002207', '002446', '161005', '163406', '008282', '001790', '008641', '001838', '001475'] |
| 203 | + const _fundsCode = fundsCode.length > 0 ? fundsCode : defaultFundsCode |
| 204 | + return config.widgetFamily === 'medium' ? _fundsCode.slice(0, 3) : _fundsCode.slice(0, 9) |
| 205 | + } |
| 206 | + |
| 207 | + // 生成 device id |
| 208 | + getDeviceId(): string { |
| 209 | + return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, c => { |
| 210 | + const r = (Math.random() * 16) | 0 |
| 211 | + const v = c == 'x' ? r : (r & 0x3) | 0x8 |
| 212 | + return v.toString(16) |
| 213 | + }) |
| 214 | + } |
| 215 | + |
| 216 | + // 获取基金数据 |
| 217 | + async getFundsData(fundsId: string[]): Promise<ResponseType<FundsData>> { |
| 218 | + return request<FundsData>({ |
| 219 | + url: `https://fundmobapi.eastmoney.com/FundMNewApi/FundMNFInfo?pageIndex=1&pageSize=100&plat=Android&appType=ttjj&product=EFund&Version=1&deviceid=${this.getDeviceId()}&Fcodes=${fundsId.join( |
| 220 | + ',', |
| 221 | + )}`, |
| 222 | + dataType: 'json', |
| 223 | + }) |
| 224 | + } |
| 225 | +} |
| 226 | + |
| 227 | +new Funds().init() |
0 commit comments