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/point/components/PointTableSelect.vue |  300 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 300 insertions(+), 0 deletions(-)

diff --git a/src/views/mall/promotion/point/components/PointTableSelect.vue b/src/views/mall/promotion/point/components/PointTableSelect.vue
new file mode 100644
index 0000000..d68b5f1
--- /dev/null
+++ b/src/views/mall/promotion/point/components/PointTableSelect.vue
@@ -0,0 +1,300 @@
+<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="status">
+          <el-select
+            v-model="queryParams.status"
+            class="!w-240px"
+            clearable
+            placeholder="璇烽�夋嫨娲诲姩鐘舵��"
+          >
+            <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 v-if="multiple" width="55">
+          <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 v-else label="#" width="55">
+          <template #default="{ row }">
+            <el-radio
+              v-model="selectedActivityId"
+              :value="row.id"
+              @change="handleSingleSelected(row)"
+            >
+              <!-- 绌烘牸涓嶈兘鐪佺暐锛屾槸涓轰簡璁╁崟閫夋涓嶆樉绀簂abel锛屽鏋滀笉鎸囧畾label涓嶄細鏈夐�変腑鐨勬晥鏋� -->
+              &nbsp;
+            </el-radio>
+          </template>
+        </el-table-column>
+        <el-table-column label="娲诲姩缂栧彿" min-width="80" prop="id" />
+        <el-table-column label="鍟嗗搧鍥剧墖" min-width="80" prop="spuName">
+          <template #default="scope">
+            <el-image
+              :preview-src-list="[scope.row.picUrl]"
+              :src="scope.row.picUrl"
+              class="h-40px w-40px"
+              preview-teleported
+            />
+          </template>
+        </el-table-column>
+        <el-table-column label="鍟嗗搧鏍囬" min-width="300" prop="spuName" />
+        <el-table-column
+          :formatter="fenToYuanFormat"
+          label="鍘熶环"
+          min-width="100"
+          prop="marketPrice"
+        />
+        <el-table-column label="鍘熶环" min-width="100" prop="marketPrice" />
+        <el-table-column align="center" label="娲诲姩鐘舵��" min-width="100" prop="status">
+          <template #default="scope">
+            <dict-tag :type="DICT_TYPE.COMMON_STATUS" :value="scope.row.status" />
+          </template>
+        </el-table-column>
+        <el-table-column align="center" label="搴撳瓨" min-width="80" prop="stock" />
+        <el-table-column align="center" label="鎬诲簱瀛�" min-width="80" prop="totalStock" />
+        <el-table-column align="center" label="宸插厬鎹㈡暟閲�" min-width="100" prop="redeemedQuantity">
+          <template #default="{ row }">
+            {{ getRedeemedQuantity(row) }}
+          </template>
+        </el-table-column>
+        <el-table-column
+          :formatter="dateFormatter"
+          align="center"
+          label="鍒涘缓鏃堕棿"
+          prop="createTime"
+          width="180px"
+        />
+      </el-table>
+      <!-- 鍒嗛〉 -->
+      <Pagination
+        v-model:limit="queryParams.pageSize"
+        v-model:page="queryParams.pageNo"
+        :total="total"
+        @pagination="getList"
+      />
+    </ContentWrap>
+    <template v-if="multiple" #footer>
+      <el-button type="primary" @click="handleEmitChange">纭� 瀹�</el-button>
+      <el-button @click="dialogVisible = false">鍙� 娑�</el-button>
+    </template>
+  </Dialog>
+</template>
+
+<script lang="ts" setup>
+import { propTypes } from '@/utils/propTypes'
+import { CHANGE_EVENT } from 'element-plus'
+import { PointActivityApi, PointActivityVO } from '@/api/mall/promotion/point'
+import { fenToYuanFormat } from '@/utils/formatter'
+import { DICT_TYPE, getIntDictOptions } from '@/utils/dict'
+import { dateFormatter } from '@/utils/formatTime'
+
+/**
+ * 娲诲姩琛ㄦ牸閫夋嫨瀵硅瘽妗�
+ * 1. 鍗曢�夋ā寮忥細
+ *    1.1 鐐瑰嚮琛ㄦ牸宸︿晶鐨勫崟閫夋鏃讹紝缁撴潫閫夋嫨锛屽苟鍏抽棴瀵硅瘽妗�
+ *    1.2 鍐嶆鎵撳紑鏃讹紝淇濇寔閫変腑鐘舵��
+ * 2. 澶氶�夋ā寮忥細
+ *    2.1 鐐瑰嚮琛ㄦ牸宸︿晶鐨勫閫夋鏃讹紝璁板綍閫変腑鐨勬椿鍔�
+ *    2.2 鍒囨崲鍒嗛〉鏃讹紝淇濇寔娲诲姩鐨勯�変腑鐘舵��
+ *    2.3 鐐瑰嚮鍙充笅瑙掔殑纭畾鎸夐挳鏃讹紝缁撴潫閫夋嫨锛屽叧闂璇濇
+ *    2.4 鍐嶆鎵撳紑鏃讹紝淇濇寔閫変腑鐘舵��
+ */
+defineOptions({ name: 'PointTableSelect' })
+
+defineProps({
+  // 澶氶�夋ā寮�
+  multiple: propTypes.bool.def(false)
+})
+
+// 鍒楄〃鐨勬�婚〉鏁�
+const total = ref(0)
+// 鍒楄〃鐨勬暟鎹�
+const list = ref<PointActivityVO[]>([])
+// 鍒楄〃鐨勫姞杞戒腑
+const loading = ref(false)
+// 寮圭獥鐨勬槸鍚﹀睍绀�
+const dialogVisible = ref(false)
+// 鏌ヨ鍙傛暟
+const queryParams = ref({
+  pageNo: 1,
+  pageSize: 10,
+  name: null,
+  status: undefined
+})
+const getRedeemedQuantity = computed(() => (row: any) => (row.totalStock || 0) - (row.stock || 0)) // 鑾峰緱鍟嗗搧宸插厬鎹㈡暟閲�
+/** 鎵撳紑寮圭獥 */
+const open = (pointList?: PointActivityVO[]) => {
+  // 閲嶇疆
+  checkedActivities.value = []
+  checkedStatus.value = {}
+  isCheckAll.value = false
+  isIndeterminate.value = false
+
+  // 澶勭悊宸查�変腑
+  if (pointList && pointList.length > 0) {
+    checkedActivities.value = [...pointList]
+    checkedStatus.value = Object.fromEntries(pointList.map((activityVO) => [activityVO.id, true]))
+  }
+
+  dialogVisible.value = true
+  resetQuery()
+}
+// 鎻愪緵 open 鏂规硶锛岀敤浜庢墦寮�寮圭獥
+defineExpose({ open })
+
+/** 鏌ヨ鍒楄〃 */
+const getList = async () => {
+  loading.value = true
+  try {
+    const data = await PointActivityApi.getPointActivityPage(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: null,
+    status: undefined
+  }
+  getList()
+}
+
+// 鏄惁鍏ㄩ��
+const isCheckAll = ref(false)
+// 鍏ㄩ�夋鏄惁澶勪簬涓棿鐘舵�侊細涓嶆槸鍏ㄩ儴閫変腑 && 浠绘剰涓�涓�変腑
+const isIndeterminate = ref(false)
+// 閫変腑鐨勬椿鍔�
+const checkedActivities = ref<PointActivityVO[]>([])
+// 閫変腑鐘舵�侊細key涓烘椿鍔↖D锛寁alue涓烘槸鍚﹂�変腑
+const checkedStatus = ref<Record<string, boolean>>({})
+
+// 閫変腑鐨勬椿鍔� activityId
+const selectedActivityId = ref()
+/** 鍗曢�変腑鏃惰Е鍙� */
+const handleSingleSelected = (pointActivityVO: PointActivityVO) => {
+  emits(CHANGE_EVENT, pointActivityVO)
+  // 鍏抽棴寮圭獥
+  dialogVisible.value = false
+  // 璁颁綇涓婃閫夋嫨鐨処D
+  selectedActivityId.value = pointActivityVO.id
+}
+
+/** 澶氶�夊畬鎴� */
+const handleEmitChange = () => {
+  // 鍏抽棴寮圭獥
+  dialogVisible.value = false
+  emits(CHANGE_EVENT, [...checkedActivities.value])
+}
+
+/** 纭閫夋嫨鏃剁殑瑙﹀彂浜嬩欢 */
+const emits = defineEmits<{
+  (e: CHANGE_EVENT, v: PointActivityVO | PointActivityVO[] | any): void
+}>()
+
+/** 鍏ㄩ��/鍏ㄤ笉閫� */
+const handleCheckAll = (checked: boolean) => {
+  isCheckAll.value = checked
+  isIndeterminate.value = false
+
+  list.value.forEach((pointActivity) => handleCheckOne(checked, pointActivity, false))
+}
+
+/**
+ * 閫変腑涓�琛�
+ * @param checked 鏄惁閫変腑
+ * @param pointActivity 娲诲姩
+ * @param isCalcCheckAll 鏄惁璁$畻鍏ㄩ��
+ */
+const handleCheckOne = (
+  checked: boolean,
+  pointActivity: PointActivityVO,
+  isCalcCheckAll: boolean
+) => {
+  if (checked) {
+    checkedActivities.value.push(pointActivity)
+    checkedStatus.value[pointActivity.id] = true
+  } else {
+    const index = findCheckedIndex(pointActivity)
+    if (index > -1) {
+      checkedActivities.value.splice(index, 1)
+      checkedStatus.value[pointActivity.id] = false
+      isCheckAll.value = false
+    }
+  }
+
+  // 璁$畻鍏ㄩ�夋鐘舵��
+  if (isCalcCheckAll) {
+    calculateIsCheckAll()
+  }
+}
+
+// 鏌ユ壘娲诲姩鍦ㄥ凡閫変腑娲诲姩鍒楄〃涓殑绱㈠紩
+const findCheckedIndex = (activityVO: PointActivityVO) =>
+  checkedActivities.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])
+}
+</script>

--
Gitblit v1.8.0