|
|
@@ -1,149 +1,64 @@
|
|
|
<template>
|
|
|
<div class="app-container">
|
|
|
- <!-- 页面头部 -->
|
|
|
- <div class="detail-header">
|
|
|
- <el-icon class="back-icon" @click="goBack"><ArrowLeft /></el-icon>
|
|
|
- <span class="header-title">编辑合约供货</span>
|
|
|
- </div>
|
|
|
|
|
|
- <!-- 表单卡片 -->
|
|
|
- <el-card shadow="never" class="form-card">
|
|
|
- <el-form ref="formRef" :model="form" :rules="rules" label-width="100px" class="large-form">
|
|
|
- <el-row :gutter="20">
|
|
|
- <el-col :span="8">
|
|
|
- <el-form-item label="协议编号" prop="contractSupplyNo">
|
|
|
- <span class="form-text">{{ form.contractSupplyNo }}</span>
|
|
|
- </el-form-item>
|
|
|
- </el-col>
|
|
|
- <el-col :span="8">
|
|
|
- <el-form-item label="所属公司" prop="companyId">
|
|
|
- <el-select v-model="form.companyId" placeholder="请选择" style="width: 100%;" size="large">
|
|
|
- <el-option
|
|
|
- v-for="item in companyList"
|
|
|
- :key="item.id"
|
|
|
- :label="item.companyName"
|
|
|
- :value="item.id"
|
|
|
- />
|
|
|
- </el-select>
|
|
|
- </el-form-item>
|
|
|
- </el-col>
|
|
|
- </el-row>
|
|
|
-
|
|
|
- <el-row :gutter="20">
|
|
|
- <el-col :span="8">
|
|
|
- <el-form-item label="开始时间" prop="startTime">
|
|
|
- <el-date-picker
|
|
|
- v-model="form.startTime"
|
|
|
- type="date"
|
|
|
- placeholder="请选择"
|
|
|
- value-format="YYYY-MM-DD"
|
|
|
- style="width: 100%;"
|
|
|
- size="large"
|
|
|
- />
|
|
|
- </el-form-item>
|
|
|
- </el-col>
|
|
|
- <el-col :span="8">
|
|
|
- <el-form-item label="结束时间" prop="endTime">
|
|
|
- <el-date-picker
|
|
|
- v-model="form.endTime"
|
|
|
- type="date"
|
|
|
- placeholder="请选择"
|
|
|
- value-format="YYYY-MM-DD"
|
|
|
- style="width: 100%;"
|
|
|
- size="large"
|
|
|
- />
|
|
|
- </el-form-item>
|
|
|
- </el-col>
|
|
|
- </el-row>
|
|
|
-
|
|
|
- <el-row :gutter="20">
|
|
|
- <el-col :span="24">
|
|
|
- <el-form-item label="附件" prop="attachment">
|
|
|
- <FileUpload
|
|
|
- v-model="form.attachment"
|
|
|
- :limit="10"
|
|
|
- :file-size="50"
|
|
|
- :file-type="['doc', 'docx', 'xls', 'xlsx', 'ppt', 'pptx', 'txt', 'pdf']"
|
|
|
- />
|
|
|
- </el-form-item>
|
|
|
- </el-col>
|
|
|
- </el-row>
|
|
|
-
|
|
|
- <el-row :gutter="20">
|
|
|
- <el-col :span="24">
|
|
|
- <el-form-item label="备注" prop="remark">
|
|
|
- <el-input
|
|
|
- v-model="form.remark"
|
|
|
- type="textarea"
|
|
|
- :rows="4"
|
|
|
- placeholder="请输入内容"
|
|
|
- size="large"
|
|
|
- />
|
|
|
- </el-form-item>
|
|
|
- </el-col>
|
|
|
- </el-row>
|
|
|
-
|
|
|
- <!-- 商品列表 -->
|
|
|
- <div class="section-title">
|
|
|
- <el-button type="primary" @click="handleAddProduct">添加商品报价</el-button>
|
|
|
- </div>
|
|
|
|
|
|
- <el-table :data="productList" border style="width: 100%; margin-top: 20px;">
|
|
|
- <el-table-column prop="productCode" label="产品编号" align="center" width="120" />
|
|
|
- <el-table-column label="产品图片" align="center" width="100">
|
|
|
- <template #default="scope">
|
|
|
- <el-image
|
|
|
- v-if="scope.row.productImage"
|
|
|
- :src="scope.row.productImage"
|
|
|
- style="width: 60px; height: 60px;"
|
|
|
- fit="cover"
|
|
|
- />
|
|
|
- </template>
|
|
|
- </el-table-column>
|
|
|
- <el-table-column prop="productName" label="产品名称" align="center" show-overflow-tooltip />
|
|
|
- <el-table-column prop="productType" label="产品类型" align="center" width="120" />
|
|
|
- <el-table-column prop="brand" label="品牌" align="center" width="100" />
|
|
|
- <el-table-column prop="unit" label="单位" align="center" width="80" />
|
|
|
- <el-table-column label="市场价" align="center" width="100">
|
|
|
- <template #default="scope">
|
|
|
- <span>¥{{ scope.row.marketPrice || '0.00' }}</span>
|
|
|
- </template>
|
|
|
- </el-table-column>
|
|
|
- <el-table-column label="平台价" align="center" width="100">
|
|
|
- <template #default="scope">
|
|
|
- <span>¥{{ scope.row.platformPrice || '0.00' }}</span>
|
|
|
- </template>
|
|
|
- </el-table-column>
|
|
|
- <el-table-column label="供应价(元)" align="center" width="120">
|
|
|
- <template #default="scope">
|
|
|
- <el-input v-model="scope.row.supplyPrice" placeholder="请输入" />
|
|
|
- </template>
|
|
|
- </el-table-column>
|
|
|
- <el-table-column label="供应时效" align="center" width="120">
|
|
|
- <template #default="scope">
|
|
|
- <el-input v-model="scope.row.supplyCycle" placeholder="请输入" />
|
|
|
- </template>
|
|
|
- </el-table-column>
|
|
|
- <el-table-column label="上架状态" align="center" width="100">
|
|
|
- <template #default="scope">
|
|
|
- <span>{{ scope.row.upPrice }}</span>
|
|
|
- </template>
|
|
|
- </el-table-column>
|
|
|
- <el-table-column label="操作" align="center" width="100" fixed="right">
|
|
|
- <template #default="scope">
|
|
|
- <el-button link type="primary" @click="handleDeleteProduct(scope.$index)">删除</el-button>
|
|
|
- </template>
|
|
|
- </el-table-column>
|
|
|
- </el-table>
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
- <el-row style="margin-top: 20px;">
|
|
|
- <el-col :span="24" style="text-align: center;">
|
|
|
- <el-button type="primary" @click="handleSubmit">提交</el-button>
|
|
|
- </el-col>
|
|
|
- </el-row>
|
|
|
- </el-form>
|
|
|
+ <!-- 商品报价信息 -->
|
|
|
+ <el-card shadow="never" class="form-card">
|
|
|
+ <div class="section-title">
|
|
|
+ <el-button type="primary" @click="handleAddProduct">添加商品报价</el-button>
|
|
|
+ <el-button type="success" icon="Upload" @click="handleImport">导入</el-button>
|
|
|
+ <el-button icon="Download" @click="handleDownloadTemplate">下载模板</el-button>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <el-table :data="productList" border style="width: 100%; margin-top: 20px;">
|
|
|
+ <el-table-column prop="productNo" label="产品编号" align="center" width="120" />
|
|
|
+ <el-table-column label="产品图片" align="center" width="100">
|
|
|
+ <template #default="scope">
|
|
|
+ <el-image
|
|
|
+ v-if="scope.row.productImage"
|
|
|
+ :src="scope.row.productImage"
|
|
|
+ style="width: 60px; height: 60px;"
|
|
|
+ fit="cover"
|
|
|
+ />
|
|
|
+ </template>
|
|
|
+ </el-table-column>
|
|
|
+ <el-table-column prop="itemName" label="产品名称" align="center" show-overflow-tooltip />
|
|
|
+ <el-table-column label="产品分类" align="center" width="180" show-overflow-tooltip>
|
|
|
+ <template #default="scope">
|
|
|
+ <span>{{ scope.row.topCategoryName }}-{{ scope.row.mediumCategoryName }}-{{ scope.row.bottomCategoryName }}</span>
|
|
|
+ </template>
|
|
|
+ </el-table-column>
|
|
|
+ <el-table-column prop="brandName" label="品牌" align="center" width="100" />
|
|
|
+ <el-table-column prop="unitName" label="单位" align="center" width="80" />
|
|
|
+ <el-table-column label="市场价" align="center" width="100">
|
|
|
+ <template #default="scope">
|
|
|
+ <span>¥{{ scope.row.marketPrice || '0.00' }}</span>
|
|
|
+ </template>
|
|
|
+ </el-table-column>
|
|
|
+ <el-table-column label="官网价" align="center" width="100">
|
|
|
+ <template #default="scope">
|
|
|
+ <span>¥{{ scope.row.memberPrice || '0.00' }}</span>
|
|
|
+ </template>
|
|
|
+ </el-table-column>
|
|
|
+ <el-table-column label="供应价(元)" align="center" width="120">
|
|
|
+ <template #default="scope">
|
|
|
+ <span>¥{{ scope.row.supplyPrice || '0.00' }}</span>
|
|
|
+ </template>
|
|
|
+ </el-table-column>
|
|
|
+ <el-table-column label="操作" align="center" width="100" fixed="right">
|
|
|
+ <template #default="scope">
|
|
|
+ <el-button link type="primary" @click="handleDeleteProduct(scope.row, scope.$index)">删除</el-button>
|
|
|
+ </template>
|
|
|
+ </el-table-column>
|
|
|
+ </el-table>
|
|
|
+
|
|
|
+ <pagination
|
|
|
+ v-show="total > 0"
|
|
|
+ :total="total"
|
|
|
+ v-model:page="queryParams.pageNum"
|
|
|
+ v-model:limit="queryParams.pageSize"
|
|
|
+ @pagination="getProductData"
|
|
|
+ />
|
|
|
</el-card>
|
|
|
|
|
|
<!-- 添加商品对话框 -->
|
|
|
@@ -151,155 +66,188 @@
|
|
|
v-model:visible="productDialog.visible"
|
|
|
v-model:modelValue="productList"
|
|
|
/>
|
|
|
+
|
|
|
+ <!-- 导入对话框 -->
|
|
|
+ <el-dialog v-model="upload.open" title="合同产品导入" width="400px" append-to-body>
|
|
|
+ <el-upload
|
|
|
+ ref="uploadRef"
|
|
|
+ :limit="1"
|
|
|
+ accept=".xlsx, .xls"
|
|
|
+ :auto-upload="false"
|
|
|
+ :http-request="customUpload"
|
|
|
+ :on-change="handleFileChange"
|
|
|
+ :on-progress="handleFileUploadProgress"
|
|
|
+ :on-success="handleFileSuccess"
|
|
|
+ :on-error="handleFileError"
|
|
|
+ drag
|
|
|
+ >
|
|
|
+ <el-icon class="el-icon--upload">
|
|
|
+ <i-ep-upload-filled />
|
|
|
+ </el-icon>
|
|
|
+ <div class="el-upload__text">将文件拖到此处,或<em>点击上传</em></div>
|
|
|
+ <template #tip>
|
|
|
+ <div class="text-center el-upload__tip">
|
|
|
+ <span>仅允许导入 xls、xlsx 格式文件。</span>
|
|
|
+ <el-link type="primary" :underline="false" style="font-size: 12px; vertical-align: baseline" @click="handleDownloadTemplate">下载模板</el-link>
|
|
|
+ </div>
|
|
|
+ </template>
|
|
|
+ </el-upload>
|
|
|
+ <template #footer>
|
|
|
+ <div class="dialog-footer">
|
|
|
+ <el-button type="primary" :loading="upload.isUploading" @click="submitFileForm">确 定</el-button>
|
|
|
+ <el-button @click="upload.open = false">取 消</el-button>
|
|
|
+ </div>
|
|
|
+ </template>
|
|
|
+ </el-dialog>
|
|
|
</div>
|
|
|
</template>
|
|
|
|
|
|
<script setup lang="ts">
|
|
|
-import { ref, onMounted, reactive } from 'vue';
|
|
|
-import { useRoute, useRouter } from 'vue-router';
|
|
|
-import { ArrowLeft } from '@element-plus/icons-vue';
|
|
|
-import { getContractsupply, updateContractsupply } from '@/api/supplier/contractsupply';
|
|
|
-import { getCompanyList } from '@/api/customer/info';
|
|
|
-import { ElMessage } from 'element-plus';
|
|
|
-import FileUpload from '@/components/FileUpload/index.vue';
|
|
|
+import { ref, onMounted, reactive, getCurrentInstance } from 'vue';
|
|
|
+import { useRouter } from 'vue-router';
|
|
|
+import { getContractProductList, delContracproductBySupplier, importTemplate, importData } from '@/api/product/contracproduct';
|
|
|
+import { ElMessage, ElMessageBox } from 'element-plus';
|
|
|
+import type { UploadFile, UploadInstance, UploadRequestOptions } from 'element-plus';
|
|
|
import Product from './components/Product.vue';
|
|
|
import { useUserStore } from '@/store/modules/user';
|
|
|
|
|
|
-const route = useRoute();
|
|
|
+const { proxy } = getCurrentInstance() as any;
|
|
|
const router = useRouter();
|
|
|
const userStore = useUserStore();
|
|
|
|
|
|
-const formRef = ref();
|
|
|
const productList = ref<any[]>([]);
|
|
|
-const companyList = ref<any[]>([]);
|
|
|
+const total = ref(0);
|
|
|
+const queryParams = reactive({
|
|
|
+ pageNum: 1,
|
|
|
+ pageSize: 10
|
|
|
+});
|
|
|
|
|
|
// 商品对话框相关
|
|
|
const productDialog = reactive({
|
|
|
visible: false
|
|
|
});
|
|
|
|
|
|
-const form = ref({
|
|
|
- id: '',
|
|
|
- contractSupplyNo: '',
|
|
|
- companyId: '',
|
|
|
- supplierId: '',
|
|
|
- supplyNo: '',
|
|
|
- supplierName: '',
|
|
|
- startTime: '',
|
|
|
- endTime: '',
|
|
|
- attachment: '',
|
|
|
- remark: '',
|
|
|
- isSubmit: false
|
|
|
+// 导入相关
|
|
|
+const uploadRef = ref<UploadInstance>();
|
|
|
+const upload = reactive({
|
|
|
+ open: false,
|
|
|
+ isUploading: false
|
|
|
});
|
|
|
|
|
|
-const rules = {
|
|
|
- // 编辑页面所有字段都不是必填
|
|
|
-};
|
|
|
-
|
|
|
/** 返回上一页 */
|
|
|
const goBack = () => {
|
|
|
router.back();
|
|
|
};
|
|
|
|
|
|
-/** 获取公司列表 */
|
|
|
-const getCompanyData = async () => {
|
|
|
+/** 获取商品列表 */
|
|
|
+const getProductData = async () => {
|
|
|
try {
|
|
|
- const res = await getCompanyList({ pageNum: 1, pageSize: 1000 });
|
|
|
- companyList.value = res.rows || res.data || [];
|
|
|
+ const res = await getContractProductList({
|
|
|
+ supplierId: userStore.supplierId,
|
|
|
+ pageNum: queryParams.pageNum,
|
|
|
+ pageSize: queryParams.pageSize
|
|
|
+ } as any);
|
|
|
+ productList.value = res.rows || []
|
|
|
+ total.value = (res as any).total || 0;
|
|
|
} catch (e) {
|
|
|
- console.error('获取公司列表失败:', e);
|
|
|
+ console.error('获取商品列表失败:', e);
|
|
|
+ ElMessage.error('获取商品列表失败');
|
|
|
}
|
|
|
};
|
|
|
|
|
|
-/** 获取详情数据 */
|
|
|
-const getDetail = async () => {
|
|
|
- const id = route.params.id as string;
|
|
|
- if (id) {
|
|
|
- try {
|
|
|
- const res = await getContractsupply(id);
|
|
|
- const data: any = res.data;
|
|
|
+/** 添加商品 */
|
|
|
+const handleAddProduct = () => {
|
|
|
+ productDialog.visible = true;
|
|
|
+};
|
|
|
|
|
|
- // 回显基本信息
|
|
|
- form.value = {
|
|
|
- id: String(data.id ?? ''),
|
|
|
- contractSupplyNo: String(data.contractSupplyNo ?? ''),
|
|
|
- companyId: data.companyId ?? '',
|
|
|
- supplierId: (userStore.supplierId ?? data.supplierId) as any,
|
|
|
- supplyNo: data.supplyNo || '',
|
|
|
- supplierName: data.supplierName,
|
|
|
- startTime: data.startTime,
|
|
|
- endTime: data.endTime,
|
|
|
- attachment: data.attachment,
|
|
|
- remark: data.remark,
|
|
|
- isSubmit: data.isSubmit || false
|
|
|
- };
|
|
|
+/** 删除商品 */
|
|
|
+const handleDeleteProduct = async (row: any, index: number) => {
|
|
|
+ console.log('handleDeleteProduct', row, index);
|
|
|
+ try {
|
|
|
+ await proxy?.$modal.confirm('是否确认删除该商品报价数据项?');
|
|
|
+ await delContracproductBySupplier(row.id, userStore.supplierId as any);
|
|
|
+ proxy?.$modal.msgSuccess('删除成功');
|
|
|
+ await getProductData();
|
|
|
+ } catch (e) {
|
|
|
+ // 用户取消或请求失败时不提示
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+/** 打开导入弹窗 */
|
|
|
+const handleImport = () => {
|
|
|
+ uploadRef.value?.clearFiles();
|
|
|
+ upload.open = true;
|
|
|
+};
|
|
|
|
|
|
- // 回显商品列表(关键!需要字段映射)
|
|
|
- productList.value = (data.contractProduct || []).map((item: any) => ({
|
|
|
- productId: item.productId,
|
|
|
- productCode: item.productNo,
|
|
|
- productImage: item.productImage,
|
|
|
- productName: item.itemName,
|
|
|
- productType: item.categoryName,
|
|
|
- brand: item.brandName,
|
|
|
- unit: item.unitName,
|
|
|
- basePrice: item.purchasingPrice || 0,
|
|
|
- marketPrice: item.marketPrice || 0,
|
|
|
- platformPrice: item.memberPrice || 0,
|
|
|
- supplyPrice: item.offerPrice || '',
|
|
|
- supplyCycle: item.supplyCycle || '',
|
|
|
- upPrice: item.productStatus === 1 ? '上架' : '下架'
|
|
|
- }));
|
|
|
- } catch (e) {
|
|
|
- console.error('获取详情失败:', e);
|
|
|
- ElMessage.error('获取详情失败');
|
|
|
- }
|
|
|
+/** 下载导入模板 */
|
|
|
+const handleDownloadTemplate = async () => {
|
|
|
+ try {
|
|
|
+ const data: any = await importTemplate();
|
|
|
+ const blob = new Blob([data], {
|
|
|
+ type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
|
|
|
+ });
|
|
|
+ const link = document.createElement('a');
|
|
|
+ link.href = window.URL.createObjectURL(blob);
|
|
|
+ link.download = `contracproduct_template_${new Date().getTime()}.xlsx`;
|
|
|
+ document.body.appendChild(link);
|
|
|
+ link.click();
|
|
|
+ document.body.removeChild(link);
|
|
|
+ window.URL.revokeObjectURL(link.href);
|
|
|
+ } catch (e) {
|
|
|
+ console.error('下载模板失败:', e);
|
|
|
+ ElMessage.error('下载模板失败');
|
|
|
}
|
|
|
};
|
|
|
|
|
|
-/** 添加商品 */
|
|
|
-const handleAddProduct = () => {
|
|
|
- productDialog.visible = true;
|
|
|
+/** 文件选择变更 */
|
|
|
+const handleFileChange = () => {
|
|
|
+ // 占位:用于触发响应(element-plus 类型需要)
|
|
|
};
|
|
|
|
|
|
-/** 删除商品 */
|
|
|
-const handleDeleteProduct = (index: number) => {
|
|
|
- productList.value.splice(index, 1);
|
|
|
+/** 自定义上传:直接调用后端 importData 接口 */
|
|
|
+const customUpload = async (options: UploadRequestOptions) => {
|
|
|
+ upload.isUploading = true;
|
|
|
+ try {
|
|
|
+ const res: any = await importData(options.file as File);
|
|
|
+ options.onSuccess?.(res);
|
|
|
+ } catch (err: any) {
|
|
|
+ options.onError?.(err);
|
|
|
+ }
|
|
|
};
|
|
|
|
|
|
-/** 提交表单 */
|
|
|
-const handleSubmit = async () => {
|
|
|
- formRef.value?.validate(async (valid: boolean) => {
|
|
|
- if (valid) {
|
|
|
- try {
|
|
|
- // 组装提交数据,包含表单数据和商品列表
|
|
|
- const submitData = {
|
|
|
- ...form.value,
|
|
|
- contractProduct: productList.value.map(item => ({
|
|
|
- productId: item.productId,
|
|
|
- productNo: item.productCode,
|
|
|
- offerPrice: item.supplyPrice || '',
|
|
|
- supplyCycle: item.supplyCycle || ''
|
|
|
- }))
|
|
|
- };
|
|
|
+/** 文件上传中处理 */
|
|
|
+const handleFileUploadProgress = () => {
|
|
|
+ upload.isUploading = true;
|
|
|
+};
|
|
|
|
|
|
- console.log('提交的数据:', submitData);
|
|
|
- console.log('商品列表:', productList.value);
|
|
|
+/** 文件上传成功处理 */
|
|
|
+const handleFileSuccess = (response: any, file: UploadFile) => {
|
|
|
+ upload.open = false;
|
|
|
+ upload.isUploading = false;
|
|
|
+ uploadRef.value?.handleRemove(file);
|
|
|
+ const msg = response?.msg || '导入成功';
|
|
|
+ ElMessageBox.alert(
|
|
|
+ "<div style='overflow: auto;overflow-x: hidden;max-height: 70vh;padding: 10px 20px 0;'>" + msg + '</div>',
|
|
|
+ '导入结果',
|
|
|
+ { dangerouslyUseHTMLString: true }
|
|
|
+ );
|
|
|
+ queryParams.pageNum = 1;
|
|
|
+ getProductData();
|
|
|
+};
|
|
|
+
|
|
|
+/** 文件上传失败处理 */
|
|
|
+const handleFileError = () => {
|
|
|
+ upload.isUploading = false;
|
|
|
+ ElMessage.error('导入失败');
|
|
|
+};
|
|
|
|
|
|
- await updateContractsupply(submitData);
|
|
|
- ElMessage.success('保存成功');
|
|
|
- router.back();
|
|
|
- } catch (e) {
|
|
|
- console.error('保存失败:', e);
|
|
|
- ElMessage.error('保存失败');
|
|
|
- }
|
|
|
- }
|
|
|
- });
|
|
|
+/** 提交导入 */
|
|
|
+const submitFileForm = () => {
|
|
|
+ uploadRef.value?.submit();
|
|
|
};
|
|
|
|
|
|
onMounted(() => {
|
|
|
- getDetail();
|
|
|
- getCompanyData();
|
|
|
+ getProductData();
|
|
|
});
|
|
|
</script>
|
|
|
|
|
|
@@ -340,14 +288,6 @@ onMounted(() => {
|
|
|
padding: 24px;
|
|
|
}
|
|
|
|
|
|
-.large-form :deep(.el-form-item__label) {
|
|
|
- font-weight: 500;
|
|
|
-}
|
|
|
-
|
|
|
-.form-text {
|
|
|
- color: #303133;
|
|
|
-}
|
|
|
-
|
|
|
.section-title {
|
|
|
margin: 20px 0;
|
|
|
padding-bottom: 12px;
|