|
35 | 35 | } |
36 | 36 |
|
37 | 37 | export let options = [] |
| 38 | + let typeSortOrder = 'none' |
| 39 | + let sortedOptions = [] |
| 40 | +
|
| 41 | + const getTypeLabel = (item) => (item.alias || item.type || '').trim() |
| 42 | + const getSortBucket = (label) => { |
| 43 | + if (!label) return 3 |
| 44 | + const firstChar = label[0] |
| 45 | + if (/\d/.test(firstChar) || /[^\p{L}\p{N}]/u.test(firstChar)) return 0 |
| 46 | + if (/\p{Script=Latin}/u.test(firstChar)) return 1 |
| 47 | + if (/[\u3400-\u9FFF]/.test(firstChar)) return 2 |
| 48 | + return 3 |
| 49 | + } |
| 50 | +
|
| 51 | + const baseSortOptions = { numeric: true, sensitivity: 'base' } |
| 52 | + const defaultCollator = new Intl.Collator('en', baseSortOptions) |
| 53 | + const pinyinCollator = new Intl.Collator('zh-u-co-pinyin', baseSortOptions) |
| 54 | + const compareByTypeLabel = (left, right) => { |
| 55 | + const leftLabel = getTypeLabel(left) |
| 56 | + const rightLabel = getTypeLabel(right) |
| 57 | + const bucketDiff = getSortBucket(leftLabel) - getSortBucket(rightLabel) |
| 58 | + if (bucketDiff !== 0) return bucketDiff |
| 59 | + if (getSortBucket(leftLabel) === 2) return pinyinCollator.compare(leftLabel, rightLabel) |
| 60 | + return defaultCollator.compare(leftLabel, rightLabel) |
| 61 | + } |
| 62 | +
|
| 63 | + $: { |
| 64 | + if (typeSortOrder === 'asc') { |
| 65 | + sortedOptions = [...options].sort(compareByTypeLabel) |
| 66 | + } else if (typeSortOrder === 'desc') { |
| 67 | + sortedOptions = [...options].sort((left, right) => compareByTypeLabel(right, left)) |
| 68 | + } else { |
| 69 | + sortedOptions = options |
| 70 | + } |
| 71 | + } |
38 | 72 |
|
39 | 73 | // 计算转换后的总资产并更新到 store |
40 | 74 | $: { |
|
91 | 125 | const onResetClick = () => { |
92 | 126 | dispatch('reset') |
93 | 127 | } |
| 128 | +
|
| 129 | + const onTypeSortToggle = () => { |
| 130 | + if (typeSortOrder === 'none') { |
| 131 | + typeSortOrder = 'asc' |
| 132 | + } else if (typeSortOrder === 'asc') { |
| 133 | + typeSortOrder = 'desc' |
| 134 | + } else { |
| 135 | + typeSortOrder = 'none' |
| 136 | + } |
| 137 | + } |
94 | 138 | </script> |
95 | 139 |
|
96 | 140 | <Card |
|
102 | 146 | </div> |
103 | 147 | <Table hoverable={true} striped={true} class="divide-y last:border-b-0"> |
104 | 148 | <TableHead class="text-sm"> |
105 | | - <TableHeadCell>{$_('type')}</TableHeadCell> |
| 149 | + <TableHeadCell> |
| 150 | + <button |
| 151 | + type="button" |
| 152 | + class="hover:text-brand inline-flex items-center gap-2 focus:outline-none" |
| 153 | + on:click={onTypeSortToggle}> |
| 154 | + <span>{$_('type')}</span> |
| 155 | + {#if typeSortOrder === 'asc'} |
| 156 | + <span class="text-xs">A-Z</span> |
| 157 | + {:else if typeSortOrder === 'desc'} |
| 158 | + <span class="text-xs">Z-A</span> |
| 159 | + {/if} |
| 160 | + </button> |
| 161 | + </TableHeadCell> |
106 | 162 | <TableHeadCell>{$_('amount')}</TableHeadCell> |
107 | 163 | <TableHeadCell>{$_('currency')}</TableHeadCell> |
108 | 164 | <TableBodyCell><span class="px-4 py-2">{$_('action')}</span></TableBodyCell> |
109 | 165 | <TableBodyCell><span class="px-4 py-2">{$_('action')}</span></TableBodyCell> |
110 | 166 | </TableHead> |
111 | 167 | <TableBody tableBodyClass="py-4"> |
112 | | - {#each options as item (item.type)} |
| 168 | + {#each sortedOptions as item (item.type)} |
113 | 169 | <TableBodyRow> |
114 | 170 | <TableBodyCell>{item.alias || item.type}</TableBodyCell> |
115 | 171 | <TableBodyCell> |
|
0 commit comments