list.vue 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502
  1. <template>
  2. <div class="page-indent-list py-4 px-2 shadow max-w-[1800px] mx-auto">
  3. <el-form
  4. ref="searchForm"
  5. :inline="true"
  6. :model="form"
  7. label-width="110px"
  8. >
  9. <div class="flex flex-wrap items-center search-form">
  10. <el-form-item :label="$t(prefix + 'label_project_name') + ':'">
  11. <el-input v-model="form.name"></el-input>
  12. </el-form-item>
  13. <el-form-item :label="$t(prefix + 'label_category') + ':'">
  14. <el-cascader
  15. v-model="form.category"
  16. :options="categoryList"
  17. :props="{ label: 'name', value: 'id' }"
  18. ></el-cascader>
  19. </el-form-item>
  20. <el-form-item :label="$t(prefix + 'label_status') + ':'">
  21. <el-select
  22. v-model="form.status"
  23. clearable
  24. >
  25. <el-option
  26. v-for="item in statusList"
  27. :key="item.value"
  28. :label="item.label"
  29. :value="item.value"
  30. ></el-option>
  31. </el-select>
  32. </el-form-item>
  33. <div class="flex items-center btn-group">
  34. <el-button
  35. size="small"
  36. type="primary"
  37. @click="search"
  38. >
  39. {{ $t('btn_query') }}
  40. </el-button>
  41. <el-button
  42. size="small"
  43. type="default"
  44. @click="reset"
  45. >
  46. {{ $t('btn_reset') }}
  47. </el-button>
  48. </div>
  49. </div>
  50. </el-form>
  51. <div class="mb-2 flex justify-between">
  52. <el-button
  53. size="small"
  54. type="primary"
  55. @click="componentEditVisible = 1"
  56. >
  57. {{ $t('btn_add') }}
  58. </el-button>
  59. <el-form inline>
  60. <el-form-item label="审核人:">
  61. <el-select
  62. v-model="auditUser"
  63. :loading="setAuditUserLoading"
  64. class="min-w-[200px]"
  65. filterable
  66. placeholder="可搜索"
  67. size="small"
  68. >
  69. <el-option
  70. v-for="user in userList"
  71. :key="user.id"
  72. :value="user.id"
  73. :label="`${user.name} (${user.username})`"
  74. ></el-option>
  75. </el-select>
  76. </el-form-item>
  77. <el-form-item>
  78. <el-tooltip content="保存审核人">
  79. <el-button
  80. type="primary"
  81. size="small"
  82. :loading="setAuditUserLoading"
  83. @click="setAuditUser"
  84. >
  85. 保存
  86. </el-button>
  87. </el-tooltip>
  88. </el-form-item>
  89. </el-form>
  90. </div>
  91. <el-table
  92. ref="tableIndent"
  93. :header-cell-style="{ backgroundColor: '#F2F6FC' }"
  94. :row-style="{ backgroundColor: '#F2F6FC' }"
  95. :data="list"
  96. default-expand-all
  97. border
  98. >
  99. <el-table-column type="index"></el-table-column>
  100. <el-table-column
  101. v-for="value in mainTableConfig"
  102. :key="value.field"
  103. :align="value.align || 'center'"
  104. :width="value.width || ''"
  105. :prop="value.field"
  106. :label="$t(value.label)"
  107. >
  108. <template #default="scope">
  109. <div v-if="value.type === 'imageList'">
  110. <img
  111. v-if="scope.row[value.field].length"
  112. style="width: 100%"
  113. :src="scope.row[value.field][0]"
  114. @click="imgClick(scope.row[value.field][0])"
  115. />
  116. </div>
  117. <div v-else-if="value.field === 'status'">
  118. <div>
  119. {{ getStatusLabel(scope.row[value.field]) }}
  120. </div>
  121. <el-button
  122. size="small"
  123. type="primary"
  124. link
  125. @click="openRecord(scope.row)"
  126. >
  127. {{ $t(prefix + 'label_audit_detail') }}
  128. </el-button>
  129. </div>
  130. <div
  131. v-else
  132. class="table-cell-content"
  133. :style="value.style || {}"
  134. >
  135. {{ scope.row[value.field] }}
  136. </div>
  137. </template>
  138. </el-table-column>
  139. <el-table-column
  140. prop="status"
  141. width="220"
  142. :label="$t('table_operation')"
  143. >
  144. <template #default="scope">
  145. <el-button
  146. size="small"
  147. type="primary"
  148. :disabled="scope.row.status === 0"
  149. @click="edit(scope.row)"
  150. >
  151. {{ $t('btn_edit') }}
  152. </el-button>
  153. <el-button
  154. size="small"
  155. type="warning"
  156. :disabled="scope.row.status !== 0"
  157. @click="examine(scope.row)"
  158. >
  159. {{ $t('btn_audit') }}
  160. </el-button>
  161. <el-button
  162. :disabled="scope.row.status !== 2"
  163. size="small"
  164. type="danger"
  165. @click="deleteProductFunc(scope.row)"
  166. >
  167. {{ $t('btn_delete') }}
  168. </el-button>
  169. </template>
  170. </el-table-column>
  171. </el-table>
  172. <div class="flex justify-end my-4">
  173. <el-pagination
  174. v-show="total > 0"
  175. v-model:current-page="pageForm.page"
  176. v-model:page-size="pageForm.limit"
  177. v-model:total="total"
  178. layout="prev, pager, next, jumper, sizes"
  179. @current-change="getList"
  180. @size-change="getList"
  181. />
  182. </div>
  183. <comp-edit
  184. v-model:visible="componentEditVisible"
  185. :product-data="dataForEdit"
  186. :category-data="categoryList"
  187. @update:visible="getList"
  188. ></comp-edit>
  189. <comp-record
  190. :id="recordId"
  191. v-model:visible="componentRecordVisible"
  192. :status-list="statusList"
  193. ></comp-record>
  194. <comp-examine
  195. v-model:visible="componentExamineVisible"
  196. :category-data="categoryList"
  197. :data-for-examine="dataForEaxmine"
  198. @update:visible="getList"
  199. ></comp-examine>
  200. <el-dialog
  201. v-model="bigImageVisible"
  202. style="margin: 5vh auto"
  203. width="800"
  204. >
  205. <div class="flex justify-center">
  206. <img
  207. :src="currentBigImage"
  208. style="max-width: 100%; height: auto"
  209. alt=""
  210. />
  211. </div>
  212. </el-dialog>
  213. </div>
  214. </template>
  215. <script lang="ts" setup>
  216. import { defineComponent, ref, inject, watch } from 'vue'
  217. import {
  218. ElButton,
  219. ElForm,
  220. ElFormItem,
  221. ElInput,
  222. ElTable,
  223. ElTableColumn,
  224. ElSelect,
  225. ElOption,
  226. ElMessageBox,
  227. ElNotification,
  228. ElPagination,
  229. ElCascader,
  230. ElDialog,
  231. ElTooltip,
  232. ElMessage,
  233. } from 'element-plus'
  234. import compEdit from './components/edit.vue'
  235. import compRecord from './components/record.vue'
  236. import compExamine from './components/examine.vue'
  237. import { $t } from '@/i18n/index'
  238. import { getProductList, deleteProduct } from '@/api/product.js'
  239. import { getCategoryTree } from '@/api/indent.js'
  240. import userAPI from '@/api/user'
  241. defineComponent({
  242. name: 'ComponentIndentProductList',
  243. })
  244. const $mediaRegExp = inject('mediaRegExp') as RegExp
  245. const prefix = 'order.product.'
  246. let componentEditVisible = ref(0) // 1 新增, 2编辑. 0关闭
  247. let componentRecordVisible = ref(false) // 审核记录
  248. let componentExamineVisible = ref(false) // 审核
  249. let dataForEaxmine = ref({})
  250. let dataForEdit = ref({}) // 修改时用, 只是用作传递给子组件数据的变量
  251. let recordId = ref('')
  252. let loading = ref(false)
  253. let categoryList = ref([])
  254. let form = ref({
  255. name: '',
  256. category: [],
  257. status: '',
  258. } as any)
  259. let total = ref(0)
  260. let pageForm = ref({
  261. page: 1,
  262. limit: 20,
  263. })
  264. let list = ref([])
  265. const mainTableConfig: any[] = [
  266. {
  267. label: 'order.product.label_img',
  268. type: 'imageList',
  269. field: 'images',
  270. width: '120',
  271. },
  272. {
  273. label: 'order.product.label_product_code',
  274. field: 'product_sku',
  275. width: '180',
  276. },
  277. {
  278. label: 'order.product.label_name',
  279. field: 'product_name',
  280. // style: 'text-align: left'
  281. },
  282. {
  283. label: 'order.product.label_status',
  284. field: 'status',
  285. width: '110',
  286. style: 'font-weight: bold;',
  287. },
  288. {
  289. label: 'table_operator',
  290. field: 'admin_name',
  291. width: '90',
  292. },
  293. {
  294. label: 'table_operated_time',
  295. field: 'update_time',
  296. width: '180',
  297. },
  298. ]
  299. const statusList = [
  300. {
  301. value: 0,
  302. label: '待审核',
  303. },
  304. {
  305. value: 1,
  306. label: '审核通过',
  307. },
  308. {
  309. value: 2,
  310. label: '审核不通过',
  311. },
  312. ]
  313. const search = () => {
  314. pageForm.value = {
  315. page: 1,
  316. limit: 20,
  317. }
  318. getList()
  319. }
  320. const getStatusLabel = (value: number) => {
  321. const temp = statusList.filter((i: any) => i.value === value)
  322. return temp.length ? temp[0].label : '-'
  323. }
  324. const reset = () => {
  325. form.value = {
  326. name: '',
  327. category: [],
  328. status: 0,
  329. }
  330. pageForm.value = {
  331. page: 1,
  332. limit: 20,
  333. }
  334. total.value = 0
  335. getList()
  336. }
  337. const edit = (row: any) => {
  338. dataForEdit.value = row
  339. componentEditVisible.value = 2
  340. }
  341. const deleteProductFunc = (row: any) => {
  342. ElMessageBox.confirm('将删除该商品, 是否继续?', '提示', {
  343. confirmButtonText: '确定',
  344. cancelButtonText: '取消',
  345. type: 'warning',
  346. }).then(() => {
  347. deleteProduct({ id: row.id }).then((res: any) => {
  348. if (res.code === 1) {
  349. getList()
  350. ElNotification({
  351. title: '删除成功',
  352. message: '正在刷新数据',
  353. duration: 3000,
  354. })
  355. }
  356. })
  357. })
  358. }
  359. const examine = (row: any) => {
  360. dataForEaxmine.value = row
  361. componentExamineVisible.value = true
  362. }
  363. const openRecord = (row: any) => {
  364. recordId.value = row.id
  365. componentRecordVisible.value = true
  366. }
  367. const getList = () => {
  368. const p: any = Object.assign({}, pageForm.value)
  369. const temp = { k: '', category: '', status: '' }
  370. if (form.value.category.length) {
  371. temp.category = form.value.category.join(',')
  372. }
  373. if (form.value.name?.length) {
  374. temp.k = form.value.name.trim()
  375. }
  376. if (statusList.map((i) => i.value).includes(form.value.status)) {
  377. temp.status = `${form.value.status}`
  378. }
  379. if (Object.keys(temp).length) {
  380. p.searchParams = JSON.stringify(temp)
  381. }
  382. loading.value = true
  383. getProductList(p)
  384. .then((res: any) => {
  385. list.value =
  386. res.result?.data?.map((main: any) => {
  387. const t =
  388. typeof main.images === 'string'
  389. ? `${main.images}`.split(',').filter((i: string) => i.length > 0)
  390. : []
  391. let status = Number(main.status)
  392. if (typeof status !== 'number') status = 0
  393. return {
  394. ...main,
  395. status,
  396. images: t.map((i: string) => {
  397. return $mediaRegExp.test(i)
  398. ? i
  399. : import.meta.env.VITE_APP_OSS_PREFIX + i
  400. }),
  401. }
  402. }) || []
  403. total.value = res.result.total
  404. })
  405. .finally(() => {
  406. loading.value = false
  407. })
  408. }
  409. const getCategoryList = () => {
  410. getCategoryTree().then((response: any) => {
  411. const res = response.result
  412. categoryList.value = res
  413. })
  414. }
  415. getList()
  416. getCategoryList()
  417. const currentBigImage = ref('')
  418. const bigImageVisible = ref(false)
  419. const imgClick = (url: string) => {
  420. currentBigImage.value = url
  421. bigImageVisible.value = true
  422. }
  423. watch(bigImageVisible, () => {
  424. if (!bigImageVisible.value) currentBigImage.value = ''
  425. })
  426. const userList = ref([] as any[])
  427. const getUserListFunc = () => {
  428. userAPI
  429. .getUserList({
  430. page: 1,
  431. limit: 200,
  432. })
  433. .then((res: any) => {
  434. if (res.code !== 1) {
  435. return
  436. }
  437. userList.value =
  438. res.result.data
  439. .filter((i: any) => i.status === 1)
  440. .sort((a: any, b: any) => a.name.localeCompare(b.name)) || []
  441. })
  442. }
  443. getUserListFunc()
  444. const auditUser = ref('')
  445. const getCurrentAuditUser = () => {
  446. userAPI.getAuditUser().then((res: any) => {
  447. console.log(res, 'res')
  448. if (
  449. res.code === 1 &&
  450. Array.isArray(res.result.data) &&
  451. res.result.data.length
  452. ) {
  453. const temp = res.result.data.filter((i: any) => i.type === 2)
  454. console.log(temp, 'temp')
  455. if (temp.length) auditUser.value = temp[0].check_id
  456. }
  457. })
  458. }
  459. getCurrentAuditUser()
  460. const setAuditUserLoading = ref(false)
  461. const setAuditUser = () => {
  462. setAuditUserLoading.value = true
  463. userAPI
  464. .setAuditUser({ check_id: auditUser.value, type: 2 })
  465. .then((res: any) => {
  466. console.log(res, 'res')
  467. if (res.code === 1) {
  468. ElMessage.success('设置成功')
  469. }
  470. })
  471. .finally(() => (setAuditUserLoading.value = false))
  472. }
  473. </script>
  474. <style lang="scss" scoped>
  475. .search-form {
  476. .el-input,
  477. .el-select,
  478. .el-date-editor {
  479. width: 220px;
  480. }
  481. .btn-group {
  482. margin: 0 0 22px 8px;
  483. }
  484. }
  485. </style>