index.vue 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209
  1. <template>
  2. <u-popup :show="show" @close="hideBrandList" mode="right" class="brand_list_popup">
  3. <view class="brand_list_page">
  4. <view class="brand_list">
  5. <u-navbar class="nav-bar" title="品牌" :autoBack="false" :placeholder="true" v-hideNav @leftClick="hideBrandList">
  6. <!-- <view class="u-nav-slot" slot="right" @click="handleAddBrand">
  7. <u-icon name="plus-circle" color="#2979ff" size="20"></u-icon>
  8. <text>新增</text>
  9. </view> -->
  10. </u-navbar>
  11. <u-search placeholder="搜索" v-model="keyword" @custom="handleSearch" @change="handleSearch"></u-search>
  12. <view class="suggest_list">
  13. <view class="brand_item" v-for="item in adviceList" :key="item.id" @click="handleBrandClick(item)">
  14. <image class="brand_img" :src="item.imgUrl ? item.imgUrl : '/static/no-img.png'" alt=""></image>
  15. <view class="brand_name">{{ item.dictLabel }}</view>
  16. </view>
  17. </view>
  18. </view>
  19. <u-index-list :index-list="indexList" class="index_list">
  20. <template v-for="(item, index) in brandList">
  21. <!-- #ifdef APP-NVUE -->
  22. <u-index-anchor :text="indexList[index]"></u-index-anchor>
  23. <!-- #endif -->
  24. <u-index-item>
  25. <!-- #ifndef APP-NVUE -->
  26. <u-index-anchor :text="indexList[index]"></u-index-anchor>
  27. <!-- #endif -->
  28. <view class="list-cell" v-for="cell in item" :key="cell.dictValue" @click="handleBrandClick(cell)">
  29. <image class="brand_img" :src="cell.imgUrl ? cell.imgUrl : '/static/no-img.png'" alt=""></image>
  30. {{ cell.dictLabel }}
  31. </view>
  32. </u-index-item>
  33. </template>
  34. </u-index-list>
  35. <!-- <view class="no_brand">
  36. <u-button type="primary" :plain="true" text="找不到品牌" color="#108cff"></u-button>
  37. </view> -->
  38. </view>
  39. </u-popup>
  40. </template>
  41. <script>
  42. import { chineseToPinYin } from '@/utils/pinyin.js'
  43. export default {
  44. components: {
  45. },
  46. props: {
  47. },
  48. emits: ['selectedBrand'],
  49. data() {
  50. return {
  51. show: false,
  52. keyword: '',
  53. adviceList: [],
  54. indexList: [],
  55. brandList: [],
  56. list: [],
  57. }
  58. },
  59. methods: {
  60. handleSearch() {
  61. const keyword = this.keyword.trim().toLowerCase();
  62. if (keyword) {
  63. const filteredList = this.list.filter(item => {
  64. const brandName = (item.dictLabel || '').toLowerCase();
  65. return brandName.includes(keyword);
  66. });
  67. this.filterData(filteredList);
  68. } else {
  69. this.filterData(this.list);
  70. }
  71. },
  72. handleBrandClick(brand) {
  73. this.$emit('selectedBrand', brand)
  74. this.hideBrandList()
  75. },
  76. // 显示品牌列表
  77. showBrandList() {
  78. this.getList()
  79. this.show = true;
  80. },
  81. // 隐藏品牌列表
  82. hideBrandList() {
  83. this.show = false;
  84. },
  85. getList() {
  86. this.$getDicts('crm_form_brand').then(res => {
  87. this.filterData(res)
  88. this.list = res
  89. this.adviceList = res.filter(item => item.recommend)
  90. })
  91. },
  92. filterData(res){
  93. const processedData = this.processBrandData(res)
  94. this.brandList = processedData.groupedList
  95. this.indexList = processedData.indexList
  96. },
  97. processBrandData(data) {
  98. // 1. 按每个字符的拼音首字母排序
  99. const sortedData = data.sort((a, b) => {
  100. const labelA = a.dictLabel || ''
  101. const labelB = b.dictLabel || ''
  102. const maxLength = Math.max(labelA.length, labelB.length)
  103. // 逐个字符比较
  104. for (let i = 0; i < maxLength; i++) {
  105. const charA = labelA[i] || ''
  106. const charB = labelB[i] || ''
  107. // 检查是否为英文字符
  108. const isEnglishA = /[a-zA-Z]/.test(charA)
  109. const isEnglishB = /[a-zA-Z]/.test(charB)
  110. if (isEnglishA && isEnglishB) {
  111. // 都是英文,直接比较(忽略大小写)
  112. const upperA = charA.toUpperCase()
  113. const upperB = charB.toUpperCase()
  114. if (upperA !== upperB) {
  115. return upperA.localeCompare(upperB)
  116. }
  117. } else if (isEnglishA) {
  118. // 只有A是英文,英文排在前面
  119. return -1
  120. } else if (isEnglishB) {
  121. // 只有B是英文,英文排在前面
  122. return 1
  123. } else {
  124. // 都不是英文,比较拼音首字母
  125. let pinyinA = ''
  126. let pinyinB = ''
  127. try {
  128. pinyinA = chineseToPinYin(charA).charAt(0).toUpperCase()
  129. } catch (error) {
  130. pinyinA = '#'
  131. }
  132. try {
  133. pinyinB = chineseToPinYin(charB).charAt(0).toUpperCase()
  134. } catch (error) {
  135. pinyinB = '#'
  136. }
  137. if (pinyinA !== pinyinB) {
  138. if (pinyinA === '#') return 1
  139. if (pinyinB === '#') return -1
  140. return pinyinA.localeCompare(pinyinB)
  141. }
  142. }
  143. }
  144. // 如果所有字符都相同,则按长度排序
  145. return labelA.length - labelB.length
  146. })
  147. // 2. 按首字母分组
  148. const groupedData = {}
  149. const indexList = []
  150. for (const item of sortedData) {
  151. let firstLetter
  152. const label = item.dictLabel || ''
  153. try {
  154. const firstChar = label.charAt(0) || ''
  155. if (/[a-zA-Z]/.test(firstChar)) {
  156. // 英文直接使用大写
  157. firstLetter = firstChar.toUpperCase()
  158. } else {
  159. // 中文使用拼音首字母
  160. const pinyin = chineseToPinYin(firstChar)
  161. if (pinyin && pinyin.length > 0 && /[a-zA-Z]/.test(pinyin.charAt(0))) {
  162. firstLetter = pinyin.charAt(0).toUpperCase()
  163. } else {
  164. firstLetter = '#'
  165. }
  166. }
  167. } catch (error) {
  168. firstLetter = '#'
  169. }
  170. // 创建字母分组
  171. if (!groupedData[firstLetter]) {
  172. groupedData[firstLetter] = []
  173. indexList.push(firstLetter)
  174. }
  175. groupedData[firstLetter].push(item)
  176. }
  177. // 3. 按字母顺序排序索引列表
  178. indexList.sort((a, b) => {
  179. if (a === '#') return 1
  180. if (b === '#') return -1
  181. return a.localeCompare(b)
  182. })
  183. // 4. 将分组数据转换为数组格式
  184. const groupedList = indexList.map(letter => groupedData[letter])
  185. return {
  186. groupedList,
  187. indexList
  188. }
  189. },
  190. }
  191. }
  192. </script>
  193. <style lang="scss" scoped>
  194. @import './index.scss';
  195. </style>