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/promotion/combination/components/CombinationTableSelect.vue |  345 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 345 insertions(+), 0 deletions(-)

diff --git a/src/views/mall/promotion/combination/components/CombinationTableSelect.vue b/src/views/mall/promotion/combination/components/CombinationTableSelect.vue
new file mode 100644
index 0000000..3639521
--- /dev/null
+++ b/src/views/mall/promotion/combination/components/CombinationTableSelect.vue
@@ -0,0 +1,345 @@
+<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"
+            placeholder="璇疯緭鍏ユ椿鍔ㄥ悕绉�"
+            clearable
+            @keyup.enter="handleQuery"
+            class="!w-240px"
+          />
+        </el-form-item>
+        <el-form-item label="娲诲姩鐘舵��" prop="status">
+          <el-select
+            v-model="queryParams.status"
+            placeholder="璇烽�夋嫨娲诲姩鐘舵��"
+            clearable
+            class="!w-240px"
+          >
+            <el-option
+              v-for="dict in getIntDictOptions(DICT_TYPE.COMMON_STATUS)"
+              :key="dict.value"
+              :label="dict.label"
+              :value="dict.value"
+            />
+          </el-select>
+        </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="selectedActivityId"
+              @change="handleSingleSelected(row)"
+            >
+              <!-- 绌烘牸涓嶈兘鐪佺暐锛屾槸涓轰簡璁╁崟閫夋涓嶆樉绀簂abel锛屽鏋滀笉鎸囧畾label涓嶄細鏈夐�変腑鐨勬晥鏋� -->
+              &nbsp;
+            </el-radio>
+          </template>
+        </el-table-column>
+        <el-table-column label="娲诲姩缂栧彿" prop="id" min-width="80" />
+        <el-table-column label="娲诲姩鍚嶇О" prop="name" min-width="140" />
+        <el-table-column label="娲诲姩鏃堕棿" min-width="210">
+          <template #default="scope">
+            {{ formatDate(scope.row.startTime, 'YYYY-MM-DD') }}
+            ~ {{ formatDate(scope.row.endTime, 'YYYY-MM-DD') }}
+          </template>
+        </el-table-column>
+        <el-table-column label="鍟嗗搧鍥剧墖" prop="spuName" min-width="80">
+          <template #default="scope">
+            <el-image
+              :src="scope.row.picUrl"
+              class="h-40px w-40px"
+              :preview-src-list="[scope.row.picUrl]"
+              preview-teleported
+            />
+          </template>
+        </el-table-column>
+        <el-table-column label="鍟嗗搧鏍囬" prop="spuName" min-width="300" />
+        <el-table-column
+          label="鍘熶环"
+          prop="marketPrice"
+          min-width="100"
+          :formatter="fenToYuanFormat"
+        />
+        <el-table-column label="鎷煎洟浠�" prop="seckillPrice" min-width="100">
+          <template #default="scope">
+            {{ formatCombinationPrice(scope.row.products) }}
+          </template>
+        </el-table-column>
+        <el-table-column label="寮�鍥㈢粍鏁�" prop="groupCount" min-width="100" />
+        <el-table-column label="鎴愬洟缁勬暟" prop="groupSuccessCount" min-width="100" />
+        <el-table-column label="璐拱娆℃暟" prop="recordCount" min-width="100" />
+        <el-table-column label="娲诲姩鐘舵��" align="center" prop="status" min-width="100">
+          <template #default="scope">
+            <dict-tag :type="DICT_TYPE.COMMON_STATUS" :value="scope.row.status" />
+          </template>
+        </el-table-column>
+        <el-table-column
+          label="鍒涘缓鏃堕棿"
+          align="center"
+          prop="createTime"
+          :formatter="dateFormatter"
+          width="180px"
+        />
+      </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 { handleTree } from '@/utils/tree'
+
+import * as ProductCategoryApi from '@/api/mall/product/category'
+import { propTypes } from '@/utils/propTypes'
+import { CHANGE_EVENT } from 'element-plus'
+import * as CombinationActivityApi from '@/api/mall/promotion/combination/combinationActivity'
+import { fenToYuanFormat } from '@/utils/formatter'
+import { DICT_TYPE, getIntDictOptions } from '@/utils/dict'
+import { dateFormatter, formatDate } from '@/utils/formatTime'
+import { fenToYuan } from '@/utils'
+
+type CombinationActivityVO = Required<CombinationActivityApi.CombinationActivityVO>
+
+/**
+ * 娲诲姩琛ㄦ牸閫夋嫨瀵硅瘽妗�
+ * 1. 鍗曢�夋ā寮忥細
+ *    1.1 鐐瑰嚮琛ㄦ牸宸︿晶鐨勫崟閫夋鏃讹紝缁撴潫閫夋嫨锛屽苟鍏抽棴瀵硅瘽妗�
+ *    1.2 鍐嶆鎵撳紑鏃讹紝淇濇寔閫変腑鐘舵��
+ * 2. 澶氶�夋ā寮忥細
+ *    2.1 鐐瑰嚮琛ㄦ牸宸︿晶鐨勫閫夋鏃讹紝璁板綍閫変腑鐨勬椿鍔�
+ *    2.2 鍒囨崲鍒嗛〉鏃讹紝淇濇寔娲诲姩鐨勯�変腑鐘舵��
+ *    2.3 鐐瑰嚮鍙充笅瑙掔殑纭畾鎸夐挳鏃讹紝缁撴潫閫夋嫨锛屽叧闂璇濇
+ *    2.4 鍐嶆鎵撳紑鏃讹紝淇濇寔閫変腑鐘舵��
+ */
+defineOptions({ name: 'CombinationTableSelect' })
+
+defineProps({
+  // 澶氶�夋ā寮�
+  multiple: propTypes.bool.def(false)
+})
+
+// 鍒楄〃鐨勬�婚〉鏁�
+const total = ref(0)
+// 鍒楄〃鐨勬暟鎹�
+const list = ref<CombinationActivityVO[]>([])
+// 鍒楄〃鐨勫姞杞戒腑
+const loading = ref(false)
+// 寮圭獥鐨勬槸鍚﹀睍绀�
+const dialogVisible = ref(false)
+// 鏌ヨ鍙傛暟
+const queryParams = ref({
+  pageNo: 1,
+  pageSize: 10,
+  name: null,
+  status: undefined
+})
+
+/** 鎵撳紑寮圭獥 */
+const open = (CombinationList?: CombinationActivityVO[]) => {
+  // 閲嶇疆
+  checkedActivitys.value = []
+  checkedStatus.value = {}
+  isCheckAll.value = false
+  isIndeterminate.value = false
+
+  // 澶勭悊宸查�変腑
+  if (CombinationList && CombinationList.length > 0) {
+    checkedActivitys.value = [...CombinationList]
+    checkedStatus.value = Object.fromEntries(
+      CombinationList.map((activityVO) => [activityVO.id, true])
+    )
+  }
+
+  dialogVisible.value = true
+  resetQuery()
+}
+// 鎻愪緵 open 鏂规硶锛岀敤浜庢墦寮�寮圭獥
+defineExpose({ open })
+
+/** 鏌ヨ鍒楄〃 */
+const getList = async () => {
+  loading.value = true
+  try {
+    const data = await CombinationActivityApi.getCombinationActivityPage(queryParams.value)
+    list.value = data.list
+    total.value = data.total
+    // checkbox缁戝畾undefined浼氭湁闂锛岄渶瑕佺粰涓�涓猙ool鍊�
+    list.value.forEach(
+      (activityVO) =>
+        (checkedStatus.value[activityVO.id] = checkedStatus.value[activityVO.id] || false)
+    )
+    // 璁$畻鍏ㄩ�夋鐘舵��
+    calculateIsCheckAll()
+  } finally {
+    loading.value = false
+  }
+}
+
+/** 鎼滅储鎸夐挳鎿嶄綔 */
+const handleQuery = () => {
+  queryParams.value.pageNo = 1
+  getList()
+}
+
+/** 閲嶇疆鎸夐挳鎿嶄綔 */
+const resetQuery = () => {
+  queryParams.value = {
+    pageNo: 1,
+    pageSize: 10,
+    name: '',
+    createTime: []
+  }
+  getList()
+}
+
+/**
+ * 鏍煎紡鍖栨嫾鍥环鏍�
+ * @param products
+ */
+const formatCombinationPrice = (products) => {
+  const combinationPrice = Math.min(...products.map((item) => item.combinationPrice))
+  return `锟�${fenToYuan(combinationPrice)}`
+}
+
+// 鏄惁鍏ㄩ��
+const isCheckAll = ref(false)
+// 鍏ㄩ�夋鏄惁澶勪簬涓棿鐘舵�侊細涓嶆槸鍏ㄩ儴閫変腑 && 浠绘剰涓�涓�変腑
+const isIndeterminate = ref(false)
+// 閫変腑鐨勬椿鍔�
+const checkedActivitys = ref<CombinationActivityVO[]>([])
+// 閫変腑鐘舵�侊細key涓烘椿鍔↖D锛寁alue涓烘槸鍚﹂�変腑
+const checkedStatus = ref<Record<string, boolean>>({})
+
+// 閫変腑鐨勬椿鍔� activityId
+const selectedActivityId = ref()
+/** 鍗曢�変腑鏃惰Е鍙� */
+const handleSingleSelected = (combinationActivityVO: CombinationActivityVO) => {
+  emits(CHANGE_EVENT, combinationActivityVO)
+  // 鍏抽棴寮圭獥
+  dialogVisible.value = false
+  // 璁颁綇涓婃閫夋嫨鐨処D
+  selectedActivityId.value = combinationActivityVO.id
+}
+
+/** 澶氶�夊畬鎴� */
+const handleEmitChange = () => {
+  // 鍏抽棴寮圭獥
+  dialogVisible.value = false
+  emits(CHANGE_EVENT, [...checkedActivitys.value])
+}
+
+/** 纭閫夋嫨鏃剁殑瑙﹀彂浜嬩欢 */
+const emits = defineEmits<{
+  change: [CombinationActivityApi: CombinationActivityVO | CombinationActivityVO[] | any]
+}>()
+
+/** 鍏ㄩ��/鍏ㄤ笉閫� */
+const handleCheckAll = (checked: boolean) => {
+  isCheckAll.value = checked
+  isIndeterminate.value = false
+
+  list.value.forEach((combinationActivity) => handleCheckOne(checked, combinationActivity, false))
+}
+
+/**
+ * 閫変腑涓�琛�
+ * @param checked 鏄惁閫変腑
+ * @param combinationActivity 娲诲姩
+ * @param isCalcCheckAll 鏄惁璁$畻鍏ㄩ��
+ */
+const handleCheckOne = (
+  checked: boolean,
+  combinationActivity: CombinationActivityVO,
+  isCalcCheckAll: boolean
+) => {
+  if (checked) {
+    checkedActivitys.value.push(combinationActivity)
+    checkedStatus.value[combinationActivity.id] = true
+  } else {
+    const index = findCheckedIndex(combinationActivity)
+    if (index > -1) {
+      checkedActivitys.value.splice(index, 1)
+      checkedStatus.value[combinationActivity.id] = false
+      isCheckAll.value = false
+    }
+  }
+
+  // 璁$畻鍏ㄩ�夋鐘舵��
+  if (isCalcCheckAll) {
+    calculateIsCheckAll()
+  }
+}
+
+// 鏌ユ壘娲诲姩鍦ㄥ凡閫変腑娲诲姩鍒楄〃涓殑绱㈠紩
+const findCheckedIndex = (activityVO: CombinationActivityVO) =>
+  checkedActivitys.value.findIndex((item) => item.id === activityVO.id)
+
+// 璁$畻鍏ㄩ�夋鐘舵��
+const calculateIsCheckAll = () => {
+  isCheckAll.value = list.value.every((activityVO) => checkedStatus.value[activityVO.id])
+  // 璁$畻涓棿鐘舵�侊細涓嶆槸鍏ㄩ儴閫変腑 && 浠绘剰涓�涓�変腑
+  isIndeterminate.value =
+    !isCheckAll.value && list.value.some((activityVO) => checkedStatus.value[activityVO.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