|
@@ -1,534 +1,383 @@
|
|
|
<template>
|
|
<template>
|
|
|
- <div class="order-manage-container">
|
|
|
|
|
- <div class="page-title"><i class="title-bar"></i><span>企业采购习惯</span></div>
|
|
|
|
|
- <!-- 搜索栏 -->
|
|
|
|
|
- <div class="search-bar">
|
|
|
|
|
- <el-input v-model="queryParams.keyword" placeholder="搜索订单号" style="width: 200px" clearable @keyup.enter="handleQuery">
|
|
|
|
|
- <template #prefix
|
|
|
|
|
- ><el-icon><Search /></el-icon
|
|
|
|
|
- ></template>
|
|
|
|
|
- </el-input>
|
|
|
|
|
- <el-date-picker
|
|
|
|
|
- v-model="queryParams.dateRange"
|
|
|
|
|
- type="daterange"
|
|
|
|
|
- range-separator="—"
|
|
|
|
|
- start-placeholder="开始日期"
|
|
|
|
|
- end-placeholder="结束日期"
|
|
|
|
|
- style="width: 240px"
|
|
|
|
|
- />
|
|
|
|
|
- <el-button type="primary" @click="handleQuery">搜索</el-button>
|
|
|
|
|
- <el-button @click="handleReset">重置</el-button>
|
|
|
|
|
|
|
+ <div class="purchase-habit-container">
|
|
|
|
|
+ <!-- 顶部返回 -->
|
|
|
|
|
+ <div class="page-header">
|
|
|
|
|
+ <el-button link @click="handleBack">
|
|
|
|
|
+ <el-icon><ArrowLeft /></el-icon>
|
|
|
|
|
+ <span>返回</span>
|
|
|
|
|
+ </el-button>
|
|
|
|
|
+ <span class="page-title">企业采购习惯</span>
|
|
|
</div>
|
|
</div>
|
|
|
- <!-- 筛选栏 -->
|
|
|
|
|
- <div class="filter-bar">
|
|
|
|
|
- <span class="filter-label">下单部门</span>
|
|
|
|
|
- <el-tree-select
|
|
|
|
|
- v-model="queryParams.department"
|
|
|
|
|
- style="width: 100px"
|
|
|
|
|
- :data="deptList"
|
|
|
|
|
- :props="{ value: 'deptId', label: 'deptName', children: 'children' }"
|
|
|
|
|
- value-key="deptId"
|
|
|
|
|
- placeholder="请选择"
|
|
|
|
|
- check-strictly
|
|
|
|
|
- :render-after-expand="false"
|
|
|
|
|
- clearable
|
|
|
|
|
- >
|
|
|
|
|
- </el-tree-select>
|
|
|
|
|
- <span class="filter-label">状态</span>
|
|
|
|
|
- <el-select v-model="queryParams.status" placeholder="请选择" style="width: 100px" clearable>
|
|
|
|
|
- <el-option v-for="dict in order_status" :key="dict.value" :label="dict.label" :value="dict.value" />
|
|
|
|
|
- </el-select>
|
|
|
|
|
- <span class="filter-label">支付方式</span>
|
|
|
|
|
- <el-select v-model="queryParams.payType" placeholder="请选择" style="width: 100px" clearable
|
|
|
|
|
- ><el-option v-for="dict in pay_method" :key="dict.value" :label="dict.label" :value="dict.value"
|
|
|
|
|
- /></el-select>
|
|
|
|
|
- </div>
|
|
|
|
|
- <!-- Tab切换 -->
|
|
|
|
|
- <div class="tab-bar">
|
|
|
|
|
- <div class="tab-left">
|
|
|
|
|
- <div v-for="tab in statusTabs" :key="tab.key" :class="['tab-item', { active: activeTab === tab.key }]" @click="activeTab = tab.key">
|
|
|
|
|
- <el-icon><component :is="tab.icon" /></el-icon><span>{{ tab.label }}</span>
|
|
|
|
|
- </div>
|
|
|
|
|
- </div>
|
|
|
|
|
- </div>
|
|
|
|
|
- <!-- 订单列表 -->
|
|
|
|
|
- <div class="order-list">
|
|
|
|
|
- <div v-for="order in orderList" :key="order.id" class="order-card">
|
|
|
|
|
- <div class="order-header">
|
|
|
|
|
- <span class="order-time">{{ order.orderTime }}</span>
|
|
|
|
|
- <span class="order-info">订单号:{{ order.orderNo }}</span>
|
|
|
|
|
- <span class="order-info">下单人:{{ order.orderPerson }}</span>
|
|
|
|
|
- <span class="order-info">部门:{{ order.department }}</span>
|
|
|
|
|
- <el-button type="primary" link class="expand-btn" @click="handleExpand(order)"
|
|
|
|
|
- >{{ order.expanded ? '收起' : '展开' }} <el-icon><ArrowDown /></el-icon
|
|
|
|
|
- ></el-button>
|
|
|
|
|
- </div>
|
|
|
|
|
- <div v-if="order.countdown" class="countdown-bar">订单锁定剩余时间:{{ order.countdown }}</div>
|
|
|
|
|
- <div class="product-list">
|
|
|
|
|
- <div v-for="(item, itemIndex) in order.expanded ? order.products : order.products.slice(0, 1)" :key="itemIndex" class="product-row">
|
|
|
|
|
- <div class="product-cell product-info-cell">
|
|
|
|
|
- <div class="product-image">
|
|
|
|
|
- <el-image :src="item.image" fit="contain"
|
|
|
|
|
- ><template #error
|
|
|
|
|
- ><div class="image-placeholder">
|
|
|
|
|
- <el-icon :size="30" color="#ccc"><Picture /></el-icon></div></template
|
|
|
|
|
- ></el-image>
|
|
|
|
|
- </div>
|
|
|
|
|
- <div class="product-detail">
|
|
|
|
|
- <div class="product-name">{{ item.name }}</div>
|
|
|
|
|
- <div class="product-spec">{{ item.spec1 }} {{ item.spec2 }}</div>
|
|
|
|
|
- <div class="product-price">¥{{ item.price }}</div>
|
|
|
|
|
- </div>
|
|
|
|
|
- <div class="product-quantity">x{{ item.quantity }}</div>
|
|
|
|
|
|
|
+
|
|
|
|
|
+ <div class="page-content">
|
|
|
|
|
+ <el-form ref="formRef" :model="form" label-position="top">
|
|
|
|
|
+ <!-- 采购金额 -->
|
|
|
|
|
+ <el-row :gutter="40">
|
|
|
|
|
+ <el-col :span="12">
|
|
|
|
|
+ <el-form-item label="月度采购金额">
|
|
|
|
|
+ <el-input v-model="form.monthlyAmount" placeholder="请输入">
|
|
|
|
|
+ <template #suffix>万</template>
|
|
|
|
|
+ </el-input>
|
|
|
|
|
+ </el-form-item>
|
|
|
|
|
+ </el-col>
|
|
|
|
|
+ <el-col :span="12">
|
|
|
|
|
+ <el-form-item label="年度采购金额">
|
|
|
|
|
+ <el-input v-model="form.yearlyAmount" placeholder="请输入">
|
|
|
|
|
+ <template #suffix>万</template>
|
|
|
|
|
+ </el-input>
|
|
|
|
|
+ </el-form-item>
|
|
|
|
|
+ </el-col>
|
|
|
|
|
+ </el-row>
|
|
|
|
|
+
|
|
|
|
|
+ <!-- 产品选型 -->
|
|
|
|
|
+ <el-form-item label="产品选型">
|
|
|
|
|
+ <div class="tag-group">
|
|
|
|
|
+ <div
|
|
|
|
|
+ v-for="item in productTypeOptions"
|
|
|
|
|
+ :key="item"
|
|
|
|
|
+ :class="['tag-item', { active: form.productTypes.includes(item) }]"
|
|
|
|
|
+ @click="toggleTag(form.productTypes, item)"
|
|
|
|
|
+ >
|
|
|
|
|
+ {{ item }}
|
|
|
</div>
|
|
</div>
|
|
|
- <div class="product-cell amount-cell" v-if="itemIndex === 0">
|
|
|
|
|
- <div class="amount-info">
|
|
|
|
|
- <span class="label">支付款</span><span class="value highlight">¥{{ order.payAmount }}</span>
|
|
|
|
|
- </div>
|
|
|
|
|
- <div class="amount-info">
|
|
|
|
|
- <span class="label">含运费:</span><span class="value">¥{{ order.freight }}</span>
|
|
|
|
|
- </div>
|
|
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </el-form-item>
|
|
|
|
|
+
|
|
|
|
|
+ <!-- 日常打印量 -->
|
|
|
|
|
+ <el-form-item label="日常打印量">
|
|
|
|
|
+ <div class="tag-group">
|
|
|
|
|
+ <div
|
|
|
|
|
+ v-for="item in printVolumeOptions"
|
|
|
|
|
+ :key="item"
|
|
|
|
|
+ :class="['tag-item', { active: form.printVolume === item }]"
|
|
|
|
|
+ @click="form.printVolume = item"
|
|
|
|
|
+ >
|
|
|
|
|
+ {{ item }}
|
|
|
</div>
|
|
</div>
|
|
|
- <div class="product-cell status-cell" v-if="itemIndex === 0">
|
|
|
|
|
- <span class="status-text" :style="{ color: getStatusColor(order.status) }">{{ order.statusText }}</span>
|
|
|
|
|
- <el-button type="primary" link size="small" @click="handleViewDetail(order)">查看订单轨迹</el-button>
|
|
|
|
|
- <template v-if="order.auditStatus"
|
|
|
|
|
- ><span :class="['audit-status', getAuditStatusClass(order.auditStatus)]">{{ order.auditStatus }}</span
|
|
|
|
|
- ><el-button type="primary" link size="small">查看审批流</el-button></template
|
|
|
|
|
- >
|
|
|
|
|
- <el-button v-if="order.fileCount" type="primary" link size="small">审核文件({{ order.fileCount }})</el-button>
|
|
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </el-form-item>
|
|
|
|
|
+
|
|
|
|
|
+ <!-- 购买原装耗材 & 专人进行技术服务 -->
|
|
|
|
|
+ <el-row :gutter="40">
|
|
|
|
|
+ <el-col :span="12">
|
|
|
|
|
+ <el-form-item label="购买原装耗材">
|
|
|
|
|
+ <el-radio-group v-model="form.buyOriginal">
|
|
|
|
|
+ <el-radio v-for="dict in sys_platform_yes_no" :key="dict.value" :value="dict.value">{{ dict.label }}</el-radio>
|
|
|
|
|
+ </el-radio-group>
|
|
|
|
|
+ </el-form-item>
|
|
|
|
|
+ </el-col>
|
|
|
|
|
+ <el-col :span="12">
|
|
|
|
|
+ <el-form-item label="专人进行技术服务">
|
|
|
|
|
+ <el-radio-group v-model="form.technologyService">
|
|
|
|
|
+ <el-radio v-for="dict in sys_platform_yes_no" :key="dict.value" :value="dict.value">{{ dict.label }}</el-radio>
|
|
|
|
|
+ </el-radio-group>
|
|
|
|
|
+ </el-form-item>
|
|
|
|
|
+ </el-col>
|
|
|
|
|
+ </el-row>
|
|
|
|
|
+
|
|
|
|
|
+ <!-- 主要办公采购类目 -->
|
|
|
|
|
+ <el-form-item label="主要办公采购类目">
|
|
|
|
|
+ <div class="tag-group">
|
|
|
|
|
+ <div
|
|
|
|
|
+ v-for="item in categoryOptions"
|
|
|
|
|
+ :key="item"
|
|
|
|
|
+ :class="['tag-item', { active: form.categories.includes(item) }]"
|
|
|
|
|
+ @click="toggleTag(form.categories, item)"
|
|
|
|
|
+ >
|
|
|
|
|
+ {{ item }}
|
|
|
</div>
|
|
</div>
|
|
|
</div>
|
|
</div>
|
|
|
- </div>
|
|
|
|
|
|
|
+ <el-input v-model="form.otherCategory" placeholder="其他采购类目" maxlength="50" show-word-limit class="other-input" />
|
|
|
|
|
+ </el-form-item>
|
|
|
|
|
+
|
|
|
|
|
+ <!-- 企业福利 -->
|
|
|
|
|
+ <el-form-item label="企业福利">
|
|
|
|
|
+ <div class="tag-group">
|
|
|
|
|
+ <div
|
|
|
|
|
+ v-for="item in welfareOptions"
|
|
|
|
|
+ :key="item"
|
|
|
|
|
+ :class="['tag-item', { active: form.welfares.includes(item) }]"
|
|
|
|
|
+ @click="toggleTag(form.welfares, item)"
|
|
|
|
|
+ >
|
|
|
|
|
+ {{ item }}
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ <el-input v-model="form.otherScene" placeholder="其他福利" maxlength="50" show-word-limit class="other-input" />
|
|
|
|
|
+ </el-form-item>
|
|
|
|
|
+
|
|
|
|
|
+ <!-- 产品定制需求 -->
|
|
|
|
|
+ <el-form-item label="产品定制需求">
|
|
|
|
|
+ <div class="tag-group">
|
|
|
|
|
+ <div
|
|
|
|
|
+ v-for="item in customOptions"
|
|
|
|
|
+ :key="item"
|
|
|
|
|
+ :class="['tag-item', { active: form.customs.includes(item) }]"
|
|
|
|
|
+ @click="toggleTag(form.customs, item)"
|
|
|
|
|
+ >
|
|
|
|
|
+ {{ item }}
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ <el-input v-model="form.otherCustomize" placeholder="其他需求" maxlength="50" show-word-limit class="other-input" />
|
|
|
|
|
+ </el-form-item>
|
|
|
|
|
+ </el-form>
|
|
|
|
|
+
|
|
|
|
|
+ <!-- 底部按钮 -->
|
|
|
|
|
+ <div class="form-footer">
|
|
|
|
|
+ <el-button type="danger" @click="handleSave">保存</el-button>
|
|
|
|
|
+ <el-button @click="handleBack">取消</el-button>
|
|
|
</div>
|
|
</div>
|
|
|
- <el-empty v-if="orderList.length === 0" description="暂无订单" />
|
|
|
|
|
</div>
|
|
</div>
|
|
|
- <!-- 分页 -->
|
|
|
|
|
- <TablePagination v-model:page="queryParams.pageNum" v-model:page-size="queryParams.pageSize" :total="total" @change="handleQuery" />
|
|
|
|
|
</div>
|
|
</div>
|
|
|
</template>
|
|
</template>
|
|
|
|
|
|
|
|
<script setup lang="ts">
|
|
<script setup lang="ts">
|
|
|
-import { ref, reactive, computed, onMounted, watch } from 'vue';
|
|
|
|
|
|
|
+import { reactive, getCurrentInstance, toRefs, onMounted, ComponentInternalInstance, computed } from 'vue';
|
|
|
import { useRouter } from 'vue-router';
|
|
import { useRouter } from 'vue-router';
|
|
|
-import { Search, ArrowDown, Document, Clock, Box, CircleCheck, CircleClose, Picture } from '@element-plus/icons-vue';
|
|
|
|
|
-import { TablePagination } from '@/components';
|
|
|
|
|
-import { getOrderList, getOrderProducts } from '@/api/pc/enterprise/order';
|
|
|
|
|
-import type { OrderMain } from '@/api/pc/enterprise/orderTypes';
|
|
|
|
|
|
|
+import { ArrowLeft } from '@element-plus/icons-vue';
|
|
|
import { ElMessage } from 'element-plus';
|
|
import { ElMessage } from 'element-plus';
|
|
|
-import { getDeptTree } from '@/api/pc/organization';
|
|
|
|
|
-import { DeptInfo } from '@/api/pc/organization/types';
|
|
|
|
|
|
|
+import { updatePurchaseHabit, getCustomerPurchaseHabitData } from '@/api/pc/enterprise/purchaseHabit';
|
|
|
|
|
+
|
|
|
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
|
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
|
|
-const { order_status, pay_method } = toRefs<any>(proxy?.useDict('order_status', 'pay_method'));
|
|
|
|
|
|
|
+const { welfare_item, sys_platform_yes_no, product_types_choosing, purchase_item, product_customization, daily_print_volume } = toRefs<any>(
|
|
|
|
|
+ proxy?.useDict('welfare_item', 'sys_platform_yes_no', 'product_types_choosing', 'purchase_item', 'product_customization', 'daily_print_volume')
|
|
|
|
|
+);
|
|
|
|
|
|
|
|
const router = useRouter();
|
|
const router = useRouter();
|
|
|
-const activeTab = ref('all');
|
|
|
|
|
-const loading = ref(false);
|
|
|
|
|
-
|
|
|
|
|
-const deptList = ref([]);
|
|
|
|
|
|
|
|
|
|
-const statusTabs = [
|
|
|
|
|
- { key: 'all', label: '全部订单', icon: Document },
|
|
|
|
|
- { key: 'preOrder', label: '预下单', icon: Clock },
|
|
|
|
|
- { key: 'shipping', label: '待收货', icon: Box },
|
|
|
|
|
- { key: 'completed', label: '已完成', icon: CircleCheck },
|
|
|
|
|
- { key: 'cancelled', label: '已取消', icon: CircleClose }
|
|
|
|
|
-];
|
|
|
|
|
|
|
+// 根据字典数据生成选项
|
|
|
|
|
+const productTypeOptions = computed(() => product_types_choosing.value?.map((item: any) => item.label) || []);
|
|
|
|
|
+const printVolumeOptions = computed(() => daily_print_volume.value?.map((item: any) => item.label) || []);
|
|
|
|
|
+const categoryOptions = computed(() => purchase_item.value?.map((item: any) => item.label) || []);
|
|
|
|
|
+const welfareOptions = computed(() => welfare_item.value?.map((item: any) => item.label) || []);
|
|
|
|
|
+const customOptions = computed(() => product_customization.value?.map((item: any) => item.label) || []);
|
|
|
|
|
|
|
|
-// 监听标签页切换,重置页码并重新获取数据
|
|
|
|
|
-watch(activeTab, (newTab) => {
|
|
|
|
|
- queryParams.pageNum = 1;
|
|
|
|
|
- // 根据标签页设置后端查询的状态参数
|
|
|
|
|
- if (newTab === 'all') {
|
|
|
|
|
- queryParams.status = '';
|
|
|
|
|
- } else {
|
|
|
|
|
- // 将前端标签页key映射回后端状态值
|
|
|
|
|
- const tabToStatusMap: Record<string, string> = {
|
|
|
|
|
- 'preOrder': '0', // 待支付
|
|
|
|
|
- 'shipping': '4', // 待发货,部分发货,发货完成
|
|
|
|
|
- 'completed': '5', // 已完成
|
|
|
|
|
- 'cancelled': '7' // 已关闭,已取消
|
|
|
|
|
- };
|
|
|
|
|
- queryParams.status = tabToStatusMap[newTab] || '';
|
|
|
|
|
- }
|
|
|
|
|
- fetchOrderList();
|
|
|
|
|
|
|
+const form = reactive({
|
|
|
|
|
+ id: undefined,
|
|
|
|
|
+ customerId: undefined,
|
|
|
|
|
+ customerNo: '',
|
|
|
|
|
+ permanentOfficer: '',
|
|
|
|
|
+ monthlyAmount: '',
|
|
|
|
|
+ yearlyAmount: '',
|
|
|
|
|
+ productTypes: [] as string[],
|
|
|
|
|
+ printVolume: '',
|
|
|
|
|
+ printAmount: '',
|
|
|
|
|
+ buyOriginal: '',
|
|
|
|
|
+ technologyService: '',
|
|
|
|
|
+ categories: [] as string[],
|
|
|
|
|
+ otherCategory: '',
|
|
|
|
|
+ welfares: [] as string[],
|
|
|
|
|
+ customs: [] as string[],
|
|
|
|
|
+ adaptScenes: [] as string[],
|
|
|
|
|
+ otherScene: '',
|
|
|
|
|
+ otherCustomize: '',
|
|
|
|
|
+ choiceModel: '',
|
|
|
|
|
+ remark: ''
|
|
|
});
|
|
});
|
|
|
|
|
|
|
|
-const queryParams = reactive({ keyword: '', dateRange: null, department: '', status: '', payType: '', pageNum: 1, pageSize: 5 });
|
|
|
|
|
-const total = ref(0);
|
|
|
|
|
-const allOrders = ref<any[]>([]);
|
|
|
|
|
-
|
|
|
|
|
-// 将后端状态映射为前端标签页key
|
|
|
|
|
-const mapBackendStatusToTabKey = (backendStatus: string) => {
|
|
|
|
|
- const statusMap: Record<string, string> = {
|
|
|
|
|
- '0': 'preOrder', // 待支付
|
|
|
|
|
- '1': 'preOrder', // 待确认
|
|
|
|
|
- '2': 'shipping', // 待发货
|
|
|
|
|
- '3': 'shipping', // 部分发货
|
|
|
|
|
- '4': 'shipping', // 发货完成
|
|
|
|
|
- '5': 'completed', // 已完成
|
|
|
|
|
- '6': 'cancelled', // 已关闭
|
|
|
|
|
- '7': 'cancelled' // 已取消
|
|
|
|
|
- };
|
|
|
|
|
- return statusMap[backendStatus] || backendStatus;
|
|
|
|
|
|
|
+const toggleTag = (arr: string[], item: string) => {
|
|
|
|
|
+ const index = arr.indexOf(item);
|
|
|
|
|
+ if (index > -1) arr.splice(index, 1);
|
|
|
|
|
+ else arr.push(item);
|
|
|
};
|
|
};
|
|
|
-
|
|
|
|
|
-// 根据订单状态获取状态文本
|
|
|
|
|
-const getStatusText = (status: string) => {
|
|
|
|
|
- const statusMap: Record<string, string> = {
|
|
|
|
|
- '0': '待支付',
|
|
|
|
|
- '1': '待确认',
|
|
|
|
|
- '2': '待发货',
|
|
|
|
|
- '3': '部分发货',
|
|
|
|
|
- '4': '发货完成',
|
|
|
|
|
- '5': '已完成',
|
|
|
|
|
- '6': '已关闭',
|
|
|
|
|
- '7': '已取消'
|
|
|
|
|
- };
|
|
|
|
|
- return statusMap[status] || status;
|
|
|
|
|
|
|
+const handleBack = () => {
|
|
|
|
|
+ router.push('/enterprise/companyInfo');
|
|
|
};
|
|
};
|
|
|
-
|
|
|
|
|
-// 加载部门树
|
|
|
|
|
-const loadDeptTree = async () => {
|
|
|
|
|
|
|
+const handleSave = async () => {
|
|
|
try {
|
|
try {
|
|
|
- const res = await getDeptTree();
|
|
|
|
|
- if (res.code === 200 && res.data) {
|
|
|
|
|
- deptList.value = res.data;
|
|
|
|
|
|
|
+ // 将表单数据映射为接口所需格式
|
|
|
|
|
+ const submitData = {
|
|
|
|
|
+ id: form.id,
|
|
|
|
|
+ customerId: form.customerId,
|
|
|
|
|
+ customerNo: form.customerNo,
|
|
|
|
|
+ monthPurchase: form.monthlyAmount ? parseFloat(form.monthlyAmount) : undefined,
|
|
|
|
|
+ yearPurchase: form.yearlyAmount ? parseFloat(form.yearlyAmount) : undefined,
|
|
|
|
|
+ permanentOfficer: form.permanentOfficer,
|
|
|
|
|
+ choiceModel: form.productTypes.length > 0 ? product_types_choosing.value?.find((i: any) => i.label === form.productTypes[0])?.value || '' : '',
|
|
|
|
|
+ printAmount: form.printVolume ? daily_print_volume.value?.find((i: any) => i.label === form.printVolume)?.value || '' : '',
|
|
|
|
|
+ buyOriginal: form.buyOriginal,
|
|
|
|
|
+ technologyService: form.technologyService,
|
|
|
|
|
+ purchaseCategory:
|
|
|
|
|
+ form.categories.length > 0
|
|
|
|
|
+ ? form.categories
|
|
|
|
|
+ .map((label) => {
|
|
|
|
|
+ const item = purchase_item.value?.find((i: any) => i.label === label);
|
|
|
|
|
+ return item ? item.value : '';
|
|
|
|
|
+ })
|
|
|
|
|
+ .filter(Boolean)
|
|
|
|
|
+ .join(',')
|
|
|
|
|
+ : undefined,
|
|
|
|
|
+ otherCategory: form.otherCategory || undefined,
|
|
|
|
|
+ adaptScene:
|
|
|
|
|
+ form.welfares.length > 0
|
|
|
|
|
+ ? form.welfares
|
|
|
|
|
+ .map((label) => {
|
|
|
|
|
+ const item = welfare_item.value?.find((i: any) => i.label === label);
|
|
|
|
|
+ return item ? item.value : '';
|
|
|
|
|
+ })
|
|
|
|
|
+ .filter(Boolean)
|
|
|
|
|
+ .join(',')
|
|
|
|
|
+ : undefined,
|
|
|
|
|
+ otherScene: form.otherScene || undefined,
|
|
|
|
|
+ customizeDemand:
|
|
|
|
|
+ form.customs.length > 0
|
|
|
|
|
+ ? form.customs
|
|
|
|
|
+ .map((label) => {
|
|
|
|
|
+ const item = product_customization.value?.find((i: any) => i.label === label);
|
|
|
|
|
+ return item ? item.value : '';
|
|
|
|
|
+ })
|
|
|
|
|
+ .filter(Boolean)
|
|
|
|
|
+ .join(',')
|
|
|
|
|
+ : undefined,
|
|
|
|
|
+ otherCustomize: form.otherCustomize || undefined,
|
|
|
|
|
+ remark: form.remark || undefined
|
|
|
|
|
+ };
|
|
|
|
|
|
|
|
- if (Array.isArray(res.data)) {
|
|
|
|
|
- const treeData = proxy?.handleTree<DeptInfo>(res.data, 'deptId', 'parentId');
|
|
|
|
|
- deptList.value = treeData || res.data;
|
|
|
|
|
- } else {
|
|
|
|
|
- deptList.value = [];
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ await updatePurchaseHabit(submitData);
|
|
|
|
|
+ ElMessage.success('保存成功');
|
|
|
|
|
+ handleBack();
|
|
|
} catch (error) {
|
|
} catch (error) {
|
|
|
- console.error('获取部门树失败:', error);
|
|
|
|
|
- ElMessage.error('获取部门树失败');
|
|
|
|
|
|
|
+ ElMessage.error('保存失败');
|
|
|
}
|
|
}
|
|
|
};
|
|
};
|
|
|
|
|
|
|
|
-// 获取订单列表
|
|
|
|
|
-const fetchOrderList = async () => {
|
|
|
|
|
- loading.value = true;
|
|
|
|
|
|
|
+const getPurchaseHabitData = async () => {
|
|
|
try {
|
|
try {
|
|
|
- const params: any = {
|
|
|
|
|
- pageNum: queryParams.pageNum,
|
|
|
|
|
- pageSize: queryParams.pageSize
|
|
|
|
|
- };
|
|
|
|
|
|
|
+ const res = await getCustomerPurchaseHabitData();
|
|
|
|
|
+ if (res.code === 200 && res.data) {
|
|
|
|
|
+ const data = res.data;
|
|
|
|
|
|
|
|
- // 添加筛选条件
|
|
|
|
|
- if (queryParams.keyword) params.orderNo = queryParams.keyword;
|
|
|
|
|
- if (queryParams.department) params.department = queryParams.department;
|
|
|
|
|
- if (queryParams.status) params.orderStatuses = queryParams.status; // 使用orderStatuses支持多状态查询
|
|
|
|
|
- if (queryParams.payType) params.payType = queryParams.payType;
|
|
|
|
|
- if (queryParams.dateRange && queryParams.dateRange.length === 2) {
|
|
|
|
|
- params.beginTime = queryParams.dateRange[0];
|
|
|
|
|
- params.endTime = queryParams.dateRange[1];
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ // 映射数据到表单
|
|
|
|
|
+ form.id = data.id;
|
|
|
|
|
+ form.customerId = data.customerId;
|
|
|
|
|
+ form.customerNo = data.customerNo || '';
|
|
|
|
|
+ form.permanentOfficer = data.permanentOfficer || '';
|
|
|
|
|
+ form.monthlyAmount = data.monthPurchase || '';
|
|
|
|
|
+ form.yearlyAmount = data.yearPurchase || '';
|
|
|
|
|
|
|
|
- const res = await getOrderList(params);
|
|
|
|
|
- if (res.code === 200) {
|
|
|
|
|
- // 将后端数据转换为前端需要的格式
|
|
|
|
|
- allOrders.value = (res.rows || []).map((order: OrderMain) => ({
|
|
|
|
|
- id: order.id,
|
|
|
|
|
- orderTime: order.createTime,
|
|
|
|
|
- orderNo: order.orderNo,
|
|
|
|
|
- orderPerson: order.customerName, // 需要关联用户信息
|
|
|
|
|
- department: order.createDeptName, // 需要关联部门信息
|
|
|
|
|
- payAmount: order.payableAmount || 0,
|
|
|
|
|
- freight: order.shippingFee || 0,
|
|
|
|
|
- status: mapBackendStatusToTabKey(order.orderStatus || ''),
|
|
|
|
|
- statusText: getStatusText(order.orderStatus || ''),
|
|
|
|
|
- countdown: '',
|
|
|
|
|
- auditStatus: order.checkStatus,
|
|
|
|
|
- fileCount: 0,
|
|
|
|
|
- expanded: false,
|
|
|
|
|
- products: [] // 商品信息需要单独加载
|
|
|
|
|
- }));
|
|
|
|
|
|
|
+ // 处理产品选型(单选)
|
|
|
|
|
+ form.productTypes = data.choiceModel ? [product_types_choosing.value?.find((i: any) => i.value === data.choiceModel)?.label || ''] : [];
|
|
|
|
|
|
|
|
- total.value = res.total || 0;
|
|
|
|
|
- }
|
|
|
|
|
- } catch (error) {
|
|
|
|
|
- console.error('获取订单列表失败:', error);
|
|
|
|
|
- } finally {
|
|
|
|
|
- loading.value = false;
|
|
|
|
|
- }
|
|
|
|
|
-};
|
|
|
|
|
|
|
+ // 处理日常打印量(单选)
|
|
|
|
|
+ form.printVolume = data.printAmount ? daily_print_volume.value?.find((i: any) => i.value === data.printAmount)?.label || '' : '';
|
|
|
|
|
|
|
|
-const orderList = computed(() => allOrders.value);
|
|
|
|
|
|
|
+ form.categories = data.purchaseCategory
|
|
|
|
|
+ ? data.purchaseCategory
|
|
|
|
|
+ .split(',')
|
|
|
|
|
+ .map((id: string) => {
|
|
|
|
|
+ const item = purchase_item.value?.find((i: any) => i.value === id);
|
|
|
|
|
+ return item ? item.label : '';
|
|
|
|
|
+ })
|
|
|
|
|
+ .filter(Boolean)
|
|
|
|
|
+ : [];
|
|
|
|
|
|
|
|
-const getStatusColor = (status: string) =>
|
|
|
|
|
- ({ completed: '#67c23a', preOrder: '#e6a23c', shipping: '#409eff', cancelled: '#909399' })[status] || '#909399';
|
|
|
|
|
-const getAuditStatusClass = (auditStatus: string) => (auditStatus === '审批通过' ? 'success' : auditStatus === '审批驳回' ? 'danger' : 'warning');
|
|
|
|
|
|
|
+ form.welfares = data.adaptScene
|
|
|
|
|
+ ? data.adaptScene
|
|
|
|
|
+ .split(',')
|
|
|
|
|
+ .map((id: string) => {
|
|
|
|
|
+ const item = welfare_item.value?.find((i: any) => i.value === id);
|
|
|
|
|
+ return item ? item.label : '';
|
|
|
|
|
+ })
|
|
|
|
|
+ .filter(Boolean)
|
|
|
|
|
+ : [];
|
|
|
|
|
|
|
|
-const handleExpand = async (order: any) => {
|
|
|
|
|
- const orderIndex = allOrders.value.findIndex((o) => o.id === order.id);
|
|
|
|
|
- if (orderIndex === -1) return;
|
|
|
|
|
|
|
+ form.customs = data.customizeDemand
|
|
|
|
|
+ ? data.customizeDemand
|
|
|
|
|
+ .split(',')
|
|
|
|
|
+ .map((id: string) => {
|
|
|
|
|
+ const item = product_customization.value?.find((i: any) => i.value === id);
|
|
|
|
|
+ return item ? item.label : '';
|
|
|
|
|
+ })
|
|
|
|
|
+ .filter(Boolean)
|
|
|
|
|
+ : [];
|
|
|
|
|
|
|
|
- const currentOrder = allOrders.value[orderIndex];
|
|
|
|
|
|
|
+ // 处理单选字段
|
|
|
|
|
+ form.printAmount = data.printAmount || '';
|
|
|
|
|
|
|
|
- if (!currentOrder.expanded && currentOrder.products.length === 0) {
|
|
|
|
|
- try {
|
|
|
|
|
- const res = await getOrderProducts([order.id]);
|
|
|
|
|
- if (res.code === 200 && res.rows) {
|
|
|
|
|
- const products = res.rows.map((p: any) => ({
|
|
|
|
|
- image: p.productImage || '',
|
|
|
|
|
- name: p.productName || '',
|
|
|
|
|
- spec1: p.productUnit || '',
|
|
|
|
|
- spec2: p.productNo || '',
|
|
|
|
|
- price: p.orderPrice || 0,
|
|
|
|
|
- quantity: p.orderQuantity || 0
|
|
|
|
|
- }));
|
|
|
|
|
|
|
+ form.buyOriginal = data.buyOriginal || '';
|
|
|
|
|
|
|
|
- // 替换整个数组以触发响应式更新
|
|
|
|
|
- allOrders.value = allOrders.value.map((o, i) => (i === orderIndex ? { ...o, expanded: true, products } : o));
|
|
|
|
|
- return;
|
|
|
|
|
- }
|
|
|
|
|
- } catch (error) {
|
|
|
|
|
- console.error('加载商品失败:', error);
|
|
|
|
|
- return;
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ form.technologyService = data.technologyService;
|
|
|
|
|
|
|
|
- // 替换整个数组以触发响应式更新
|
|
|
|
|
- allOrders.value = allOrders.value.map((o, i) => (i === orderIndex ? { ...o, expanded: !o.expanded } : o));
|
|
|
|
|
-};
|
|
|
|
|
|
|
+ form.choiceModel = data.choiceModel || '';
|
|
|
|
|
|
|
|
-const handleViewDetail = (order: any) => {
|
|
|
|
|
- router.push(`/order/orderManage/detail/${order.orderNo}`);
|
|
|
|
|
-};
|
|
|
|
|
-const handleQuery = () => {
|
|
|
|
|
- queryParams.pageNum = 1;
|
|
|
|
|
- fetchOrderList();
|
|
|
|
|
-};
|
|
|
|
|
-const handleReset = () => {
|
|
|
|
|
- queryParams.keyword = '';
|
|
|
|
|
- queryParams.dateRange = null;
|
|
|
|
|
- queryParams.department = '';
|
|
|
|
|
- queryParams.payType = '';
|
|
|
|
|
- queryParams.pageNum = 1;
|
|
|
|
|
- fetchOrderList();
|
|
|
|
|
|
|
+ // 其他字段
|
|
|
|
|
+ form.otherCategory = data.otherCategory || '';
|
|
|
|
|
+ form.otherCustomize = data.otherCustomize || '';
|
|
|
|
|
+ form.otherScene = data.otherScene || '';
|
|
|
|
|
+ form.otherCustomize = data.otherCustomize || '';
|
|
|
|
|
+ form.remark = data.remark || '';
|
|
|
|
|
+ }
|
|
|
|
|
+ } catch (error) {
|
|
|
|
|
+ console.error('获取采购习惯数据失败:', error);
|
|
|
|
|
+ ElMessage.error('获取数据失败');
|
|
|
|
|
+ }
|
|
|
};
|
|
};
|
|
|
|
|
|
|
|
-// 页面加载时获取订单列表
|
|
|
|
|
onMounted(() => {
|
|
onMounted(() => {
|
|
|
- loadDeptTree();
|
|
|
|
|
- fetchOrderList();
|
|
|
|
|
|
|
+ getPurchaseHabitData();
|
|
|
});
|
|
});
|
|
|
</script>
|
|
</script>
|
|
|
|
|
|
|
|
<style scoped lang="scss">
|
|
<style scoped lang="scss">
|
|
|
-.order-manage-container {
|
|
|
|
|
- padding: 20px;
|
|
|
|
|
- background: #fff;
|
|
|
|
|
|
|
+.purchase-habit-container {
|
|
|
|
|
+ background: #f5f5f5;
|
|
|
min-height: 100%;
|
|
min-height: 100%;
|
|
|
- display: flex;
|
|
|
|
|
- flex-direction: column;
|
|
|
|
|
- max-height: calc(100vh - 120px);
|
|
|
|
|
- flex: 1;
|
|
|
|
|
}
|
|
}
|
|
|
-.page-title {
|
|
|
|
|
- font-size: 16px;
|
|
|
|
|
- font-weight: bold;
|
|
|
|
|
- display: flex;
|
|
|
|
|
- align-items: center;
|
|
|
|
|
- gap: 8px;
|
|
|
|
|
- margin-bottom: 20px;
|
|
|
|
|
-}
|
|
|
|
|
-.title-bar {
|
|
|
|
|
- display: inline-block;
|
|
|
|
|
- width: 3px;
|
|
|
|
|
- height: 16px;
|
|
|
|
|
- background: #e60012;
|
|
|
|
|
- border-radius: 2px;
|
|
|
|
|
-}
|
|
|
|
|
-.search-bar {
|
|
|
|
|
- display: flex;
|
|
|
|
|
- align-items: center;
|
|
|
|
|
- gap: 15px;
|
|
|
|
|
- margin-bottom: 15px;
|
|
|
|
|
-}
|
|
|
|
|
-.filter-bar {
|
|
|
|
|
|
|
+.page-header {
|
|
|
|
|
+ background: #fff;
|
|
|
|
|
+ padding: 15px 20px;
|
|
|
display: flex;
|
|
display: flex;
|
|
|
align-items: center;
|
|
align-items: center;
|
|
|
gap: 10px;
|
|
gap: 10px;
|
|
|
- margin-bottom: 15px;
|
|
|
|
|
- .filter-label {
|
|
|
|
|
- font-size: 14px;
|
|
|
|
|
- color: #666;
|
|
|
|
|
|
|
+ border-bottom: 1px solid #eee;
|
|
|
|
|
+ .page-title {
|
|
|
|
|
+ font-size: 16px;
|
|
|
|
|
+ font-weight: bold;
|
|
|
|
|
+ color: #333;
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
-.tab-bar {
|
|
|
|
|
|
|
+.page-content {
|
|
|
|
|
+ padding: 20px;
|
|
|
|
|
+ background: #fff;
|
|
|
|
|
+ margin: 20px;
|
|
|
|
|
+ border-radius: 8px;
|
|
|
|
|
+}
|
|
|
|
|
+.tag-group {
|
|
|
display: flex;
|
|
display: flex;
|
|
|
- justify-content: space-between;
|
|
|
|
|
- align-items: center;
|
|
|
|
|
- border-bottom: 1px solid #eee;
|
|
|
|
|
- margin-bottom: 15px;
|
|
|
|
|
- .tab-left {
|
|
|
|
|
- display: flex;
|
|
|
|
|
- gap: 25px;
|
|
|
|
|
- }
|
|
|
|
|
- .tab-item {
|
|
|
|
|
- display: flex;
|
|
|
|
|
- align-items: center;
|
|
|
|
|
- gap: 5px;
|
|
|
|
|
- padding: 12px 0;
|
|
|
|
|
|
|
+ flex-wrap: wrap;
|
|
|
|
|
+ gap: 10px;
|
|
|
|
|
+ .tag-item {
|
|
|
|
|
+ padding: 8px 20px;
|
|
|
|
|
+ border: 1px solid #ddd;
|
|
|
|
|
+ border-radius: 4px;
|
|
|
cursor: pointer;
|
|
cursor: pointer;
|
|
|
- color: #666;
|
|
|
|
|
font-size: 14px;
|
|
font-size: 14px;
|
|
|
- border-bottom: 2px solid transparent;
|
|
|
|
|
- margin-bottom: -1px;
|
|
|
|
|
- &:hover,
|
|
|
|
|
- &.active {
|
|
|
|
|
- color: #333;
|
|
|
|
|
|
|
+ color: #666;
|
|
|
|
|
+ transition: all 0.2s;
|
|
|
|
|
+ &:hover {
|
|
|
|
|
+ border-color: #e60012;
|
|
|
|
|
+ color: #e60012;
|
|
|
}
|
|
}
|
|
|
&.active {
|
|
&.active {
|
|
|
- border-bottom-color: #e60012;
|
|
|
|
|
|
|
+ border-color: #e60012;
|
|
|
|
|
+ color: #e60012;
|
|
|
|
|
+ background: #fff5f5;
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
-.order-list {
|
|
|
|
|
- flex: 1;
|
|
|
|
|
- overflow-y: auto;
|
|
|
|
|
- margin-bottom: 15px;
|
|
|
|
|
- .order-card {
|
|
|
|
|
- border: 1px solid #eee;
|
|
|
|
|
- border-radius: 4px;
|
|
|
|
|
- margin-bottom: 15px;
|
|
|
|
|
- overflow: hidden;
|
|
|
|
|
- .order-header {
|
|
|
|
|
- display: flex;
|
|
|
|
|
- align-items: center;
|
|
|
|
|
- gap: 15px;
|
|
|
|
|
- padding: 12px 15px;
|
|
|
|
|
- background: #f9f9f9;
|
|
|
|
|
- border-bottom: 1px solid #eee;
|
|
|
|
|
- font-size: 13px;
|
|
|
|
|
- color: #666;
|
|
|
|
|
- .order-time {
|
|
|
|
|
- color: #333;
|
|
|
|
|
- }
|
|
|
|
|
- .expand-btn {
|
|
|
|
|
- margin-left: auto;
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
- .countdown-bar {
|
|
|
|
|
- background: #fff5e6;
|
|
|
|
|
- color: #e6a23c;
|
|
|
|
|
- padding: 8px 15px;
|
|
|
|
|
- font-size: 13px;
|
|
|
|
|
- border-bottom: 1px solid #eee;
|
|
|
|
|
- }
|
|
|
|
|
- .product-list {
|
|
|
|
|
- .product-row {
|
|
|
|
|
- display: flex;
|
|
|
|
|
- border-bottom: 1px solid #f5f5f5;
|
|
|
|
|
- &:last-child {
|
|
|
|
|
- border-bottom: none;
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
- .product-cell {
|
|
|
|
|
- padding: 15px;
|
|
|
|
|
- display: flex;
|
|
|
|
|
- flex-direction: column;
|
|
|
|
|
- justify-content: center;
|
|
|
|
|
- }
|
|
|
|
|
- .product-info-cell {
|
|
|
|
|
- flex: 1;
|
|
|
|
|
- flex-direction: row;
|
|
|
|
|
- align-items: center;
|
|
|
|
|
- gap: 15px;
|
|
|
|
|
- .product-image {
|
|
|
|
|
- width: 80px;
|
|
|
|
|
- height: 80px;
|
|
|
|
|
- background: #f5f5f5;
|
|
|
|
|
- border-radius: 4px;
|
|
|
|
|
- overflow: hidden;
|
|
|
|
|
- flex-shrink: 0;
|
|
|
|
|
- .el-image {
|
|
|
|
|
- width: 100%;
|
|
|
|
|
- height: 100%;
|
|
|
|
|
- }
|
|
|
|
|
- .image-placeholder {
|
|
|
|
|
- width: 100%;
|
|
|
|
|
- height: 100%;
|
|
|
|
|
- display: flex;
|
|
|
|
|
- align-items: center;
|
|
|
|
|
- justify-content: center;
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
- .product-detail {
|
|
|
|
|
- flex: 1;
|
|
|
|
|
- .product-name {
|
|
|
|
|
- font-size: 14px;
|
|
|
|
|
- color: #333;
|
|
|
|
|
- margin-bottom: 5px;
|
|
|
|
|
- line-height: 1.4;
|
|
|
|
|
- }
|
|
|
|
|
- .product-spec {
|
|
|
|
|
- font-size: 12px;
|
|
|
|
|
- color: #999;
|
|
|
|
|
- margin-bottom: 5px;
|
|
|
|
|
- }
|
|
|
|
|
- .product-price {
|
|
|
|
|
- font-size: 16px;
|
|
|
|
|
- font-weight: bold;
|
|
|
|
|
- color: #e60012;
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
- .product-quantity {
|
|
|
|
|
- font-size: 13px;
|
|
|
|
|
- color: #666;
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
- .amount-cell {
|
|
|
|
|
- width: 120px;
|
|
|
|
|
- border-left: 1px solid #f5f5f5;
|
|
|
|
|
- .amount-info {
|
|
|
|
|
- margin-bottom: 5px;
|
|
|
|
|
- .label {
|
|
|
|
|
- font-size: 12px;
|
|
|
|
|
- color: #999;
|
|
|
|
|
- }
|
|
|
|
|
- .value {
|
|
|
|
|
- font-size: 14px;
|
|
|
|
|
- color: #333;
|
|
|
|
|
- &.highlight {
|
|
|
|
|
- font-size: 16px;
|
|
|
|
|
- font-weight: bold;
|
|
|
|
|
- color: #e60012;
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
- .status-cell {
|
|
|
|
|
- width: 120px;
|
|
|
|
|
- border-left: 1px solid #f5f5f5;
|
|
|
|
|
- align-items: flex-start;
|
|
|
|
|
- gap: 5px;
|
|
|
|
|
- .status-text {
|
|
|
|
|
- font-size: 14px;
|
|
|
|
|
- font-weight: 500;
|
|
|
|
|
- }
|
|
|
|
|
- .audit-status {
|
|
|
|
|
- font-size: 12px;
|
|
|
|
|
- &.success {
|
|
|
|
|
- color: #e60012;
|
|
|
|
|
- }
|
|
|
|
|
- &.warning {
|
|
|
|
|
- color: #e6a23c;
|
|
|
|
|
- }
|
|
|
|
|
- &.danger {
|
|
|
|
|
- color: #e60012;
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
|
|
+.other-input {
|
|
|
|
|
+ margin-top: 10px;
|
|
|
|
|
+}
|
|
|
|
|
+.form-footer {
|
|
|
|
|
+ text-align: center;
|
|
|
|
|
+ padding-top: 30px;
|
|
|
|
|
+ border-top: 1px solid #eee;
|
|
|
|
|
+ margin-top: 20px;
|
|
|
|
|
+}
|
|
|
|
|
+:deep(.el-form-item__label) {
|
|
|
|
|
+ font-weight: 500;
|
|
|
|
|
+ color: #333;
|
|
|
}
|
|
}
|
|
|
-:deep(.table-pagination) {
|
|
|
|
|
- flex-shrink: 0;
|
|
|
|
|
- margin-top: 15px;
|
|
|
|
|
|
|
+:deep(.el-radio) {
|
|
|
|
|
+ margin-right: 30px;
|
|
|
}
|
|
}
|
|
|
</style>
|
|
</style>
|