skuSelect.vue 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342
  1. <template>
  2. <div class="component-sku-select">
  3. <el-dialog
  4. v-model.sync="show"
  5. class="custom-select-sku-dialog"
  6. title="选择SKU"
  7. :close-on-click-modal="false"
  8. :close-on-press-escape="false"
  9. :before-close="close"
  10. width="1200px"
  11. >
  12. <div
  13. v-loading="loading"
  14. class="flex items-start"
  15. style="max-height: 100%"
  16. >
  17. <div class="max-h-[800px] overflow-auto min-w-[180px]">
  18. <el-input
  19. v-model="keywords"
  20. placeholder="SKU / 商品名"
  21. style="margin-bottom: 24px"
  22. @keyup.enter="search"
  23. >
  24. <template #append>
  25. <el-button
  26. size="small"
  27. @click="search"
  28. >
  29. 查询
  30. </el-button>
  31. </template>
  32. </el-input>
  33. <div class="catgory-area">
  34. <el-tree
  35. node-key="id"
  36. :default-expanded-keys="defaultExpandID"
  37. :data="categoryList"
  38. :props="defaultProps"
  39. @node-click="clickNode"
  40. ></el-tree>
  41. </div>
  42. </div>
  43. <div class="flex-auto pl-[24px]">
  44. <el-button
  45. v-if="scene !== 'changeOrder'"
  46. type="primary"
  47. class="mb-2"
  48. @click="dialogApplySkuVisible = true"
  49. >
  50. 申请
  51. </el-button>
  52. <div
  53. v-if="skuList.length"
  54. class="sku-area flex flex-wrap items-center"
  55. >
  56. <div
  57. v-for="sku in skuList"
  58. :key="sku.id"
  59. class="sku-item"
  60. >
  61. <div class="image flex justify-center">
  62. <img
  63. v-if="sku.images.length"
  64. :src="sku.images[0]"
  65. class="h-[100%] w-auto"
  66. />
  67. </div>
  68. <div class="sku-name">{{ sku.product_name }}</div>
  69. <div class="flex justify-between items-center">
  70. <div class="sku-code">Product Code: {{ sku.product_sku }}</div>
  71. <el-button
  72. type="primary"
  73. size="small"
  74. plain
  75. @click="selectSku(sku)"
  76. >
  77. 使用
  78. </el-button>
  79. </div>
  80. </div>
  81. </div>
  82. <div
  83. v-else-if="scene === 'changeOrder'"
  84. class="sku-area flex-auto flex items-center"
  85. style="padding-left: 25%"
  86. >
  87. 未找到你想要的Indent商品
  88. </div>
  89. <div
  90. v-else
  91. class="sku-area flex-auto flex items-center"
  92. style="padding-left: 25%"
  93. >
  94. 未找到你想要的Indent商品, 可进行
  95. <el-button
  96. link
  97. type="primary"
  98. @click="dialogApplySkuVisible = true"
  99. >
  100. 申请
  101. </el-button>
  102. </div>
  103. </div>
  104. </div>
  105. <template #footer>
  106. <div class="flex items-center justify-end">
  107. <el-pagination
  108. v-show="total > 0"
  109. v-model:current-page="pageForm.page"
  110. v-model:page-size="pageForm.limit"
  111. :page-sizes="[10, 20, 50, 100]"
  112. :total="total"
  113. :layout="'total, sizes, prev, pager, next, jumper'"
  114. @size-change="getSku"
  115. @current-change="getSku"
  116. />
  117. </div>
  118. </template>
  119. </el-dialog>
  120. <sku-apply
  121. v-model:visible="dialogApplySkuVisible"
  122. @apply="onSkuApply"
  123. ></sku-apply>
  124. </div>
  125. </template>
  126. <script lang="ts" setup>
  127. import { defineComponent, ref, inject, watch } from 'vue'
  128. import { ElButton, ElInput, ElTree, ElDialog, ElPagination } from 'element-plus'
  129. import algoliasearch from 'algoliasearch'
  130. import { getCategoryTree, getSkuList } from '@/api/indent.js'
  131. import skuApply from './skuApply.vue'
  132. defineComponent({
  133. name: 'ComponentSkuSelect',
  134. })
  135. const $mediaRegExp = inject('mediaRegExp') as RegExp
  136. const { visible = false, scene = '' } = defineProps<{ visible: boolean; scene?: string }>()
  137. const $emit = defineEmits(['update:visible', 'select'])
  138. const defaultProps = {
  139. children: 'children',
  140. label: 'name',
  141. }
  142. const dialogApplySkuVisible = ref(false)
  143. const loading = ref(false)
  144. const keywords = ref('')
  145. const defaultExpandID = ref([] as any[])
  146. const show = ref(false)
  147. const currentCategory = ref('')
  148. const categoryList = ref([] as any[])
  149. const skuList = ref([] as any[])
  150. const pageForm = ref({
  151. page: 1,
  152. limit: 20,
  153. })
  154. const total = ref(0)
  155. const onSkuApply = (data: any) => {
  156. $emit('select', {
  157. product_name: data.product_name,
  158. product_sku: '申请中',
  159. id: data.id,
  160. })
  161. close()
  162. }
  163. const search = () => {
  164. currentCategory.value = ''
  165. skuList.value = []
  166. pageForm.value = {
  167. page: 1,
  168. limit: 20,
  169. }
  170. total.value = 0
  171. getSku()
  172. }
  173. const resetData = () => {
  174. currentCategory.value = ''
  175. categoryList.value = []
  176. skuList.value = []
  177. pageForm.value = {
  178. page: 1,
  179. limit: 20,
  180. }
  181. total.value = 0
  182. }
  183. const selectSku = (item: any) => {
  184. $emit('select', item)
  185. close()
  186. }
  187. const clickNode = (obj: any) => {
  188. currentCategory.value = obj.name
  189. }
  190. const getCategory = () => {
  191. getCategoryTree().then((response: any) => {
  192. const res = response.result
  193. categoryList.value = res
  194. categoryList.value.forEach((i) => {
  195. defaultExpandID.value.push(i.id)
  196. i.path = `${i.id}`
  197. if (Array.isArray(i.children) && i.children.length > 0) {
  198. i.children.forEach((son: any) => {
  199. son.path = `${i.id},${son.id}`
  200. if (Array.isArray(son.children) && son.children.length > 0) {
  201. defaultExpandID.value.push(son.id)
  202. son.children.forEach((grandson: any) => {
  203. grandson.path = `${i.id},${son.id},${grandson.id}`
  204. })
  205. }
  206. })
  207. }
  208. })
  209. })
  210. }
  211. let index = ref({} as any)
  212. const initAI = () => {
  213. const client = algoliasearch('7BX4P6RSP2', 'aa9ec8e7e12a6633e7924fab6487e6af')
  214. index.value = client.initIndex('indent_app')
  215. }
  216. const getSku = () => {
  217. loading.value = true
  218. index.value
  219. .search(currentCategory.value || keywords.value, {
  220. hitsPerPage: pageForm.value.limit,
  221. page: pageForm.value.page - 1,
  222. })
  223. .then((response: any) => {
  224. const res = response.hits
  225. let temp = res.map((item: any) => {
  226. const t =
  227. typeof item.images === 'string'
  228. ? `${item.images}`.split(',').filter((i: string) => i.length > 0)
  229. : []
  230. return {
  231. ...item,
  232. images: t.map((i: string) => {
  233. return $mediaRegExp.test(i) ? i : import.meta.env.VITE_APP_OSS_PREFIX + i
  234. }),
  235. }
  236. })
  237. // product_type属性有几种类型 indent Express Stock Other. 把他们按这个顺序排雷, 所有indent要出现在嘴在前面, Other在最后面
  238. temp.sort((a: any, b: any) => {
  239. const order = ['indent', 'Express', 'Stock', 'Other']
  240. return order.indexOf(a.product_type) - order.indexOf(b.product_type)
  241. })
  242. skuList.value = temp
  243. total.value = response.nbHits > 1000 ? 1000 : response.nbHits
  244. })
  245. .finally(() => {
  246. loading.value = false
  247. })
  248. }
  249. watch(
  250. () => visible,
  251. () => {
  252. show.value = visible
  253. resetData()
  254. if (show.value) {
  255. initAI()
  256. setTimeout(() => {
  257. getSku()
  258. }, 500)
  259. getCategory()
  260. }
  261. },
  262. )
  263. watch(currentCategory, () => {
  264. if (!currentCategory.value) return
  265. keywords.value = ''
  266. skuList.value = []
  267. pageForm.value = {
  268. page: 1,
  269. limit: 20,
  270. }
  271. total.value = 0
  272. getSku()
  273. })
  274. const close = (done = {} as any) => {
  275. $emit('update:visible', false)
  276. if (typeof done === 'function') done()
  277. }
  278. </script>
  279. <style lang="scss">
  280. .component-sku-select {
  281. .custom-select-sku-dialog {
  282. margin-top: 0 !important;
  283. margin-bottom: 0 !important;
  284. height: 100vh;
  285. .el-dialog__body {
  286. position: relative;
  287. // max-height: 87vh;
  288. // overflow-y: scroll;
  289. // overflow-x: auto;
  290. padding-top: 8px;
  291. padding-bottom: 8px;
  292. }
  293. }
  294. }
  295. </style>
  296. <style lang="scss" scoped>
  297. .component-sku-select {
  298. .catgory-area {
  299. width: 180px;
  300. min-width: 180px;
  301. border: 1px solid #eee;
  302. padding: 0 12px 24px 0;
  303. }
  304. .sku-area {
  305. width: 100%;
  306. // padding-left: 24px;
  307. height: 82vh;
  308. overflow-y: auto;
  309. }
  310. .sku-item {
  311. border: 1px solid #eee;
  312. padding: 12px;
  313. width: 280px;
  314. margin: 0 18px 12px 0;
  315. .sku-name {
  316. overflow: hidden;
  317. font-size: 18px;
  318. line-height: 24px;
  319. height: 48px;
  320. max-height: 48px;
  321. color: #222;
  322. margin-bottom: 8px;
  323. word-break: break-word;
  324. }
  325. .sku-code {
  326. color: #409eff;
  327. }
  328. .image {
  329. border: 1px solid #eee;
  330. position: relative;
  331. width: 100%;
  332. height: 120px;
  333. margin-bottom: 8px;
  334. }
  335. }
  336. }
  337. </style>