From a1d7e81859f554f3a53680cc35f0f49bf1f77098 Mon Sep 17 00:00:00 2001
From: wwf <1971391498@qq.com>
Date: 星期四, 14 五月 2026 14:37:02 +0800
Subject: [PATCH] 导入项目
---
src/views/mall/product/spu/components/SpuTableSelect.vue | 303 ++++++++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 303 insertions(+), 0 deletions(-)
diff --git a/src/views/mall/product/spu/components/SpuTableSelect.vue b/src/views/mall/product/spu/components/SpuTableSelect.vue
new file mode 100644
index 0000000..4775e11
--- /dev/null
+++ b/src/views/mall/product/spu/components/SpuTableSelect.vue
@@ -0,0 +1,303 @@
+<template>
+ <Dialog v-model="dialogVisible" :appendToBody="true" title="閫夋嫨鍟嗗搧" width="70%">
+ <ContentWrap>
+ <el-form
+ ref="queryFormRef"
+ :inline="true"
+ :model="queryParams"
+ class="-mb-15px"
+ label-width="68px"
+ >
+ <el-form-item label="鍟嗗搧鍚嶇О" prop="name">
+ <el-input
+ v-model="queryParams.name"
+ class="!w-240px"
+ clearable
+ placeholder="璇疯緭鍏ュ晢鍝佸悕绉�"
+ @keyup.enter="handleQuery"
+ />
+ </el-form-item>
+ <el-form-item label="鍟嗗搧鍒嗙被" prop="categoryId">
+ <el-tree-select
+ v-model="queryParams.categoryId"
+ :data="categoryTreeList"
+ :props="defaultProps"
+ check-strictly
+ class="!w-240px"
+ node-key="id"
+ placeholder="璇烽�夋嫨鍟嗗搧鍒嗙被"
+ />
+ </el-form-item>
+ <el-form-item label="鍒涘缓鏃堕棿" prop="createTime">
+ <el-date-picker
+ v-model="queryParams.createTime"
+ :default-time="[new Date('1 00:00:00'), new Date('1 23:59:59')]"
+ class="!w-240px"
+ end-placeholder="缁撴潫鏃ユ湡"
+ start-placeholder="寮�濮嬫棩鏈�"
+ type="daterange"
+ value-format="YYYY-MM-DD HH:mm:ss"
+ />
+ </el-form-item>
+ <el-form-item>
+ <el-button @click="handleQuery">
+ <Icon class="mr-5px" icon="ep:search" />
+ 鎼滅储
+ </el-button>
+ <el-button @click="resetQuery">
+ <Icon class="mr-5px" icon="ep:refresh" />
+ 閲嶇疆
+ </el-button>
+ </el-form-item>
+ </el-form>
+ <el-table v-loading="loading" :data="list" show-overflow-tooltip>
+ <!-- 1. 澶氶�夋ā寮忥紙涓嶈兘浣跨敤type="selection"锛孍lement浼氬拷鐣eader鎻掓Ы锛� -->
+ <el-table-column width="55" v-if="multiple">
+ <template #header>
+ <el-checkbox
+ v-model="isCheckAll"
+ :indeterminate="isIndeterminate"
+ @change="handleCheckAll"
+ />
+ </template>
+ <template #default="{ row }">
+ <el-checkbox
+ v-model="checkedStatus[row.id]"
+ @change="(checked: boolean) => handleCheckOne(checked, row, true)"
+ />
+ </template>
+ </el-table-column>
+ <!-- 2. 鍗曢�夋ā寮� -->
+ <el-table-column label="#" width="55" v-else>
+ <template #default="{ row }">
+ <el-radio :value="row.id" v-model="selectedSpuId" @change="handleSingleSelected(row)">
+ <!-- 绌烘牸涓嶈兘鐪佺暐锛屾槸涓轰簡璁╁崟閫夋涓嶆樉绀簂abel锛屽鏋滀笉鎸囧畾label涓嶄細鏈夐�変腑鐨勬晥鏋� -->
+
+ </el-radio>
+ </template>
+ </el-table-column>
+ <el-table-column key="id" align="center" label="鍟嗗搧缂栧彿" prop="id" min-width="60" />
+ <el-table-column label="鍟嗗搧鍥�" min-width="80">
+ <template #default="{ row }">
+ <el-image
+ :src="row.picUrl"
+ class="h-30px w-30px"
+ :preview-src-list="[row.picUrl]"
+ preview-teleported
+ />
+ </template>
+ </el-table-column>
+ <el-table-column label="鍟嗗搧鍚嶇О" min-width="200" prop="name" />
+ <el-table-column label="鍟嗗搧鍒嗙被" min-width="100" prop="categoryId">
+ <template #default="{ row }">
+ <span>{{ categoryList?.find((c) => c.id === row.categoryId)?.name }}</span>
+ </template>
+ </el-table-column>
+ </el-table>
+ <!-- 鍒嗛〉 -->
+ <Pagination
+ v-model:limit="queryParams.pageSize"
+ v-model:page="queryParams.pageNo"
+ :total="total"
+ @pagination="getList"
+ />
+ </ContentWrap>
+ <template #footer v-if="multiple">
+ <el-button type="primary" @click="handleEmitChange">纭� 瀹�</el-button>
+ <el-button @click="dialogVisible = false">鍙� 娑�</el-button>
+ </template>
+ </Dialog>
+</template>
+
+<script lang="ts" setup>
+import { defaultProps, handleTree } from '@/utils/tree'
+
+import * as ProductCategoryApi from '@/api/mall/product/category'
+import * as ProductSpuApi from '@/api/mall/product/spu'
+import { propTypes } from '@/utils/propTypes'
+import { CHANGE_EVENT } from 'element-plus'
+
+type Spu = Required<ProductSpuApi.Spu>
+
+/**
+ * 鍟嗗搧琛ㄦ牸閫夋嫨瀵硅瘽妗�
+ * 1. 鍗曢�夋ā寮忥細
+ * 1.1 鐐瑰嚮琛ㄦ牸宸︿晶鐨勫崟閫夋鏃讹紝缁撴潫閫夋嫨锛屽苟鍏抽棴瀵硅瘽妗�
+ * 1.2 鍐嶆鎵撳紑鏃讹紝淇濇寔閫変腑鐘舵��
+ * 2. 澶氶�夋ā寮忥細
+ * 2.1 鐐瑰嚮琛ㄦ牸宸︿晶鐨勫閫夋鏃讹紝璁板綍閫変腑鐨勫晢鍝�
+ * 2.2 鍒囨崲鍒嗛〉鏃讹紝淇濇寔鍟嗗搧鐨勯�変腑鐨勭姸鎬�
+ * 2.3 鐐瑰嚮鍙充笅瑙掔殑纭畾鎸夐挳鏃讹紝缁撴潫閫夋嫨锛屽叧闂璇濇
+ * 2.4 鍐嶆鎵撳紑鏃讹紝淇濇寔閫変腑鐘舵��
+ */
+defineOptions({ name: 'SpuTableSelect' })
+
+defineProps({
+ // 澶氶�夋ā寮�
+ multiple: propTypes.bool.def(false)
+})
+
+// 鍒楄〃鐨勬�婚〉鏁�
+const total = ref(0)
+// 鍒楄〃鐨勬暟鎹�
+const list = ref<Spu[]>([])
+// 鍒楄〃鐨勫姞杞戒腑
+const loading = ref(false)
+// 寮圭獥鐨勬槸鍚﹀睍绀�
+const dialogVisible = ref(false)
+// 鏌ヨ鍙傛暟
+const queryParams = ref({
+ pageNo: 1,
+ pageSize: 10,
+ // 榛樿鑾峰彇涓婃灦鐨勫晢鍝�
+ tabType: 0,
+ name: '',
+ categoryId: null,
+ createTime: []
+})
+
+/** 鎵撳紑寮圭獥 */
+const open = (spuList?: Spu[]) => {
+ // 閲嶇疆
+ checkedSpus.value = []
+ checkedStatus.value = {}
+ isCheckAll.value = false
+ isIndeterminate.value = false
+
+ // 澶勭悊宸查�変腑
+ if (spuList && spuList.length > 0) {
+ checkedSpus.value = [...spuList]
+ checkedStatus.value = Object.fromEntries(spuList.map((spu) => [spu.id, true]))
+ }
+
+ dialogVisible.value = true
+ resetQuery()
+}
+// 鎻愪緵 open 鏂规硶锛岀敤浜庢墦寮�寮圭獥
+defineExpose({ open })
+
+/** 鏌ヨ鍒楄〃 */
+const getList = async () => {
+ loading.value = true
+ try {
+ const data = await ProductSpuApi.getSpuPage(queryParams.value)
+ list.value = data.list
+ total.value = data.total
+ // checkbox缁戝畾undefined浼氭湁闂锛岄渶瑕佺粰涓�涓猙ool鍊�
+ list.value.forEach(
+ (spu) => (checkedStatus.value[spu.id] = checkedStatus.value[spu.id] || false)
+ )
+ // 璁$畻鍏ㄩ�夋鐘舵��
+ calculateIsCheckAll()
+ } finally {
+ loading.value = false
+ }
+}
+
+/** 鎼滅储鎸夐挳鎿嶄綔 */
+const handleQuery = () => {
+ queryParams.value.pageNo = 1
+ getList()
+}
+
+/** 閲嶇疆鎸夐挳鎿嶄綔 */
+const resetQuery = () => {
+ queryParams.value = {
+ pageNo: 1,
+ pageSize: 10,
+ // 榛樿鑾峰彇涓婃灦鐨勫晢鍝�
+ tabType: 0,
+ name: '',
+ categoryId: null,
+ createTime: []
+ }
+ getList()
+}
+
+// 鏄惁鍏ㄩ��
+const isCheckAll = ref(false)
+// 鍏ㄩ�夋鏄惁澶勪簬涓棿鐘舵�侊細涓嶆槸鍏ㄩ儴閫変腑 && 浠绘剰涓�涓�変腑
+const isIndeterminate = ref(false)
+// 閫変腑鐨勫晢鍝�
+const checkedSpus = ref<Spu[]>([])
+// 閫変腑鐘舵�侊細key涓哄晢鍝両D锛寁alue涓烘槸鍚﹂�変腑
+const checkedStatus = ref<Record<string, boolean>>({})
+
+// 閫変腑鐨勫晢鍝� spuId
+const selectedSpuId = ref()
+/** 鍗曢�変腑鏃惰Е鍙� */
+const handleSingleSelected = (spu: Spu) => {
+ emits(CHANGE_EVENT, spu)
+ // 鍏抽棴寮圭獥
+ dialogVisible.value = false
+ // 璁颁綇涓婃閫夋嫨鐨処D
+ selectedSpuId.value = spu.id
+}
+
+/** 澶氶�夊畬鎴� */
+const handleEmitChange = () => {
+ // 鍏抽棴寮圭獥
+ dialogVisible.value = false
+ emits(CHANGE_EVENT, [...checkedSpus.value])
+}
+
+/** 纭閫夋嫨鏃剁殑瑙﹀彂浜嬩欢 */
+const emits = defineEmits<{
+ change: [spu: Spu | Spu[] | any]
+}>()
+
+/** 鍏ㄩ��/鍏ㄤ笉閫� */
+const handleCheckAll = (checked: boolean) => {
+ isCheckAll.value = checked
+ isIndeterminate.value = false
+
+ list.value.forEach((spu) => handleCheckOne(checked, spu, false))
+}
+
+/**
+ * 閫変腑涓�琛�
+ * @param checked 鏄惁閫変腑
+ * @param spu 鍟嗗搧
+ * @param isCalcCheckAll 鏄惁璁$畻鍏ㄩ��
+ */
+const handleCheckOne = (checked: boolean, spu: Spu, isCalcCheckAll: boolean) => {
+ if (checked) {
+ checkedSpus.value.push(spu)
+ checkedStatus.value[spu.id] = true
+ } else {
+ const index = findCheckedIndex(spu)
+ if (index > -1) {
+ checkedSpus.value.splice(index, 1)
+ checkedStatus.value[spu.id] = false
+ isCheckAll.value = false
+ }
+ }
+
+ // 璁$畻鍏ㄩ�夋鐘舵��
+ if (isCalcCheckAll) {
+ calculateIsCheckAll()
+ }
+}
+
+// 鏌ユ壘鍟嗗搧鍦ㄥ凡閫変腑鍟嗗搧鍒楄〃涓殑绱㈠紩
+const findCheckedIndex = (spu: Spu) => checkedSpus.value.findIndex((item) => item.id === spu.id)
+
+// 璁$畻鍏ㄩ�夋鐘舵��
+const calculateIsCheckAll = () => {
+ isCheckAll.value = list.value.every((spu) => checkedStatus.value[spu.id])
+ // 璁$畻涓棿鐘舵�侊細涓嶆槸鍏ㄩ儴閫変腑 && 浠绘剰涓�涓�変腑
+ isIndeterminate.value = !isCheckAll.value && list.value.some((spu) => checkedStatus.value[spu.id])
+}
+
+// 鍒嗙被鍒楄〃
+const categoryList = ref()
+// 鍒嗙被鏍�
+const categoryTreeList = ref()
+/** 鍒濆鍖� **/
+onMounted(async () => {
+ await getList()
+ // 鑾峰緱鍒嗙被鏍�
+ categoryList.value = await ProductCategoryApi.getCategoryList({})
+ categoryTreeList.value = handleTree(categoryList.value, 'id', 'parentId')
+})
+</script>
--
Gitblit v1.8.0