ソースを参照

Merge branch 'xinyan' into dev

xinyan 6 ヶ月 前
コミット
3cf98d1682

+ 9 - 7
src/components/ImportButton/index.vue

@@ -30,6 +30,7 @@ function hasPermission(permissions: string | string[]): boolean {
 
 const upload = ref<UploadInstance>();
 const upBtnLoading = ref(false);
+const emits = defineEmits(['handel-error']);
 
 /**
  * @description 替换文件并上传
@@ -57,9 +58,7 @@ async function handleCustomUpload(uploadRequest: any) {
 		const fileUrl = resp.data.url;
 		const response = await props.uploadFunction({ url: fileUrl });
 		handleResponse(response);
-		// processResponseData(response.data);
-		uploadRequest.onSuccess(response); // 通知 el-upload 上传成功
-
+		uploadRequest.onSuccess(response);
 	} catch (error) {
 		console.log('==Error==', error);
 		uploadRequest.onError(error);
@@ -73,15 +72,18 @@ async function handleCustomUpload(uploadRequest: any) {
  * @param response 后端返回的响应
  */
 function handleResponse(response: any) {
+	if (response.data.length !== 0){
+		emits('handel-error', response.data);
+		return;
+	}
 	if (response.code === 2000) {
 		ElMessage.success({ message: response.msg, plain: true });
-
-		// 上传成功后调用刷新父组件的方法
 		if (refreshView) {
 			refreshView();
 		}
-	} else {
-		ElMessage.error({ message: response.msg, plain: true });
+	}
+	 else {
+		ElMessage.error({ message: '上传失败', plain: true });
 	}
 }
 </script>

+ 174 - 197
src/views/product-manage/comment-detail/component/DataTable.vue

@@ -5,7 +5,7 @@
  * @Author: Cheney
  */
 
-import { Download, InfoFilled, Plus, Refresh, RefreshRight, Search } from '@element-plus/icons-vue';
+import { Download, Plus, Refresh } from '@element-plus/icons-vue';
 import { ElMessage } from 'element-plus';
 import { usePagination } from '/@/utils/usePagination';
 import { useTableData } from '/@/utils/useTableData';
@@ -19,66 +19,65 @@ import { DictionaryStore } from '/@/stores/dictionary';
 import { useScoreEnum, useTivEnum } from '/@/views/product-manage/comment-detail/enum';
 import NegativeLabel from '/@/views/product-manage/comment-detail/component/NegativeLabel.vue';
 
-
 const { data: staticData } = DictionaryStore();
 
 const btnLoading = ref(false);
 
 const formInline = reactive<any>({
-  country: '',
-  score: '',
-  tiv: ''
+	country: '',
+	score: '',
+	tiv: '',
 });
 
 const props = defineProps({
-  asin: String
+	asin: String,
 });
 const { asin } = props;
 const { tableOptions, handlePageChange } = usePagination(fetchList);
 
 const gridRef = ref();
 const gridOptions: any = reactive({
-  // id: 'competitor-monitor-comment',
-  // keepSource: true,
-  size: 'mini',
-  border: false,
-  round: true,
-  stripe: true,
-  showHeader: true,
-  currentRowHighLight: true,
-  height: 650,
-  // customConfig: {
-  // 	storage: {
-  // 		visible: true,
-  // 		resizable:false,
-  // 	}
-  // },
-  toolbarConfig: {
-    size: 'large',
-    // custom: true,
-    slots: {
-      buttons: 'toolbar_buttons',
-      tools: 'toolbar_tools'
-    }
-  },
-  rowConfig: {
-    isHover: true
-  },
-  columnConfig: {
-    // resizable: true
-  },
-  pagerConfig: {
-    total: tableOptions.value.total,
-    page: tableOptions.value.page,
-    limit: tableOptions.value.limit
-  },
-  loading: false,
-  loadingConfig: {
-    icon: 'vxe-icon-indicator roll',
-    text: '正在拼命加载中...'
-  },
-  columns: '',
-  data: ''
+	// id: 'competitor-monitor-comment',
+	// keepSource: true,
+	size: 'mini',
+	border: false,
+	round: true,
+	stripe: true,
+	showHeader: true,
+	currentRowHighLight: true,
+	height: 650,
+	// customConfig: {
+	// 	storage: {
+	// 		visible: true,
+	// 		resizable:false,
+	// 	}
+	// },
+	toolbarConfig: {
+		size: 'large',
+		// custom: true,
+		slots: {
+			buttons: 'toolbar_buttons',
+			tools: 'toolbar_tools',
+		},
+	},
+	rowConfig: {
+		isHover: true,
+	},
+	columnConfig: {
+		// resizable: true
+	},
+	pagerConfig: {
+		total: tableOptions.value.total,
+		page: tableOptions.value.page,
+		limit: tableOptions.value.limit,
+	},
+	loading: false,
+	loadingConfig: {
+		icon: 'vxe-icon-indicator roll',
+		text: '正在拼命加载中...',
+	},
+	columns: '',
+	data: '',
 });
 
 const createOpen = ref(false);
@@ -87,65 +86,65 @@ const rowData = ref<any>({});
 const isShowLabel = ref(false);
 
 onMounted(() => {
-  fetchList();
+	fetchList();
 });
 
 // TODO: 删除goods
 async function fetchList(isQuery = false) {
-  if (isQuery) {
-    gridOptions.pagerConfig.page = 1;
-  }
+	if (isQuery) {
+		gridOptions.pagerConfig.page = 1;
+	}
 
-  gridOptions.data = [];
-  gridOptions.columns = [];
+	gridOptions.data = [];
+	gridOptions.columns = [];
 
-  const query = {
-    asin: asin,
-    country_code: formInline?.country,
-    score: formInline?.score,
-    tiv: formInline?.tiv
-  };
-  await useTableData(api.getTableData, query, gridOptions);
-  await gridRef.value.loadColumn(CompetitorMonitorCommentColumns);
-  // gridOptions.showHeader = Boolean(gridOptions.data?.length);
+	const query = {
+		asin: asin,
+		country_code: formInline?.country,
+		score: formInline?.score,
+		tiv: formInline?.tiv,
+	};
+	await useTableData(api.getTableData, query, gridOptions);
+	await gridRef.value.loadColumn(CompetitorMonitorCommentColumns);
+	// gridOptions.showHeader = Boolean(gridOptions.data?.length);
 }
 
 function handleRefresh() {
-  fetchList();
+	fetchList();
 }
 
 async function handleDownload() {
-  gridOptions.loading = true;
-  try {
-    const query = {
-      asin: asin,
-      country_code: formInline?.country,
-      score: formInline?.score,
-      tiv: formInline?.tiv
-    };
-    const response = await api.exportData(query);
-    const url = window.URL.createObjectURL(new Blob([ response.data ]));
-    const link = document.createElement('a');
-    link.href = url;
-    link.setAttribute('download', '评论详情数据.xlsx');
-    document.body.appendChild(link);
-    link.click();
-    ElMessage.success('数据导出成功!');
-  } catch (error) {
-    ElMessage.error('数据导出失败,请重试!');
-    console.error(error);
-  } finally {
-    gridOptions.loading = false;
-  }
+	gridOptions.loading = true;
+	try {
+		const query = {
+			asin: asin,
+			country_code: formInline?.country,
+			score: formInline?.score,
+			tiv: formInline?.tiv,
+		};
+		const response = await api.exportData(query);
+		const url = window.URL.createObjectURL(new Blob([response.data]));
+		const link = document.createElement('a');
+		link.href = url;
+		link.setAttribute('download', '评论详情数据.xlsx');
+		document.body.appendChild(link);
+		link.click();
+		ElMessage.success('数据导出成功!');
+	} catch (error) {
+		ElMessage.error('数据导出失败,请重试!');
+		console.error(error);
+	} finally {
+		gridOptions.loading = false;
+	}
 }
 
 function handleCreate() {
-  createOpen.value = true;
+	createOpen.value = true;
 }
 
 function showLabel(row: any) {
-  isShowLabel.value = true;
-  rowData.value = row;
+	isShowLabel.value = true;
+	rowData.value = row;
 }
 
 // async function handleQuery() {
@@ -161,124 +160,102 @@ function showLabel(row: any) {
 // }
 
 defineExpose({ fetchList });
-
 </script>
 
 <template>
-  <!--查询条件-->
-  <div ref="queryContainer" class="flex justify-between">
-    <div class="flex flex-1">
-      <div class="w-full whitespace-nowrap">
-        <el-row :gutter="20" style="margin-bottom: 5px;">
-          <el-col :span="6">
-            <div class="flex items-center">
-              <span class="mr-2">国 家</span>
-              <el-select v-model="formInline.country" clearable placeholder="请选择国家" @change="fetchList(true)">
-                <el-option v-for="item in staticData.country_code" :key="item.value" :label="item.label"
-                           :value="item.value" />
-              </el-select>
-            </div>
-          </el-col>
-          <el-col :span="6">
-            <div class="flex items-center">
-              <span class="mr-2">用户评分</span>
-              <el-select v-model="formInline.score" clearable placeholder="请选择用户评分" @change="fetchList(true)">
-                <el-option v-for="item in useScoreEnum" :key="item.value" :label="item.label"
-                           :value="item.value" />
-              </el-select>
-            </div>
-          </el-col>
-          <el-col :span="6">
-            <div class="flex items-center">
-              <span class="mr-2">评论类型</span>
-              <el-select v-model="formInline.tiv" clearable placeholder="请选择评论类型" @change="fetchList(true)">
-                <el-option v-for="item in useTivEnum" :key="item.value" :label="item.label"
-                           :value="item.value" />
-              </el-select>
-            </div>
-          </el-col>
-        </el-row>
-      </div>
-    </div>
-    <!--<div class="flex gap-1.5 ml-5">-->
-    <!--  <el-button :icon="Search" :loading="btnLoading" type="primary" @click="handleQuery">-->
-    <!--    查 询-->
-    <!--  </el-button>-->
-    <!--  <el-button :icon="RefreshRight" color="#ECECF1C9" style="width: 88px; color: #3c3c3c;" @click="resetParameter">-->
-    <!--    重 置-->
-    <!--  </el-button>-->
-    <!--</div>-->
-  </div>
-  <el-divider ref="dividerContainer" style="margin: 20px 0 12px 0;" />
-  <vxe-grid ref="gridRef" class="z-0" v-bind="gridOptions">
-    <template #toolbar_buttons>
-      <div class="flex gap-2">
-        <PermissionButton :icon="Plus" plain round type="primary" @click="handleCreate">
-          新 增
-        </PermissionButton>
-        <VerticalDivider class="px-1" style="margin-left: 7px;" />
-      </div>
-    </template>
-    <template #toolbar_tools>
-      <el-button circle class="toolbar-btn" @click="handleRefresh">
-        <el-icon>
-          <Refresh />
-        </el-icon>
-      </el-button>
-      <el-popconfirm
-          :icon="InfoFilled"
-          icon-color="#626AEF"
-          title="是否确认导出所有数据项?"
-          width="220"
-          @confirm="handleDownload"
-      >
-        <template #reference>
-          <el-button circle class="mr-3 toolbar-btn">
-            <el-icon>
-              <Download />
-            </el-icon>
-          </el-button>
-        </template>
-        <template #actions="{ confirm, cancel }">
-          <el-button size="small" @click="cancel">No!</el-button>
-          <el-button size="small" type="danger" @click="confirm">
-            Yes?
-          </el-button>
-        </template>
-      </el-popconfirm>
-    </template>
-    <template #top>
-      <div class="mb-2"></div>
-    </template>
-    <template #pager>
-      <vxe-pager
-          v-model:currentPage="gridOptions.pagerConfig.page"
-          v-model:pageSize="gridOptions.pagerConfig.limit"
-          :total="gridOptions.pagerConfig.total"
-          class="mt-1.5"
-          @page-change="handlePageChange"
-      />
-    </template>
-    <template #empty>
-      <el-empty description="暂无数据" />
-    </template>
-    <!-- 自定义列插槽 -->
-    <template v-for="col in CompetitorMonitorCommentColumns" #[`${col.field}`]="{ row }">
-      <DataTableSlot :key="row.id" :field="col.field" :row="row" @open-negativeLabel="showLabel" />
-    </template>
-  </vxe-grid>
-  <CreateDialog v-if="createOpen" v-model="createOpen" @refresh="fetchList" />
-  <NegativeLabel v-if="isShowLabel" v-model="isShowLabel" :rowData="rowData" />
+	<!--查询条件-->
+	<div ref="queryContainer" class="flex justify-between">
+		<div class="flex flex-1">
+			<div class="w-full whitespace-nowrap">
+				<el-row :gutter="20" style="margin-bottom: 5px">
+					<el-col :span="6">
+						<div class="flex items-center">
+							<span class="mr-2">国 家</span>
+							<el-select v-model="formInline.country" clearable placeholder="请选择国家" @change="fetchList(true)">
+								<el-option v-for="item in staticData.country_code" :key="item.value" :label="item.label" :value="item.value" />
+							</el-select>
+						</div>
+					</el-col>
+					<el-col :span="6">
+						<div class="flex items-center">
+							<span class="mr-2">用户评分</span>
+							<el-select v-model="formInline.score" clearable placeholder="请选择用户评分" @change="fetchList(true)">
+								<el-option v-for="item in useScoreEnum" :key="item.value" :label="item.label" :value="item.value" />
+							</el-select>
+						</div>
+					</el-col>
+					<el-col :span="6">
+						<div class="flex items-center">
+							<span class="mr-2">评论类型</span>
+							<el-select v-model="formInline.tiv" clearable placeholder="请选择评论类型" @change="fetchList(true)">
+								<el-option v-for="item in useTivEnum" :key="item.value" :label="item.label" :value="item.value" />
+							</el-select>
+						</div>
+					</el-col>
+				</el-row>
+			</div>
+		</div>
+		<!--<div class="flex gap-1.5 ml-5">-->
+		<!--  <el-button :icon="Search" :loading="btnLoading" type="primary" @click="handleQuery">-->
+		<!--    查 询-->
+		<!--  </el-button>-->
+		<!--  <el-button :icon="RefreshRight" color="#ECECF1C9" style="width: 88px; color: #3c3c3c;" @click="resetParameter">-->
+		<!--    重 置-->
+		<!--  </el-button>-->
+		<!--</div>-->
+	</div>
+	<el-divider ref="dividerContainer" style="margin: 20px 0 12px 0" />
+	<vxe-grid ref="gridRef" class="z-0" v-bind="gridOptions">
+		<template #toolbar_buttons>
+			<div class="flex gap-2">
+				<PermissionButton :icon="Plus" plain round type="primary" @click="handleCreate"> 新 增 </PermissionButton>
+				<VerticalDivider class="px-1" style="margin-left: 7px" />
+			</div>
+		</template>
+		<template #toolbar_tools>
+			<el-button circle class="toolbar-btn" @click="handleRefresh">
+				<el-icon>
+					<Refresh />
+				</el-icon>
+			</el-button>
+			<el-button circle class="mr-3 toolbar-btn" @click="handleDownload">
+				<el-icon>
+					<Download />
+				</el-icon>
+			</el-button>
+		</template>
+		<template #top>
+			<div class="mb-2"></div>
+		</template>
+		<template #pager>
+			<vxe-pager
+				v-model:currentPage="gridOptions.pagerConfig.page"
+				v-model:pageSize="gridOptions.pagerConfig.limit"
+				:total="gridOptions.pagerConfig.total"
+				class="mt-1.5"
+				@page-change="handlePageChange"
+			/>
+		</template>
+		<template #empty>
+			<el-empty description="暂无数据" />
+		</template>
+		<!-- 自定义列插槽 -->
+		<template v-for="col in CompetitorMonitorCommentColumns" #[`${col.field}`]="{ row }">
+			<DataTableSlot :key="row.id" :field="col.field" :row="row" @open-negativeLabel="showLabel" />
+		</template>
+	</vxe-grid>
+	<CreateDialog v-if="createOpen" v-model="createOpen" @refresh="fetchList" />
+	<NegativeLabel v-if="isShowLabel" v-model="isShowLabel" :rowData="rowData" />
 </template>
 
 <style scoped>
 .toolbar-btn {
-  width: 34px;
-  height: 34px;
-  font-size: 18px
+	width: 34px;
+	height: 34px;
+	font-size: 18px;
 }
 
 :deep(.custom-el-input .el-select__wrapper) {
-  border-radius: 20px;
+	border-radius: 20px;
 }
 </style>

+ 15 - 2
src/views/product-manage/comment-detail/component/NegativeLabel.vue

@@ -152,7 +152,11 @@ onMounted(() => {
             </template>
             <template #operate="{ row }">
               <div class="flex justify-center gap-2">
-                <el-button :icon="Edit" link type="primary" @click="handleEdit(row)"></el-button>
+								<PermissionButton circle plain type="warning" size="small" @click="handleEdit(row)">
+									<el-icon>
+										<Operation />
+									</el-icon>
+								</PermissionButton>
                 <el-popconfirm
                     :icon="InfoFilled"
                     icon-color="#626AEF"
@@ -161,7 +165,7 @@ onMounted(() => {
                     @confirm="singleDelete(row)"
                 >
                   <template #reference>
-                    <PermissionButton link type="danger">
+                    <PermissionButton circle plain size="small" type="danger">
                       <el-icon>
                         <Delete />
                       </el-icon>
@@ -211,4 +215,13 @@ onMounted(() => {
   font-weight: 600;
   color: #666;
 }
+
+.drawer-container :deep(.el-drawer__header) {
+	border-bottom: none;
+	font-weight: 500;
+}
+
+.drawer-container :deep(.el-drawer__title) {
+	font-size: 18px;
+}
 </style>

+ 17 - 17
src/views/product-manage/competitor-monitor/component/DataTable.vue

@@ -304,27 +304,27 @@ defineExpose({ fetchList });
           <Refresh />
         </el-icon>
       </el-button>
-      <el-popconfirm
-          :icon="InfoFilled"
-          icon-color="#626AEF"
-          title="是否确认导出当前时间内所有数据项?"
-          width="220"
-          @confirm="handleDownload"
-      >
-        <template #reference>
-          <el-button circle class="mr-3 toolbar-btn">
+      <!--<el-popconfirm-->
+      <!--    :icon="InfoFilled"-->
+      <!--    icon-color="#626AEF"-->
+      <!--    title="是否确认导出当前时间内所有数据项?"-->
+      <!--    width="220"-->
+      <!--    @confirm="handleDownload"-->
+      <!--&gt;-->
+      <!--  <template #reference>-->
+          <el-button circle class="mr-3 toolbar-btn" @click="handleDownload">
             <el-icon>
               <Download />
             </el-icon>
           </el-button>
-        </template>
-        <template #actions="{ confirm, cancel }">
-          <el-button size="small" @click="cancel">No!</el-button>
-          <el-button size="small" type="danger" @click="confirm">
-            Yes?
-          </el-button>
-        </template>
-      </el-popconfirm>
+      <!--  </template>-->
+      <!--  <template #actions="{ confirm, cancel }">-->
+      <!--    <el-button size="small" @click="cancel">No!</el-button>-->
+      <!--    <el-button size="small" type="danger" @click="confirm">-->
+      <!--      Yes?-->
+      <!--    </el-button>-->
+      <!--  </template>-->
+      <!--</el-popconfirm>-->
     </template>
     <template #top>
       <div class="mb-2"></div>

+ 9 - 0
src/views/product-manage/product-list/api.ts

@@ -116,3 +116,12 @@ export function exportData(query: any) {
     responseType: 'blob'
   });
 }
+
+// 同步群消息
+export function alarmMessage(body: any){
+  return request({
+    url: '/api/choice/goods/sku-alarm/',
+    method: 'POST',
+    data: body,
+  });
+}

+ 15 - 26
src/views/product-manage/product-list/component/DataTable.vue

@@ -19,6 +19,7 @@ import EditDrawer from '/src/views/product-manage/product-list/component/EditDra
 import NoticeDialog from '/src/views/product-manage/product-list/component/NoticeDialog.vue';
 import * as api from '../api';
 import { useResponse } from '/@/utils/useResponse';
+import DownloadError from '/@/views/product-manage/product-list/component/DownloadError.vue';
 
 
 interface Parameter {
@@ -82,6 +83,8 @@ const btnLoading = ref(false);
 
 const editOpen = ref(false);
 const rowData = ref({});
+const showError = ref(false);
+const errorMsg = ref({});
 
 const dialogVisible = ref(false);
 
@@ -233,6 +236,11 @@ function downloadTemplate() {
   }
 }
 
+function handleError(error: any) {
+	errorMsg.value = error;
+	showError.value = true;
+}
+
 const gridEvents = {
   custom({ type }: any) {
     if (type == 'confirm') {
@@ -280,7 +288,7 @@ defineExpose({ fetchList });
           <i class="bi bi-box-seam mr-3"></i>
           商品导入
         </ImportButton>
-        <ImportButton :icon="Money" :uploadFunction="api.uploadPrice" bg text>指导价格导入</ImportButton>
+        <ImportButton :icon="Money" :uploadFunction="api.uploadPrice" bg text @handelError="handleError">指导价格导入</ImportButton>
       </div>
     </template>
     <!-- 工具栏右侧 -->
@@ -290,31 +298,11 @@ defineExpose({ fetchList });
           <Refresh />
         </el-icon>
       </el-button>
-      <el-popconfirm
-          :icon="InfoFilled"
-          icon-color="#626AEF"
-          title="是否确认导出当前时间内所有数据项?"
-          width="220"
-          @confirm="handleDownload"
-      >
-        <template #reference>
-          <el-button circle class="mr-3 toolbar-btn">
-            <el-icon>
-              <Download />
-            </el-icon>
-          </el-button>
-        </template>
-        <template #actions="{ confirm, cancel }">
-          <el-button size="small" @click="cancel">No!</el-button>
-          <el-button
-              size="small"
-              type="danger"
-              @click="confirm"
-          >
-            Yes?
-          </el-button>
-        </template>
-      </el-popconfirm>
+			<el-button circle class="mr-3 toolbar-btn" @click="handleDownload">
+				<el-icon>
+					<Download />
+				</el-icon>
+			</el-button>
     </template>
     <template #top>
       <div class="mb-2"></div>
@@ -340,6 +328,7 @@ defineExpose({ fetchList });
   </vxe-grid>
   <EditDrawer v-if="editOpen" v-model="editOpen" :row-data="rowData" @refresh="handleRefresh" />
   <NoticeDialog v-if="dialogVisible" v-model="dialogVisible" :row-data="rowData" />
+	<DownloadError v-if="showError" v-model="showError" :errorMsg="errorMsg"></DownloadError>
 </template>
 
 <style scoped>

+ 88 - 0
src/views/product-manage/product-list/component/DownloadError.vue

@@ -0,0 +1,88 @@
+<script lang="ts" setup>
+/**
+ * @Name: DownloadError.vue
+ * @Description: 指导价格导入失败弹窗
+ * ElMessage(
+ * @Author: xinyan
+ */
+
+import { Close, Finished, Warning } from '@element-plus/icons-vue';
+import { useResponse } from '/@/utils/useResponse';
+import * as api from '/@/views/product-manage/product-list/api';
+import { ElMessage } from 'element-plus';
+
+const showError = defineModel({ default: false });
+const btnLoading = ref(false);
+
+const props = defineProps({
+	errorMsg: {
+		type: Object,
+		required: true,
+	},
+});
+
+const { errorMsg } = props;
+const firstThreeEntries = errorMsg.slice(0, 3);
+const emit = defineEmits(['refresh']);
+
+async function alarm() {
+	try {
+		const res = await useResponse(api.alarmMessage, { alarm_sku: errorMsg }, btnLoading);
+		if (res && res.code == 2000) {
+			showError.value = false;
+			ElMessage.success('同步成功');
+			emit('refresh');
+		}
+	} catch (error) {
+		console.log(error);
+		ElMessage.error('同步失败');
+	} finally {
+		showError.value = false;
+	}
+}
+
+function cancelDialog() {
+	showError.value = false;
+}
+</script>
+
+<template>
+	<el-dialog ref="noticeDialog" v-model="showError" :close-on-click-modal="false" :close-on-press-escape="false" class="notice-dialog" width="35%">
+		<template #title>
+			<div class="title">
+				<el-icon style="color: orange">
+					<Warning />
+				</el-icon>
+				<span class="pl-2">导入失败 {{ errorMsg.length }} 条</span>
+			</div>
+		</template>
+		<div>
+			<div v-for="(error, index) in firstThreeEntries" :key="index" class="error-message">
+				{{ index + 1 }}. SKU: {{ error.sku }} 在 {{ error.country_code }} 地区不存在
+			</div>
+		</div>
+		<div v-if="errorMsg.length > 3" class="error-message">...</div>
+		<template #footer>
+			<el-divider style="margin: 12px 0 20px 0"></el-divider>
+			<el-button :icon="Close" @click="cancelDialog">取 消</el-button>
+			<el-button :icon="Finished" :loading="btnLoading" type="primary" @click="alarm()">同步至群消息</el-button>
+		</template>
+	</el-dialog>
+</template>
+
+<style scoped>
+.error-message {
+	font-size: 14px;
+	font-weight: 500;
+	color: #666;
+	padding-bottom: 10px;
+}
+
+.title {
+	font-size: 18px;
+	font-weight: 500;
+	color: #666;
+	display: flex;
+	align-items: center;
+}
+</style>

+ 5 - 25
src/views/product-manage/product-monitor/component/DataTable.vue

@@ -300,31 +300,11 @@ defineExpose({ fetchList });
           <Refresh />
         </el-icon>
       </el-button>
-      <el-popconfirm
-          :icon="InfoFilled"
-          icon-color="#626AEF"
-          title="是否确认导出当前时间内所有数据项?"
-          width="220"
-          @confirm="handleDownload"
-      >
-        <template #reference>
-          <el-button circle class="mr-3 toolbar-btn">
-            <el-icon>
-              <Download />
-            </el-icon>
-          </el-button>
-        </template>
-        <template #actions="{ confirm, cancel }">
-          <el-button size="small" @click="cancel">No!</el-button>
-          <el-button
-              size="small"
-              type="danger"
-              @click="confirm"
-          >
-            Yes?
-          </el-button>
-        </template>
-      </el-popconfirm>
+			<el-button circle class="mr-3 toolbar-btn" @click="handleDownload">
+				<el-icon>
+					<Download />
+				</el-icon>
+			</el-button>
     </template>
     <template #top>
       <div class="mb-2"></div>

+ 9 - 1
src/views/sku-manage/Columns.ts

@@ -17,7 +17,7 @@ export const AttributeColumns = [
     slots: { default: 'create_datetime' }
   },
   {
-    field: 'operate', title: '操 作', width: 100, align: 'center', fixed: 'right',
+    field: 'operate', title: '操 作', width: 145, align: 'center', fixed: 'right',
     slots: { default: 'operate' }
   }
 ];
@@ -93,3 +93,11 @@ export const CompanySkuColumns = [
     slots: { default: 'operate' }
   }
 ];
+
+export const EnumColumns = [
+  {field:'label',title: '名称',minWidth: 100,align: 'center',},
+  {field:'value',title: '数据值',minWidth: 76,align: 'center',},
+  {field:'status',title: '状态',minWidth: 120,align: 'center',slots: { default: 'status' }},
+  {field:'operate',title: '操作',align: 'center',slots: { default: 'operate' }}
+]
+

+ 2 - 2
src/views/sku-manage/company-sku/api.ts

@@ -19,7 +19,7 @@ export function createObj (body: any) {
   })
 }
 
-export function PartialUpdateObj (id, body) {
+export function PartialUpdateObj (id: number, body: any) {
   return request({
     url: '/api/cms/sku/' + id + '/',
     method: 'put',
@@ -116,7 +116,7 @@ export function getBrandSelect() {
   })
 }
 
-export function GetDictionary (query) {
+export function GetDictionary (query: any) {
   return request({
     url: '/api/cms/sku_kind/dictionary/',
     method: 'get',

+ 1 - 1
src/views/sku-manage/company-sku/component/ShowSkuDrawer.vue

@@ -93,7 +93,7 @@ async function initData() {
 				section: '可选部分',
 				attrItems: optionalAttrs,
 			});
-			console.log('=>(ShowSkuDrawer.vue:100) optionalAttrs', optionalAttrs);
+			console.log('=>(ShowEnumDrawer.vue:100) optionalAttrs', optionalAttrs);
 		}
 	}
 	attrList.value = relatedAttrs;

+ 9 - 1
src/views/sku-manage/product-attribute/component/DataTable.vue

@@ -17,6 +17,7 @@ import EditDrawer from './EditDrawer.vue';
 import NoticeDialog from '/src/views/product-manage/product-list/component/NoticeDialog.vue';
 import * as api from '../api';
 import CreateDialog from '/src/views/sku-manage/product-attribute/component/CreateDialog.vue';
+import ManageEnumDrawer from '/src/views/sku-manage/product-attribute/component/manage-enum/index.vue';
 
 
 interface Parameter {
@@ -77,6 +78,7 @@ const gridOptions: any = reactive({
 
 const editOpen = ref(false);
 const createOpen = ref(false);
+const manageOpen = ref(false);
 const rowData = ref({});
 
 const dialogVisible = ref(false);
@@ -121,6 +123,11 @@ function handleEdit(row: any) {
   rowData.value = row;
 }
 
+function handleManage(row: any) {
+	manageOpen.value = true;
+  rowData.value = row;
+}
+
 function handleCreate() {
   createOpen.value = true;
 }
@@ -172,12 +179,13 @@ defineExpose({ fetchList });
     </template>
     <!-- 自定义列插槽 -->
     <template v-for="col in AttributeColumns" #[`${col.field}`]="{ row }">
-      <DataTableSlot :key="row.id" :field="col.field" :row="row" @edit-row="handleEdit" @handle-delete="singleDelete" />
+      <DataTableSlot :key="row.id" :field="col.field" :row="row" @edit-row="handleEdit" @handle-delete="singleDelete" @handle-manage="handleManage"/>
     </template>
   </vxe-grid>
   <EditDrawer v-if="editOpen" v-model="editOpen" :row-data="rowData" @refresh="handleRefresh" />
   <NoticeDialog v-if="dialogVisible" v-model="dialogVisible" :row-data="rowData" />
   <CreateDialog v-if="createOpen" v-model="createOpen" @refresh="fetchList" />
+	<ManageEnumDrawer v-if="manageOpen" v-model="manageOpen" :row-data="rowData" />
 </template>
 
 <style scoped>

+ 47 - 48
src/views/sku-manage/product-attribute/component/DataTableSlot.vue

@@ -5,69 +5,68 @@
  * @Author: Cheney
  */
 
-import { Delete, InfoFilled, Operation } from '@element-plus/icons-vue';
+import { Delete, InfoFilled, Operation, Tools } from '@element-plus/icons-vue';
 import PermissionButton from '/@/components/PermissionButton/index.vue';
 
-
 const props = defineProps<{
-  row: any,
-  field: any
+	row: any;
+	field: any;
 }>();
 const { row, field } = props;
 
-const emit = defineEmits([ 'edit-row', 'handle-delete' ]);
+const emit = defineEmits(['edit-row', 'handle-delete', 'handle-manage']);
 
 function handleEdit() {
-  emit('edit-row', row);
+	emit('edit-row', row);
 }
 
 function onConfirm() {
-  emit('handle-delete', row);
+	emit('handle-delete', row);
+}
+
+function handleManage() {
+	emit('handle-manage', row);
 }
 </script>
 
 <template>
-  <div class="font-medium">
-    <div v-if="field === 'operate'">
-      <div class="flex justify-center gap-2">
-        <PermissionButton circle plain type="warning" @click="handleEdit">
-          <el-icon>
-            <Operation />
-          </el-icon>
-        </PermissionButton>
-        <el-popconfirm
-            :icon="InfoFilled"
-            icon-color="#626AEF"
-            title="你确定要删除此项吗?"
-            width="220"
-            @confirm="onConfirm"
-        >
-          <template #reference>
-            <PermissionButton circle plain type="danger">
-              <el-icon>
-                <Delete />
-              </el-icon>
-            </PermissionButton>
-          </template>
-          <template #actions="{ confirm, cancel }">
-            <el-button size="small" @click="cancel">No!</el-button>
-            <el-button
-                size="small"
-                type="danger"
-                @click="confirm"
-            >
-              Yes?
-            </el-button>
-          </template>
-        </el-popconfirm>
-      </div>
-    </div>
-    <div v-else>
-      {{ row[field] }}
-    </div>
-  </div>
+	<div class="font-medium">
+		<div v-if="field === 'operate'">
+			<div class="flex justify-center gap-2">
+				<PermissionButton circle plain type="warning" @click="handleEdit">
+					<el-icon>
+						<Operation />
+					</el-icon>
+				</PermissionButton>
+				<el-popconfirm :icon="InfoFilled" icon-color="#626AEF" title="你确定要删除此项吗?" width="220" @confirm="onConfirm">
+					<template #reference>
+						<PermissionButton circle plain type="danger">
+							<el-icon>
+								<Delete />
+							</el-icon>
+						</PermissionButton>
+					</template>
+					<template #actions="{ confirm, cancel }">
+						<el-button size="small" @click="cancel">No!</el-button>
+						<el-button size="small" type="danger" @click="confirm"> Yes? </el-button>
+					</template>
+				</el-popconfirm>
+				<el-tooltip :enterable="false" :show-arrow="false" content="管理枚举" placement="top" popper-class="custom-btn-tooltip-2">
+					<el-button :icon="Tools" circle color="#6466F1" plain @click="handleManage"> </el-button>
+				</el-tooltip>
+			</div>
+		</div>
+		<div v-else>
+			{{ row[field] }}
+		</div>
+	</div>
 </template>
 
-<style scoped>
-
+<style lang="scss">
+.custom-btn-tooltip-2 {
+	background-color: #f0f0fe !important;
+	color: #606266 !important;
+	border: 1px solid #6466f1 !important;
+	font-size: 14px;
+}
 </style>

+ 45 - 0
src/views/sku-manage/product-attribute/component/manage-enum/api.ts

@@ -0,0 +1,45 @@
+import { request } from '/@/utils/service';
+
+
+const apiPrefix =  '/api/cms/sku_attr_dict/';
+
+export function getTableData(query: any) {
+	return request({
+		url: apiPrefix,
+		method: 'GET',
+		params: query
+	});
+}
+
+export function getAllDept(query: any) {
+	return request({
+		url: '/api/system/dept/all_dept/',
+		method: 'GET',
+		params: query
+	});
+}
+
+export function deleteRow(query: any) {
+	return request({
+		url: apiPrefix + query + '/',
+		method: 'DELETE',
+		params: query
+	});
+}
+
+export function updateRow(body: any) {
+	return request({
+		url: apiPrefix +`${body.id}/` ,
+		method: 'PUT',
+		data: body
+	});
+}
+
+export function createEnum(data:any) {
+	return request({
+		url: apiPrefix,
+		method: 'post',
+		data: data
+	})
+}
+

+ 106 - 0
src/views/sku-manage/product-attribute/component/manage-enum/component/CreateDialog.vue

@@ -0,0 +1,106 @@
+<script lang="ts" setup>
+/**
+ * @Name: CreateDialog.vue
+ * @Description: 属性枚举-创建对话框
+ * @Author: xinyan
+ */
+
+import { ElMessage, FormInstance, FormRules } from 'element-plus';
+import { useResponse } from '/@/utils/useResponse';
+import * as api from '../api';
+import { Close, Finished } from '@element-plus/icons-vue';
+
+const props = defineProps({
+	rowData: Object,
+});
+
+const { rowData } = props;
+const loading = ref(false);
+const createDialog = <Ref>useTemplateRef('createDialog');
+const createOpen = defineModel({ default: false });
+
+const emit = defineEmits(['refresh']);
+
+interface RuleForm {
+	label: any;
+	value: any;
+	status: boolean;
+}
+
+const ruleFormRef = ref<FormInstance>();
+const ruleForm = reactive<RuleForm>({
+	label: '',
+	value: '',
+	status: true,
+});
+
+const rules = reactive<FormRules<RuleForm>>({
+	label: [{ required: true, message: '请输入名称', trigger: 'blur' }],
+	value: [{ required: true, message: '请输入数据值', trigger: 'blur' }],
+});
+
+const submitForm = async (formEl: FormInstance | undefined) => {
+	if (!formEl) return;
+	await formEl.validate(async (valid, fields) => {
+		if (valid) {
+			const body = {
+				attr:rowData.id,
+				label: ruleForm.label,
+				value: ruleForm.value,
+				status: ruleForm.status,
+			};
+			const res = await useResponse(api.createEnum, body, loading);
+			if (res.code === 2000) {
+				ElMessage.success('创建成功');
+				createOpen.value = false;
+				emit('refresh');
+			}
+		} else {
+			// createOpen.value = false;
+			ElMessage.error('创建失败,请检查表单');
+		}
+	});
+};
+
+function cancelDialog() {
+	resetForm(ruleFormRef.value);
+	createDialog.value.visible = false;
+}
+
+const resetForm = (formEl: FormInstance | undefined) => {
+	if (!formEl) return;
+	formEl.resetFields();
+};
+</script>
+
+<template>
+	<el-dialog
+		ref="createDialog"
+		v-model="createOpen"
+		:close-on-click-modal="false"
+		:close-on-press-escape="false"
+		:title="`产品品牌 - 创建 `"
+		style="width: 30%"
+	>
+		<el-form ref="ruleFormRef" :model="ruleForm" :rules="rules" class="mx-2.5 mt-5" label-width="auto" status-icon>
+			<el-form-item class="font-medium" label="名称" prop="label">
+				<el-input v-model="ruleForm.label" placeholder="请输入名称" style="width: 328px" />
+			</el-form-item>
+			<el-form-item class="font-medium" label="数据值" prop="value">
+				<el-input v-model="ruleForm.value" placeholder="请输入数据值" style="width: 328px" />
+			</el-form-item>
+			<el-form-item class="font-medium" label="状态" prop="value">
+				<el-radio-group v-model="ruleForm.status">
+					<el-radio :label="true">启用</el-radio>
+					<el-radio :label="false">禁用</el-radio>
+				</el-radio-group>
+			</el-form-item>
+		</el-form>
+		<template #footer>
+			<el-button :icon="Close" @click="cancelDialog">取 消</el-button>
+			<el-button :icon="Finished" :loading="loading" type="primary" @click="submitForm(ruleFormRef)">确 定</el-button>
+		</template>
+	</el-dialog>
+</template>
+
+<style scoped></style>

+ 129 - 0
src/views/sku-manage/product-attribute/component/manage-enum/component/EditDrawer.vue

@@ -0,0 +1,129 @@
+<script lang="ts" setup>
+/**
+ * @Name: EditDrawer.vue
+ * @Description: 属性枚举-行编辑
+ * @Author: Cheney
+ */
+
+import { ElMessage, FormInstance, FormRules } from 'element-plus';
+import { Close, Finished } from '@element-plus/icons-vue';
+import { useResponse } from '/@/utils/useResponse';
+import * as api from '../api';
+import { updateRow } from '../api';
+
+
+const btnLoading = ref(false);
+
+const editOpen = defineModel({ default: false });
+const editDrawer = <Ref>useTemplateRef('editDrawer');
+
+const props = defineProps({
+	editData: <any>Object,
+  rowData: Object
+});
+const { editData , rowData } = props;
+
+const emit = defineEmits([ 'refresh' ]);
+
+interface RuleForm {
+  label: any,
+  value: any,
+	status: boolean;
+}
+
+const ruleFormRef = ref<FormInstance>();
+const ruleForm = reactive<RuleForm>({
+  label: editData?.label,
+  value: editData?.value,
+	status: editData?.status,
+});
+
+const rules = reactive<FormRules<RuleForm>>({
+	label: [{ required: true, message: '请输入名称', trigger: 'blur' }],
+	value: [{ required: true, message: '请输入数据值', trigger: 'blur' }],
+});
+
+const submitForm = async (formEl: FormInstance | undefined) => {
+  if (!formEl) return;
+  await formEl.validate(async (valid, fields) => {
+    if (valid) {
+      try {
+				const query = {
+					attr: rowData.id,
+					id: editData.id,
+					label: ruleForm.label,
+					value: ruleForm.value,
+				};
+        const res = await useResponse(api.updateRow, { id: editData?.id, ...query }, btnLoading);
+        if (res && res.code == 2000) {
+          editOpen.value = false;
+          ElMessage.success('编辑成功');
+          emit('refresh');
+        }
+      } catch (error) {
+        console.error('Error==>', error);
+      }
+    } else {
+      console.log('error submit!', fields);
+    }
+  });
+};
+
+function closeDrawer() {
+  editDrawer.value.handleClose();
+}
+
+</script>
+
+<template>
+  <div class="drawer-container">
+    <el-drawer ref="editDrawer"
+               v-model="editOpen"
+               :close-on-click-modal="false"
+               :close-on-press-escape="false"
+               :title="`产品属性- 编辑 `"
+               size="25%">
+      <el-form
+          ref="ruleFormRef"
+          :model="ruleForm"
+          :rules="rules"
+          class="mx-2.5 mt-7"
+          label-position="top"
+          label-width="auto"
+          status-icon>
+        <el-form-item class="font-medium" label="名称" prop="label">
+          <el-input v-model="ruleForm.label" />
+        </el-form-item>
+        <el-form-item class="font-medium" label="数据值" prop="value">
+          <el-input v-model="ruleForm.value" />
+        </el-form-item>
+				<el-form-item class="font-medium" label="状态" prop="value">
+					<el-radio-group v-model="ruleForm.status">
+						<el-radio :label="true">启用</el-radio>
+						<el-radio :label="false">禁用</el-radio>
+					</el-radio-group>
+				</el-form-item>
+        <el-form-item>
+          <el-divider />
+          <div class="flex flex-1 justify-end">
+            <el-button :icon="Close" @click="closeDrawer">取 消</el-button>
+            <el-button :icon="Finished" :loading="btnLoading" type="primary" @click="submitForm(ruleFormRef)">
+              确 定
+            </el-button>
+          </div>
+        </el-form-item>
+      </el-form>
+    </el-drawer>
+  </div>
+</template>
+
+<style scoped>
+.drawer-container :deep(.el-drawer__header) {
+  border-bottom: none;
+  font-weight: 500;
+}
+
+.drawer-container :deep(.el-drawer__title) {
+  font-size: 18px;
+}
+</style>

+ 101 - 0
src/views/sku-manage/product-attribute/component/manage-enum/component/ShowEnumDrawer.vue

@@ -0,0 +1,101 @@
+<script lang="ts" setup>/**
+ * @Name: ShowEnumDrawer.vue
+ * @Description: 属性枚举-详情抽屉
+ * @Author: xinyan
+ */
+import * as api from '../api';
+import { useResponse } from '/@/utils/useResponse';
+import { Warning } from '@element-plus/icons-vue';
+
+
+const showEnumDrawer = <Ref>useTemplateRef('showEnumDrawer');
+const viewOpen = defineModel({ default: false });
+
+const props = defineProps({
+	editData: <any>Object,
+});
+const { editData } = props;
+
+const deptData = ref([]);
+
+async function fetchAllDept() {
+	const  resp = await useResponse(api.getAllDept)
+	deptData.value = resp.data;
+}
+
+function getDeptName(id) {
+	const department = deptData.value.find(dept => dept.id === Number(id)); // 确保 id 是数字
+	return department ? department.name : id;
+}
+
+onMounted(() => {
+	fetchAllDept();
+});
+
+
+</script>
+
+<template>
+	<div class="drawer-container">
+		<el-drawer ref="showEnumDrawer" v-model="viewOpen" style="width: 40%" >
+			<template #title>
+				<div>
+					<span style="font-size: 16px; font-weight: bold">查看:</span>
+					<el-check-tag checked style="margin-left: 5px">{{ editData.label }}</el-check-tag>
+				</div>
+			</template>
+			<div class="p-5">
+				<el-descriptions :column="1" border>
+					<el-descriptions-item label="名称">
+						{{ editData.label }}
+					</el-descriptions-item>
+					<el-descriptions-item label="数据值">
+						{{ editData.value }}
+					</el-descriptions-item>
+					<el-descriptions-item label="状态">
+						<el-tag v-if="editData.status == true" type="success">启用</el-tag>
+						<el-tag v-else type="danger">禁用</el-tag>
+					</el-descriptions-item>
+					<el-descriptions-item label="创建人">
+						{{ editData.creator_name }}
+					</el-descriptions-item>
+					<el-descriptions-item label="所属部门">
+						<template #label>
+							<div style="display: flex;align-items: center">
+								所属部门
+								<el-tooltip effect="dark" content="默认不填则为当前创建用户的部门ID" placement="top">
+									<el-icon>
+										<Warning />
+									</el-icon>
+								</el-tooltip>
+							</div>
+						</template>
+						{{ getDeptName(editData.dept_belong_id) }}
+					</el-descriptions-item>
+					<el-descriptions-item label="更新时间">
+						{{ editData.update_datetime }}
+					</el-descriptions-item>
+					<el-descriptions-item label="创建时间">
+						{{ editData.create_datetime }}
+					</el-descriptions-item>
+				</el-descriptions>
+			</div>
+		</el-drawer>
+	</div>
+</template>
+
+<style scoped>
+.drawer-container :deep(.el-drawer__header) {
+	border-bottom: none;
+	/* font-weight: 500; */
+}
+
+:deep(.my-label) {
+	background: #f5f5f5 !important;
+}
+
+.my-value {
+	font-weight: 500;
+	font-size: 13px;
+}
+</style>

+ 232 - 0
src/views/sku-manage/product-attribute/component/manage-enum/index.vue

@@ -0,0 +1,232 @@
+<script lang="ts" setup>/**
+ * @Name: index.vue
+ * @Description:管理枚举弹窗
+ * @Author: xinyan
+ */
+import { Delete, View, InfoFilled, Operation, Plus } from '@element-plus/icons-vue';
+import PermissionButton from '/src/components/PermissionButton/index.vue';
+import { usePagination } from '/src/utils/usePagination';
+import { useTableData } from '/src/utils/useTableData';
+import * as api from './api';
+import { EnumColumns } from '/src/views/sku-manage/Columns';
+import { useResponse } from '/@/utils/useResponse';
+import { ElMessage } from 'element-plus';
+import CreateDialog from '/@/views/sku-manage/product-attribute/component/manage-enum/component/CreateDialog.vue';
+import EditDrawer from '/@/views/sku-manage/product-attribute/component/manage-enum/component/EditDrawer.vue';
+import EditLabelDialog from '/@/views/product-manage/comment-detail/component/EditLabelDialog.vue';
+import ShowEnumDrawer from '/@/views/sku-manage/product-attribute/component/manage-enum/component/ShowEnumDrawer.vue';
+
+const manageOpen = defineModel({ default: false });
+
+const props = defineProps({
+	rowData: Object,
+});
+
+const { rowData } = props;
+const { tableOptions, handlePageChange } = usePagination(fetchList);
+
+const createOpen = ref(false);
+const editOpen = ref(false);
+const viewOpen = ref(false);
+
+const editData = ref<any>();
+
+const formInline = reactive<any>({
+	label: '',
+	status: '',
+});
+
+const gridRef = ref();
+const gridOptions: any = reactive({
+	// id: 'NegativeLabel-table',
+	// keepSource: true,
+	height: 720,
+	size: 'mini',
+	border: false,
+	round: true,
+	stripe: true,
+	showHeader: true,
+	showOverflow: true,
+	currentRowHighLight: true,
+	toolbarConfig: {
+		size: 'large',
+		slots: {
+			buttons: 'toolbar_buttons'
+			// tools: 'toolbar_tools',
+		}
+	},
+	rowConfig: {
+		isHover: true
+	},
+	columnConfig: {
+		resizable: true
+	},
+	pagerConfig: {
+		total: tableOptions.value.total,
+		page: tableOptions.value.page,
+		limit: tableOptions.value.limit
+	},
+	loading: false,
+	loadingConfig: {
+		icon: 'vxe-icon-indicator roll',
+		text: '正在拼命加载中...'
+	},
+	columns: '',
+	data: ''
+});
+
+async function fetchList() {
+	gridOptions.data = [];
+	gridOptions.columns = [];
+
+	const query = {
+		attr: rowData.id,
+		label: formInline.label,
+		status: formInline.status,
+	};
+	await useTableData(api.getTableData, query, gridOptions);
+	await gridRef.value.loadColumn(EnumColumns);
+	gridOptions.showHeader = Boolean(gridOptions.data?.length);
+}
+
+async function singleDelete(row: any) {
+	const res = await useResponse(api.deleteRow, row.id);
+	if (res.code === 2000) {
+		ElMessage.success({ message: '删除成功', plain: true });
+		await fetchList();
+	}
+}
+
+function handleCreate() {
+	createOpen.value = true;
+}
+
+function handleView(row: any) {
+	editData.value = row;
+	viewOpen.value = true;
+}
+
+function handleEdit(row: any) {
+	editOpen.value = true;
+	editData.value = row;
+}
+
+function cellStyle() {
+	return {
+		fontWeight: 500
+	};
+}
+
+onMounted(() => {
+	fetchList();
+});
+</script>
+
+<template>
+	<div class="drawer-container">
+		<el-drawer ref="editDrawer"
+							 v-model="manageOpen"
+							 :close-on-click-modal="false"
+							 :close-on-press-escape="false"
+							 style="background-color: #f3f4fb"
+							 size="50%">
+			<template #title>
+				<div>
+					<span style="font-size: 16px; font-weight: bold">属性枚举:</span>
+					<el-check-tag checked style="margin-left: 5px">{{ rowData.name }}</el-check-tag>
+				</div>
+			</template>
+			<div class="p-5 w-full whitespace-nowrap">
+				<el-card style="height: 850px">
+					<el-row >
+						<el-col :span="8" >
+							<div>
+								<span class="mr-2">名称</span>
+								<el-input v-model="formInline.label" placeholder="请输入名称" clearable @change="fetchList"></el-input>
+							</div>
+						</el-col>
+						<el-col :span="8" :offset="4">
+							<div>
+								<span class="mr-2">状态</span>
+								<el-select v-model="formInline.status" placeholder="请选择状态" clearable @change="fetchList">
+									<el-option label="启用" value="1"></el-option>
+									<el-option label="禁用" value="0"></el-option>
+								</el-select>
+							</div>
+						</el-col>
+					</el-row>
+					<el-divider ref="dividerContainer" style="margin: 20px 0 12px 0" />
+					<vxe-grid ref="gridRef" :cell-style="cellStyle" v-bind="gridOptions">
+						<template #toolbar_buttons>
+							<div class="flex gap-2">
+								<PermissionButton :icon="Plus" plain round type="primary" @click="handleCreate"> 新 增</PermissionButton>
+							</div>
+						</template>
+						<template #status="{ row }">
+							<el-tag v-if="row.status == true" type="success">启用</el-tag>
+							<el-tag v-else type="danger">禁用</el-tag>
+						</template>
+						<template #operate="{ row }">
+							<div class="flex justify-center gap-2">
+								<el-button size="small" circle plain type="success" :icon="View" @click="handleView(row)"></el-button>
+								<PermissionButton circle plain type="warning" size="small" @click="handleEdit(row)">
+									<el-icon>
+										<Operation />
+									</el-icon>
+								</PermissionButton>
+								<el-popconfirm
+									:icon="InfoFilled"
+									icon-color="#626AEF"
+									title="你确定要删除此项吗?"
+									width="220"
+									@confirm="singleDelete(row)"
+								>
+									<template #reference>
+										<PermissionButton circle plain size="small" type="danger">
+											<el-icon>
+												<Delete />
+											</el-icon>
+										</PermissionButton>
+									</template>
+									<template #actions="{ confirm, cancel }">
+										<el-button size="small" @click="cancel">No!</el-button>
+										<el-button
+											size="small"
+											type="danger"
+											@click="confirm"
+										>
+											Yes?
+										</el-button>
+									</template>
+								</el-popconfirm>
+							</div>
+						</template>
+						<template #pager>
+							<vxe-pager
+								v-model:currentPage="gridOptions.pagerConfig.page"
+								v-model:pageSize="gridOptions.pagerConfig.limit"
+								:total="gridOptions.pagerConfig.total"
+								class="mt-1.5"
+								@page-change="handlePageChange"
+							/>
+						</template>
+					</vxe-grid>
+				</el-card>
+			</div>
+		</el-drawer>
+		<CreateDialog v-if="createOpen" v-model="createOpen" :rowData="rowData" @refresh="fetchList"></CreateDialog>
+		<EditDrawer v-if="editOpen" v-model="editOpen" :editData="editData" :rowData="rowData" @refresh="fetchList"></EditDrawer>
+		<ShowEnumDrawer v-if="viewOpen" v-model="viewOpen" :editData="editData" ></ShowEnumDrawer>
+	</div>
+</template>
+
+<style scoped>
+.drawer-container :deep(.el-drawer__header) {
+	border-bottom: none;
+	font-weight: 500;
+}
+
+.drawer-container :deep(.el-drawer__title) {
+	font-size: 18px;
+}
+</style>

+ 5 - 25
src/views/store-manage/online-merchandise/component/DataTable.vue

@@ -145,31 +145,11 @@ defineExpose({ fetchList });
           <Refresh />
         </el-icon>
       </el-button>
-      <el-popconfirm
-          :icon="InfoFilled"
-          icon-color="#626AEF"
-          title="是否确认导出当前时间内所有数据项?"
-          width="220"
-          @confirm="handleDownload"
-      >
-        <template #reference>
-          <el-button circle class="mr-3 toolbar-btn">
-            <el-icon>
-              <Download />
-            </el-icon>
-          </el-button>
-        </template>
-        <template #actions="{ confirm, cancel }">
-          <el-button size="small" @click="cancel">No!</el-button>
-          <el-button
-              size="small"
-              type="danger"
-              @click="confirm"
-          >
-            Yes?
-          </el-button>
-        </template>
-      </el-popconfirm>
+			<el-button circle class="mr-3 toolbar-btn" @click="handleDownload">
+				<el-icon>
+					<Download />
+				</el-icon>
+			</el-button>
     </template>
     <template #pager>
       <vxe-pager