Parcourir la source

feat(price-approval): 添加成本选择添加功能

- 新增成本选择相关的 API 和数据结构
- 实现成本选择页面的组件和逻辑
- 添加成本选择相关的表格列定义
- 优化成本选择页面的样式和交互
WanGxC il y a 5 mois
Parent
commit
f0894b3238

+ 38 - 0
src/views/price-approval/Columns.ts

@@ -41,6 +41,44 @@ export const CostDetailColumns = [
 	{ field: 'operate', fixed: 'right', title: '操 作', align: 'center', width: 90, slots: { default: 'operate' } }
 ];
 
+export const CostSelectColumns = [
+	{ type: 'checkbox', minWidth: 50, align: 'center' },
+	{ field: 'description', title: '描 述', minWidth: 200, align: 'center', showOverflow: true },
+	{ field: 'station', title: '地 区', minWidth: 100, align: 'center', showOverflow: true },
+	{ field: 'platform', title: '平 台', minWidth: 100, align: 'center', showOverflow: true },
+	// { field: '', title: '货币单位', minWidth: 'auto', align: 'center', showOverflow: true,},
+	{
+		title: '税费成本', align: 'center',
+		children: [
+			{ field: 'export_tax_rate', title: '出口报关费率', minWidth: 'auto', align: 'center', },
+			{ field: 'import_tax_rate', title: '进口关税率', minWidth: 'auto', align: 'center', },
+			{ field: 'VAT_rate', title: 'VAT', minWidth: 'auto', align: 'center', },
+		],
+	},
+	{
+		title: '运输成本', align: 'center',
+		children: [
+			{ field: 'first_cost', title: '头程运输费率', minWidth: 'auto', align: 'center', },
+			{ field: 'forwarding_fee', title: '转发费', minWidth: 'auto', align: 'center', },
+		],
+	},
+	{
+		title: '销售成本', align: 'center',
+		children: [
+			{ field: 'return_or_refurbishment_rates', title: '退货与翻新费', minWidth: 'auto', align: 'center',
+			},
+			{ field: 'advertising_budget_rate', title: '广告预算费率', minWidth: 'auto', align: 'center',
+			},
+			{ field: 'storage_charges_rate', title: '仓储费', minWidth: 'auto', align: 'center',
+			},
+			{ field: 'brokerage_rate', title: '佣金', minWidth: 'auto', align: 'center',
+			},
+		],
+	},
+	{ field: 'price_supply_rate', title: '供货价折算率', minWidth: 'auto', align: 'center',
+		slots: { default: 'price_supply_rate' }},
+];
+
 
 export const SupplyCheckColumns_Regular = [
 	{ type: 'seq', title: '序 号', width: 50, align: 'center' },

+ 18 - 0
src/views/price-approval/api.ts

@@ -0,0 +1,18 @@
+import { request } from '/@/utils/service';
+
+
+export function getTableData(query: any) {
+  return request({
+    url: '/api/pricing/price_cost/',
+    method: 'GET',
+    params: query
+  });
+}
+
+export function getCostOptions(query: any) {
+  return request({
+    url: '/api/pricing/price_cost/box/',
+    method: 'GET',
+    params: query
+  });
+}

+ 35 - 17
src/views/price-approval/components/SelectDrawer.vue

@@ -1,4 +1,5 @@
-<script lang="ts" setup>/**
+<script lang="ts" setup>
+/**
  * @Name: SelectDrawer.vue
  * @Description: 成本选择抽屉
  * @Author: Cheney
@@ -6,13 +7,15 @@
 
 import { hasPermission } from '/@/utils/hasPermission';
 import { Plus, Refresh } from '@element-plus/icons-vue';
-import { CompetitorMonitorCommentColumns } from '/@/views/product-manage/Columns';
 import VerticalDivider from '/@/components/VerticalDivider/index.vue';
 import PermissionButton from '/@/components/PermissionButton/index.vue';
-import DataTableSlot from '/@/views/product-manage/comment-detail/component/DataTableSlot.vue';
+import DataTableSlot from '/@/views/price-approval/cost-detail/component/DataTableSlot.vue';
 import { usePagination } from '/@/utils/usePagination';
 import { useTableData } from '/@/utils/useTableData';
-import * as api from '/@/views/product-manage/comment-detail/api';
+import * as api from '../api';
+import { CostDetailColumns, CostSelectColumns } from '/@/views/price-approval/Columns';
+import { useResponse } from '/@/utils/useResponse';
+import CreateDialog from '/@/views/price-approval/cost-detail/component/CreateDialog.vue';
 
 
 const isShow = defineModel({ default: false });
@@ -26,6 +29,10 @@ const { rowData, title } = props;
 const queryRow = reactive<any>({});
 
 const platformOptions = ref([]);
+const stationOptions = ref([]);
+provide('stationOptions', stationOptions);
+
+const createOpen = ref(false);
 
 const { tableOptions, handlePageChange } = usePagination(fetchList);
 
@@ -71,13 +78,13 @@ async function fetchList(isQuery = false) {
   gridOptions.columns = [];
 
   const query = {
-    // asin: asin,
-    // country_code: formInline?.country,
-    // score: formInline?.score,
-    // tiv: formInline?.tiv,
+    description: queryRow?.description,
+    platform: queryRow?.platform,
+    station: queryRow?.station
   };
+
   await useTableData(api.getTableData, query, gridOptions);
-  await gridRef.value.loadColumn(CompetitorMonitorCommentColumns);
+  await gridRef.value.loadColumn(CostSelectColumns);
   gridOptions.showHeader = Boolean(gridOptions.data?.length);
 }
 
@@ -86,8 +93,19 @@ function handleRefresh() {
 }
 
 function handleCreate() {
+  createOpen.value = true;
+}
 
+async function fetchOptions() {
+  const resp = (await useResponse(api.getCostOptions)).data;
+  platformOptions.value = resp.platform_list;
+  stationOptions.value = resp.station_list;
 }
+
+onBeforeMount(() => {
+  fetchList();
+  fetchOptions();
+});
 </script>
 
 <template>
@@ -109,22 +127,22 @@ function handleCreate() {
                 <el-col :span="5">
                   <div class="flex items-center">
                     <span class="mr-2">描 述</span>
-                    <el-input v-model="queryRow.description" clearable placeholder="请输入描述" />
+                    <el-input v-model="queryRow.description" clearable placeholder="请输入描述" @change="fetchList(true)" />
                   </div>
                 </el-col>
                 <el-col :span="4" class="flex">
                   <div class="flex items-center">
                     <span class="mr-2">地 区</span>
-                    <el-select v-model="queryRow.station" clearable placeholder="请选择地区">
-                      <el-option></el-option>
+                    <el-select v-model="queryRow.station" clearable placeholder="请选择地区" @change="fetchList(true)">
+                      <el-option v-for="item in stationOptions" :key="item" :label="item" :value="item" />
                     </el-select>
                   </div>
                 </el-col>
                 <el-col :span="4">
                   <div class="flex items-center">
                     <span class="mr-2">平 台</span>
-                    <el-select v-model="queryRow.platform" placeholder="请选择平台">
-                      <el-option v-for="item in platformOptions" :key="item" :label="item" :value="item"></el-option>
+                    <el-select v-model="queryRow.platform" placeholder="请选择平台" @change="fetchList(true)">
+                      <el-option v-for="item in platformOptions" :key="item" :label="item" :value="item" />
                     </el-select>
                   </div>
                 </el-col>
@@ -164,14 +182,14 @@ function handleCreate() {
             <template #empty>
               <el-empty description="暂无数据" />
             </template>
-            <!-- 自定义列插槽 -->
-            <template v-for="col in CompetitorMonitorCommentColumns" #[`${col.field}`]="{ row }">
-              <DataTableSlot :key="row.id" :field="col.field" :row="row" />
+            <!-- TODO: 供货价折算率 -->
+            <template #price_supply_rate>
             </template>
           </vxe-grid>
         </el-card>
       </div>
     </el-drawer>
+    <CreateDialog v-if="createOpen" v-model="createOpen" @refresh="fetchList" />
   </div>
 </template>
 

+ 1 - 1
src/views/price-approval/cost-detail/component/DataTableSlot.vue

@@ -64,4 +64,4 @@ function onConfirm() {
 
 <style scoped>
 
-</style>
+</style>

+ 181 - 179
src/views/price-approval/direct-sales/component/DataTable.vue

@@ -18,17 +18,17 @@ import VerticalDivider from '/src/components/VerticalDivider/index.vue';
 import * as api from '../api';
 import { useResponse } from '/@/utils/useResponse';
 import {
-	DirectSalesCheckColumns_Regular, DirectSalesCheckColumns_Special,
+  DirectSalesCheckColumns_Regular, DirectSalesCheckColumns_Special
 } from '/@/views/price-approval/Columns';
 import EditDrawer from '/@/views/price-approval/direct-sales/component/EditDrawer.vue';
 import router from '/@/router';
 
 
 interface Parameter {
-	sku: string;
-	platform: string;
-	country_code: string;
-	sales_mode: string;
+  sku: string;
+  platform: string;
+  country_code: string;
+  sales_mode: string;
 }
 
 const queryParameter: Parameter | undefined = inject('query-parameter');
@@ -36,37 +36,37 @@ const { tableOptions, handlePageChange } = usePagination(fetchList);
 
 const gridRef = ref();
 const gridOptions: any = reactive({
-	size: 'mini',
-	border: false,
-	round: true,
-	stripe: true,
-	currentRowHighLight: true,
-	height: '100%',
-	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: '',
+  size: 'mini',
+  border: false,
+  round: true,
+  stripe: true,
+  currentRowHighLight: true,
+  height: '100%',
+  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: ''
 });
 
 const checkedList = ref<Set<number>>(new Set());
@@ -80,55 +80,57 @@ const dialogVisible = ref(false);
 const templateType = ref('cost');
 
 onBeforeMount(() => {
-	gridOptions.pagerConfig.limit = 10;
+  gridOptions.pagerConfig.limit = 10;
 });
 
 onMounted(() => {
-	fetchList();
+  fetchList();
 });
 
 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 = {
-		sku: queryParameter?.sku,
-		platform: queryParameter?.platform,
-		country_code:queryParameter?.country_code,
-		sales_mode: queryParameter?.sales_mode,
-	};
+  const query = {
+    sku: queryParameter?.sku,
+    platform: queryParameter?.platform,
+    country_code: queryParameter?.country_code,
+    sales_mode: queryParameter?.sales_mode
+  };
 
-	await useTableData(api.getTableData, query, gridOptions);
-	await gridRef.value.loadColumn(DirectSalesCheckColumns_Special);
-	gridOptions.showHeader = Boolean(gridOptions.data?.length);
+  await useTableData(api.getTableData, query, gridOptions);
+  if (gridOptions && gridOptions.data?.length) {
+    await gridRef.value.loadColumn(DirectSalesCheckColumns_Special);
+  }
+  gridOptions.showHeader = Boolean(gridOptions.data?.length);
 }
 
 function handleRefresh() {
-	fetchList();
+  fetchList();
 }
 
 async function handleDownload() {
-	// gridOptions.loading = true;
-	// try {
-	// 	await uesDownloadFile({
-	// 		apiMethod: api.exportData, // 调用的 API 方法
-	// 		queryParams: {
-	// 			sku: queryParameter?.sku,
-	// 			platform: queryParameter?.platform,
-	// 			country_code:queryParameter?.country_code,
-	// 			sales_mode: queryParameter?.sales_mode,
-	// 		},
-	// 		fileName: '审批查看(直销)数据.xlsx', // 自定义文件名
-	// 		successMessage: () => ElMessage.success('数据导出成功!'),
-	// 		errorMessage: () => ElMessage.error('数据导出失败,请重试!'),
-	// 	});
-	// } finally {
-	// 	gridOptions.loading = false; // 结束加载状态
-	// }
+  // gridOptions.loading = true;
+  // try {
+  // 	await uesDownloadFile({
+  // 		apiMethod: api.exportData, // 调用的 API 方法
+  // 		queryParams: {
+  // 			sku: queryParameter?.sku,
+  // 			platform: queryParameter?.platform,
+  // 			country_code:queryParameter?.country_code,
+  // 			sales_mode: queryParameter?.sales_mode,
+  // 		},
+  // 		fileName: '审批查看(直销)数据.xlsx', // 自定义文件名
+  // 		successMessage: () => ElMessage.success('数据导出成功!'),
+  // 		errorMessage: () => ElMessage.error('数据导出失败,请重试!'),
+  // 	});
+  // } finally {
+  // 	gridOptions.loading = false; // 结束加载状态
+  // }
 }
 
 function handleCreate() {
@@ -136,138 +138,138 @@ function handleCreate() {
 }
 
 function handleEdit(row: any) {
-	editOpen.value = true;
-	rowData.value = row;
+  editOpen.value = true;
+  rowData.value = row;
 }
 
 async function singleDelete(row: any) {
-	const res = await useResponse(api.deleteRow, row);
-	if (res.code === 2000) {
-		ElMessage.error({ message: '已删除!', plain: true, icon: 'Delete' });
-		handleRefresh();
-	}
+  const res = await useResponse(api.deleteRow, row);
+  if (res.code === 2000) {
+    ElMessage.error({ message: '已删除!', plain: true, icon: 'Delete' });
+    handleRefresh();
+  }
 }
 
-
 function downloadTemplate() {
-	// const url = '/api/choice/reviews_monitor/import_data/';
-	// const fileName = '审批查看(直销)模板.xlsx';
-	//
-	// if (url) {
-	// 	downloadFile({
-	// 		url,
-	// 		method: 'GET',
-	// 		filename: fileName,
-	// 	});
-	// } else {
-	// 	console.error('未知的模板类型:', templateType.value);
-	// }
+  // const url = '/api/choice/reviews_monitor/import_data/';
+  // const fileName = '审批查看(直销)模板.xlsx';
+  //
+  // if (url) {
+  // 	downloadFile({
+  // 		url,
+  // 		method: 'GET',
+  // 		filename: fileName,
+  // 	});
+  // } else {
+  // 	console.error('未知的模板类型:', templateType.value);
+  // }
 }
 
 const gridEvents = {
-	custom({ type }: any) {
-		if (type == 'confirm') {
-			fetchList();
-		}
-	},
+  custom({ type }: any) {
+    if (type == 'confirm') {
+      fetchList();
+    }
+  }
 };
 
-function cellStyle(){
-	return{
-		fontWeight:600,
-	}
+function cellStyle() {
+  return {
+    fontWeight: 600
+  };
 }
 
 defineExpose({ fetchList });
 </script>
 
 <template>
-	<vxe-grid ref="gridRef" v-bind="gridOptions" v-on="gridEvents" @checkbox-change="selectChangeEvent" @checkbox-all="selectAllChangeEvent" :cell-style="cellStyle">
-		<!-- 工具栏左侧 -->
-		<template #toolbar_buttons>
-			<div class="flex gap-2">
-				<!--<div>-->
-				<!--	<el-popconfirm :icon="InfoFilled" icon-color="#626AEF" title="你确定要删除此项吗?" width="220" @confirm="batchDelete">-->
-				<!--		<template #reference>-->
-				<!--			<PermissionButton :disabled="!checkedList.size" :icon="Delete" plain round type="danger"> 批量删除 </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>
-					<PermissionButton :icon="Plus" plain round type="primary" @click="handleCreate">新 增</PermissionButton>
-				</div>
-				<div class="custom-el-input">
-					<el-select v-model="templateType" style="width: 200px">
-						<template #prefix>
-							<div class="flex items-center">
-								<el-button
-									size="small"
-									style="margin-left: -7px; font-size: 14px; border-radius: 29px"
-									text
-									type="success"
-									@click.stop="downloadTemplate"
-								>
-									下载
-								</el-button>
-								<VerticalDivider style="margin-left: 7px" />
-							</div>
-						</template>
-						<el-option label="审批查看(直销)" value="cost" />
-					</el-select>
-				</div>
-				<VerticalDivider class="px-1" style="margin-left: 7px" />
-				<ImportButton :icon="Upload" :uploadFunction="api.upload" bg text>导 入</ImportButton>
-			</div>
-		</template>
-		<!-- 工具栏右侧 -->
-		<template #toolbar_tools>
-			<el-button circle class="toolbar-btn" @click="handleRefresh">
-				<el-icon>
-					<Refresh />
-				</el-icon>
-			</el-button>
-			<el-button circle class="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 DirectSalesCheckColumns_Special" #[`${col.field}`]="{ row }">
-			<DataTableSlot :field="col.field" :row="row" @edit-row="handleEdit" @handle-delete="singleDelete" />
-		</template>
-	</vxe-grid>
-	<EditDrawer v-if="editOpen" v-model="editOpen" :row-data="rowData" @refresh="handleRefresh" />
+  <vxe-grid ref="gridRef" :cell-style="cellStyle" v-bind="gridOptions" v-on="gridEvents"
+            @checkbox-change="selectChangeEvent" @checkbox-all="selectAllChangeEvent">
+    <!-- 工具栏左侧 -->
+    <template #toolbar_buttons>
+      <div class="flex gap-2">
+        <!--<div>-->
+        <!--	<el-popconfirm :icon="InfoFilled" icon-color="#626AEF" title="你确定要删除此项吗?" width="220" @confirm="batchDelete">-->
+        <!--		<template #reference>-->
+        <!--			<PermissionButton :disabled="!checkedList.size" :icon="Delete" plain round type="danger"> 批量删除 </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>
+          <PermissionButton :icon="Plus" plain round type="primary" @click="handleCreate">新 增</PermissionButton>
+        </div>
+        <div class="custom-el-input">
+          <el-select v-model="templateType" style="width: 200px">
+            <template #prefix>
+              <div class="flex items-center">
+                <el-button
+                    size="small"
+                    style="margin-left: -7px; font-size: 14px; border-radius: 29px"
+                    text
+                    type="success"
+                    @click.stop="downloadTemplate"
+                >
+                  下载
+                </el-button>
+                <VerticalDivider style="margin-left: 7px" />
+              </div>
+            </template>
+            <el-option label="审批查看(直销)" value="cost" />
+          </el-select>
+        </div>
+        <VerticalDivider class="px-1" style="margin-left: 7px" />
+        <ImportButton :icon="Upload" :uploadFunction="api.upload" bg text>导 入</ImportButton>
+      </div>
+    </template>
+    <!-- 工具栏右侧 -->
+    <template #toolbar_tools>
+      <el-button circle class="toolbar-btn" @click="handleRefresh">
+        <el-icon>
+          <Refresh />
+        </el-icon>
+      </el-button>
+      <el-button circle class="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 DirectSalesCheckColumns_Special" #[`${col.field}`]="{ row }">
+      <DataTableSlot :field="col.field" :row="row" @edit-row="handleEdit" @handle-delete="singleDelete" />
+    </template>
+  </vxe-grid>
+  <EditDrawer v-if="editOpen" v-model="editOpen" :row-data="rowData" @refresh="handleRefresh" />
 </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>