Просмотр исходного кода

feat(product-manage):商品管理添加相关功能
--商品列表、商品监控添加下载功能;
--商品监控添加创建弹窗、实现创建功能;
--修改接口时间限制5000ms为120000ms;

xinyan 7 месяцев назад
Родитель
Сommit
cc39b517d6

+ 1 - 1
src/utils/service.ts

@@ -173,7 +173,7 @@ function createRequestFunction(service: any) {
 			headers: {
 				'Content-Type': get(config, 'headers.Content-Type', 'application/json'),
 			},
-			timeout: 5000,
+			timeout: 120000,
 			baseURL: getBaseURL(),
 			data: {},
 		};

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

@@ -114,4 +114,14 @@ export function uploadPrice(body: any){
     method: 'POST',
     data: body,
   });
+}
+
+// 导出
+export function exportData(query) {
+  return request({
+    url: '/api/choice/goods/export_data/',
+    method: 'GET',
+    params: query,
+    responseType: 'blob'
+  });
 }

+ 37 - 1
src/views/product-manage/product-list/component/DataTable.vue

@@ -101,6 +101,42 @@ function handleRefresh() {
   fetchList();
 }
 
+async function handleDownload() {
+	const confirmed = await ElMessageBox.confirm('是否确认导出当前时间内所有数据项?', '警告', {
+		confirmButtonText: '确定',
+		cancelButtonText: '取消',
+		type: 'warning'
+	});
+
+	if (confirmed) {
+		gridOptions.loading = true;
+		try {
+			const query = {
+				country_code: queryParameter?.country,
+				brand: queryParameter?.brand,
+				tag: queryParameter?.group,
+				status: queryParameter?.status,
+				asin: queryParameter?.asin,
+				sku: queryParameter?.sku,
+				shop_id: queryParameter?.shop
+			};
+			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 selectChangeEvent({ checked, row }: any) {
   if (checked) {
     checkedList.value.add(row.id); // 获取单个数据
@@ -222,7 +258,7 @@ defineExpose({ fetchList });
           <Refresh />
         </el-icon>
       </el-button>
-      <el-button circle class="mr-3 toolbar-btn">
+      <el-button circle class="mr-3 toolbar-btn" @click="handleDownload">
         <el-icon>
           <Download />
         </el-icon>

+ 19 - 1
src/views/product-manage/product-monitor/api.ts

@@ -11,6 +11,14 @@ export function getTableData(query: any) {
   });
 }
 
+export function createProductMonitor(body: any) {
+  return request({
+    url: '/api/choice/reviews_monitor/',
+    method: 'POST',
+    data: body
+  });
+}
+
 export function getGroupOptions(query: any) {
   return request({
     url: apiPrefix + 'goods/tags/',
@@ -51,4 +59,14 @@ export function upload(body: any){
     method: 'POST',
     data: body,
   });
-}
+}
+
+// 导出
+export function exportData(query) {
+  return request({
+    url: '/api/choice/reviews_monitor/export_data/',
+    method: 'GET',
+    params: query,
+    responseType: 'blob'
+  });
+}

+ 49 - 2
src/views/product-manage/product-monitor/component/DataTable.vue

@@ -13,6 +13,7 @@ import ImportButton from '/src/components/ImportButton/index.vue';
 import VerticalDivider from '/src/components/VerticalDivider/index.vue';
 import { productColumns } from '../ColumnsTsx';
 import DataTableSlot from '/@/views/product-manage/product-monitor/component/DataTableSlot.vue';
+import CreateDialog from '/@/views/product-manage/product-monitor/component/createDialog.vue';
 
 
 interface Parameter {
@@ -70,6 +71,7 @@ const gridOptions: any = reactive({
 const checkedList = ref<Set<number>>(new Set());
 
 const editOpen = ref(false);
+const createOpen = ref(false);
 const rowData = ref({});
 
 const dialogVisible = ref(false);
@@ -107,6 +109,46 @@ function handleRefresh() {
   fetchList();
 }
 
+async function handleDownload() {
+	const confirmed = await ElMessageBox.confirm('是否确认导出当前时间内所有数据项?', '警告', {
+		confirmButtonText: '确定',
+		cancelButtonText: '取消',
+		type: 'warning'
+	});
+
+	if (confirmed) {
+		gridOptions.loading = true;
+		try {
+			const query = {
+				country_code: queryParameter?.country,
+				goods__brand: queryParameter?.brand,
+				goods__tag: queryParameter?.group,
+				status: queryParameter?.status,
+				shop_id: queryParameter?.shop,
+				asin: queryParameter?.asin,
+				goods__sku: queryParameter?.sku,
+				platform_number: queryParameter?.platformId,
+				goods__all_ratings: queryParameter?.scoreNumber,
+				goods__all_reviews: queryParameter?.commentNumber,
+				goods__all_score: queryParameter?.displayScore
+			};
+			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; // 结束加载状态
+		}
+	}
+}
+
 async function batchOpen() {
   const ids = Array.from(checkedList.value);
   await useResponse(api.updateShopDetail, { ids, status: 1 });
@@ -141,6 +183,10 @@ function handleEdit(row: any) {
   rowData.value = row;
 }
 
+function handleCreate() {
+	createOpen.value = true;
+}
+
 function singleDelete(row: any) {
   // dialogVisible.value = true;
   rowData.value = row;
@@ -163,7 +209,7 @@ defineExpose({ fetchList });
         <PermissionButton :disabled="!checkedList.size" :icon="Delete" plain round type="danger" @click="batchOpen">
           批量删除
         </PermissionButton>
-        <PermissionButton :icon="Plus" plain round type="primary" @click="batchOpen">
+        <PermissionButton :icon="Plus" plain round type="primary" @click="handleCreate">
           新 增
         </PermissionButton>
         <div class="custom-el-input">
@@ -192,7 +238,7 @@ defineExpose({ fetchList });
           <Refresh />
         </el-icon>
       </el-button>
-      <el-button circle class="mr-3 toolbar-btn">
+      <el-button circle class="mr-3 toolbar-btn" @click="handleDownload">
         <el-icon>
           <Download />
         </el-icon>
@@ -216,6 +262,7 @@ defineExpose({ fetchList });
     </template>
   </vxe-grid>
   <EditDrawer v-if="editOpen" v-model="editOpen" :row-data="rowData" />
+	<CreateDialog v-if="createOpen" v-model="createOpen" @refresh="fetchList" />
 </template>
 
 <style scoped>

+ 154 - 0
src/views/product-manage/product-monitor/component/createDialog.vue

@@ -0,0 +1,154 @@
+<script lang="ts" setup>
+/**
+ * @Name: EditDrawer.vue
+ * @Description: 商品监控-行编辑
+ * @Author: Cheney
+ */
+
+import { ElMessage, FormInstance, FormRules } from 'element-plus';
+import { DictionaryStore } from '/@/stores/dictionary';
+import * as api from '../api';
+
+const shopOptions = <Ref>inject('shopOptions');
+const groupOptions = <Ref>inject('groupOptions');
+const { data: staticData } = DictionaryStore();
+
+const loading = ref(false);
+const createOpen = defineModel({ default: false });
+
+const emit = defineEmits(['refresh']);
+
+interface RuleForm {
+	asin: any;
+	sku: any;
+	country: any;
+	shop: any;
+	group: any;
+	// status: any;
+	frequency: any;
+	description: any;
+}
+
+const ruleFormRef = ref<FormInstance>();
+const ruleForm = reactive<RuleForm>({
+	asin: '',
+	sku: '',
+	country: '',
+	shop: '',
+	group: '',
+	// status: '',
+	frequency: 6,
+	description: '',
+});
+
+const rules = reactive<FormRules<RuleForm>>({
+	asin: [{ required: true, message: '请输入ASIN', trigger: 'blur' }],
+	sku: [{ required: true, message: '请输入SKU', trigger: 'blur' }],
+	country: [{ required: true, message: '请选择国家', trigger: 'change' }],
+	shop: [{ required: true, message: '请输入店铺', trigger: 'blur' }],
+	group: [{ required: true, message: '请输入分组', trigger: 'blur' }],
+	status: [{ message: '请选择状态', trigger: 'blur' }],
+	// frequency: [ { message: '请选择更新频率', trigger: 'blur' } ]
+});
+
+const submitForm = async (formEl: FormInstance | undefined) => {
+	if (!formEl) return;
+	await formEl.validate(async (valid, fields) => {
+		if (valid) {
+			const body = {
+				asin: ruleForm.asin,
+				sku: ruleForm.sku,
+				country_code: ruleForm.country,
+				shop_id: ruleForm.shop,
+				tag: ruleForm.group,
+				goods: {
+					sku: ruleForm.sku,
+					tag: ruleForm.group,
+				},
+				freq: ruleForm.frequency,
+				description: ruleForm.description,
+			};
+			const res = await useResponse(api.createProductMonitor, body, loading);
+			if (res.code === 2000){
+				ElMessage.success('创建成功');
+				createOpen.value = false;
+				emit('refresh');
+			}
+		} else {
+			createOpen.value = false;
+			ElMessage.error('创建失败,请检查表单');
+		}
+	});
+};
+
+const resetForm = (formEl: FormInstance | undefined) => {
+	if (!formEl) return;
+	formEl.resetFields();
+};
+</script>
+
+<template>
+	<el-dialog v-model="createOpen" :close-on-click-modal="false" :close-on-press-escape="false" :title="`商品监控 - 创建 `" style="width: 40%">
+		<el-form ref="ruleFormRef" :model="ruleForm" :rules="rules" label-position="top" label-width="auto" class="mx-2.5 mt-5" status-icon>
+			<el-row :gutter="20">
+				<el-col :span="24">
+					<el-form-item class="font-medium" label="ASIN" prop="asin">
+						<el-input v-model="ruleForm.asin" placeholder="不再支持批量创建(批量创建使用Excel导入),请填写单个asin" />
+					</el-form-item>
+				</el-col>
+
+				<el-col :span="12">
+					<el-form-item class="font-medium" label="SKU" prop="sku">
+						<el-input v-model="ruleForm.sku" placeholder="请输入SKU" />
+					</el-form-item>
+				</el-col>
+
+				<el-col :span="12">
+					<el-form-item class="font-medium" label="店 铺" prop="shop">
+						<el-select v-model="ruleForm.shop" placeholder="请选择店铺">
+							<el-option v-for="item in shopOptions" :key="item.id" :label="item.name" :value="item.id" />
+						</el-select>
+					</el-form-item>
+				</el-col>
+
+				<el-col :span="12">
+					<el-form-item class="font-medium" label="分 组" prop="group">
+						<el-select v-model="ruleForm.group" placeholder="请选择分组">
+							<el-option v-for="item in groupOptions" :label="item.tag" :value="item.tag" />
+						</el-select>
+					</el-form-item>
+				</el-col>
+
+				<el-col :span="12">
+					<el-form-item class="font-medium" label="国 家" prop="country">
+						<el-select v-model="ruleForm.country" placeholder="请选择国家">
+							<el-option v-for="item in staticData.country_code" :key="item.value" :label="item.label" :value="item.value" />
+						</el-select>
+					</el-form-item>
+				</el-col>
+
+				<el-col :span="12">
+					<el-form-item class="font-medium" label="更新频率" prop="frequency">
+						<el-input-number v-model="ruleForm.frequency" min="3" />
+					</el-form-item>
+				</el-col>
+
+				<el-col :span="12">
+					<el-form-item class="font-medium" label="备注" prop="description">
+						<el-input v-model="ruleForm.description" type="textarea" placeholder="请输入备注信息" maxlength="200" show-word-limit />
+					</el-form-item>
+				</el-col>
+			</el-row>
+		</el-form>
+		<template #footer>
+			<el-button :loading="loading" type="primary" @click="submitForm(ruleFormRef)">确 定</el-button>
+			<el-button @click="resetForm(ruleFormRef)">重 置</el-button>
+		</template>
+	</el-dialog>
+</template>
+
+<style scoped>
+:deep(.el-drawer .el-drawer__header) {
+	border: none !important;
+}
+</style>

+ 4 - 0
src/views/product-manage/product-monitor/index.vue

@@ -42,6 +42,10 @@ const groupOptions: any = ref([]);
 const brandsOptions: any = ref([]);
 const shopsOptions: any = ref([]);
 
+provide('groupOptions', groupOptions);
+provide('brandsOptions', brandsOptions);
+provide('shopOptions', shopsOptions);
+
 onBeforeMount(() => {
   fetchGroupOptions();
   fetchBrandsOptions();