feat: crm初步

This commit is contained in:
砂糖
2025-12-16 09:27:37 +08:00
parent 8f110f6a58
commit dbc9ac727a
15 changed files with 1328 additions and 45 deletions

View File

@@ -0,0 +1,44 @@
import request from '@/utils/request'
// 查询客户信息列表
export function listCustomer(query) {
return request({
url: '/crm/customer/list',
method: 'get',
params: query
})
}
// 查询客户信息详细
export function getCustomer(customerId) {
return request({
url: '/crm/customer/' + customerId,
method: 'get'
})
}
// 新增客户信息
export function addCustomer(data) {
return request({
url: '/crm/customer',
method: 'post',
data: data
})
}
// 修改客户信息
export function updateCustomer(data) {
return request({
url: '/crm/customer',
method: 'put',
data: data
})
}
// 删除客户信息
export function delCustomer(customerId) {
return request({
url: '/crm/customer/' + customerId,
method: 'delete'
})
}

View File

@@ -0,0 +1,44 @@
import request from '@/utils/request'
// 查询正式订单主列表
export function listOrder(query) {
return request({
url: '/crm/order/list',
method: 'get',
params: query
})
}
// 查询正式订单主详细
export function getOrder(orderId) {
return request({
url: '/crm/order/' + orderId,
method: 'get'
})
}
// 新增正式订单主
export function addOrder(data) {
return request({
url: '/crm/order',
method: 'post',
data: data
})
}
// 修改正式订单主
export function updateOrder(data) {
return request({
url: '/crm/order',
method: 'put',
data: data
})
}
// 删除正式订单主
export function delOrder(orderId) {
return request({
url: '/crm/order/' + orderId,
method: 'delete'
})
}

View File

@@ -0,0 +1,44 @@
import request from '@/utils/request'
// 查询正式订单明细列表
export function listOrderItem(query) {
return request({
url: '/crm/orderItem/list',
method: 'get',
params: query
})
}
// 查询正式订单明细详细
export function getOrderItem(itemId) {
return request({
url: '/crm/orderItem/' + itemId,
method: 'get'
})
}
// 新增正式订单明细
export function addOrderItem(data) {
return request({
url: '/crm/orderItem',
method: 'post',
data: data
})
}
// 修改正式订单明细
export function updateOrderItem(data) {
return request({
url: '/crm/orderItem',
method: 'put',
data: data
})
}
// 删除正式订单明细
export function delOrderItem(itemId) {
return request({
url: '/crm/orderItem/' + itemId,
method: 'delete'
})
}

View File

@@ -0,0 +1,44 @@
import request from '@/utils/request'
// 查询订单操作追溯列表
export function listOrderOperationTrace(query) {
return request({
url: '/crm/orderOperationTrace/list',
method: 'get',
params: query
})
}
// 查询订单操作追溯详细
export function getOrderOperationTrace(traceId) {
return request({
url: '/crm/orderOperationTrace/' + traceId,
method: 'get'
})
}
// 新增订单操作追溯
export function addOrderOperationTrace(data) {
return request({
url: '/crm/orderOperationTrace',
method: 'post',
data: data
})
}
// 修改订单操作追溯
export function updateOrderOperationTrace(data) {
return request({
url: '/crm/orderOperationTrace',
method: 'put',
data: data
})
}
// 删除订单操作追溯
export function delOrderOperationTrace(traceId) {
return request({
url: '/crm/orderOperationTrace/' + traceId,
method: 'delete'
})
}

View File

@@ -0,0 +1,44 @@
import request from '@/utils/request'
// 查询销售合同列表
export function listSalesContract(query) {
return request({
url: '/crm/salesContract/list',
method: 'get',
params: query
})
}
// 查询销售合同详细
export function getSalesContract(contractId) {
return request({
url: '/crm/salesContract/' + contractId,
method: 'get'
})
}
// 新增销售合同
export function addSalesContract(data) {
return request({
url: '/crm/salesContract',
method: 'post',
data: data
})
}
// 修改销售合同
export function updateSalesContract(data) {
return request({
url: '/crm/salesContract',
method: 'put',
data: data
})
}
// 删除销售合同
export function delSalesContract(contractId) {
return request({
url: '/crm/salesContract/' + contractId,
method: 'delete'
})
}

View File

@@ -0,0 +1,44 @@
import request from '@/utils/request'
// 查询销售异议管理列表
export function listSalesObjection(query) {
return request({
url: '/crm/salesObjection/list',
method: 'get',
params: query
})
}
// 查询销售异议管理详细
export function getSalesObjection(objectionId) {
return request({
url: '/crm/salesObjection/' + objectionId,
method: 'get'
})
}
// 新增销售异议管理
export function addSalesObjection(data) {
return request({
url: '/crm/salesObjection',
method: 'post',
data: data
})
}
// 修改销售异议管理
export function updateSalesObjection(data) {
return request({
url: '/crm/salesObjection',
method: 'put',
data: data
})
}
// 删除销售异议管理
export function delSalesObjection(objectionId) {
return request({
url: '/crm/salesObjection/' + objectionId,
method: 'delete'
})
}

View File

@@ -294,14 +294,14 @@ body {
.el-button--medium {
padding: 4px 8px !important;
font-size: 12px;
height: $--btn-height - 4px;
height: $--btn-height;
}
// 迷你按钮(超紧凑)
.el-button--mini {
padding: 4px 8px !important;
font-size: 12px;
height: $--btn-height - 4px;
height: $--btn-height;
&.is-circle {
padding: 4px !important;
}
@@ -310,7 +310,7 @@ body {
.el-button--small {
padding: 4px 8px !important;
font-size: 12px;
height: $--btn-height - 4px;
height: $--btn-height;
}

View File

@@ -19,7 +19,6 @@
<slot name="info1" :item="item" :isSelected="isSelected(item)">
<!-- Vue2 作用域插槽后备内容需用 template + slot-scope 包裹 -->
<template slot-scope="{ item, isSelected }">
<span class="info-label" v-if="info1Label">{{ info1Label }}</span>
<el-tooltip
:content="item[info1Field]"
placement="top"
@@ -36,7 +35,6 @@
<div class="klp-list-info-item" v-if="showInfoItem('info2', item)">
<slot name="info2" :item="item" :isSelected="isSelected(item)">
<template slot-scope="{ item, isSelected }">
<span class="info-label" v-if="info2Label">{{ info2Label }}</span>
<span class="info-value">{{ item[info2Field] }}</span>
</template>
</slot>
@@ -46,7 +44,6 @@
<div class="klp-list-info-item" v-if="showInfoItem('info3', item)">
<slot name="info3" :item="item" :isSelected="isSelected(item)">
<template slot-scope="{ item, isSelected }">
<span class="info-label" v-if="info3Label">{{ info3Label }}</span>
<span class="info-value">{{ item[info3Field] }}</span>
</template>
</slot>
@@ -59,7 +56,6 @@
<div class="klp-list-info-item" v-if="showInfoItem('info4', item)">
<slot name="info4" :item="item" :isSelected="isSelected(item)">
<template slot-scope="{ item, isSelected }">
<span class="info-label" v-if="info4Label">{{ info4Label }}</span>
<span class="info-value">{{ item[info4Field] }}</span>
</template>
</slot>
@@ -69,7 +65,6 @@
<div class="klp-list-info-item" v-if="showInfoItem('info5', item)">
<slot name="info5" :item="item" :isSelected="isSelected(item)">
<template slot-scope="{ item, isSelected }">
<span class="info-label" v-if="info5Label">{{ info5Label }}</span>
<span class="info-value">{{ item[info5Field] }}</span>
</template>
</slot>
@@ -79,7 +74,6 @@
<div class="klp-list-info-item" v-if="showInfoItem('info6', item)">
<slot name="info6" :item="item" :isSelected="isSelected(item)">
<template slot-scope="{ item, isSelected }">
<span class="info-label" v-if="info6Label">{{ info6Label }}</span>
<span class="info-value">{{ item[info6Field] }}</span>
</template>
</slot>
@@ -106,13 +100,8 @@
</template>
<script>
// Vue2 需显式引入 Element UI 组件
import { ElTooltip, ElEmpty } from 'element-ui';
export default {
name: "KLPList",
// 注册引入的 Element 组件
components: { ElTooltip, ElEmpty },
props: {
// ---------------------- 原有核心Props保留 ----------------------
/** 列表数据源(必传) */
@@ -140,66 +129,36 @@ export default {
required: false,
default: "title" // 默认对应原titleField
},
info1Label: {
type: String,
required: false,
default: "" // 兼容原titleLabel
},
// 信息位2副标题
info2Field: {
type: String,
required: false,
default: ""
},
info2Label: {
type: String,
required: false,
default: ""
},
// 信息位3状态
info3Field: {
type: String,
required: false,
default: ""
},
info3Label: {
type: String,
required: false,
default: ""
},
// 信息位4时间
info4Field: {
type: String,
required: false,
default: ""
},
info4Label: {
type: String,
required: false,
default: ""
},
// 信息位5数量/金额)
info5Field: {
type: String,
required: false,
default: ""
},
info5Label: {
type: String,
required: false,
default: ""
},
// 信息位6备注
info6Field: {
type: String,
required: false,
default: ""
},
info6Label: {
type: String,
required: false,
default: ""
},
// ---------------------- 新增样式控制Props ----------------------
/** 每行内部信息位的间距px */

View File

@@ -0,0 +1,259 @@
<template>
<div class="app-container">
<el-empty v-if="!orderId" description="未选中订单" />
<!-- <el-empty v-else-if="!orderItemList.length" description="暂无订单明细" /> -->
<div v-else>
<el-row :gutter="10" class="mb8">
<el-col :span="1.5">
<el-button type="primary" plain icon="el-icon-plus" size="mini" @click="handleAdd">新增</el-button>
</el-col>
</el-row>
<el-table v-loading="loading" :data="orderItemList">
<el-table-column label="产品类型" align="center" prop="productType" />
<el-table-column label="规格要求" align="center" prop="specRequire" />
<el-table-column label="产品数量" align="center" prop="productNum" />
<el-table-column label="特殊要求" align="center" prop="specialRequire" />
<el-table-column label="明细金额" align="center" prop="itemAmount" />
<el-table-column label="备注" align="center" prop="remark" />
<el-table-column label="操作" align="center" class-name="small-padding fixed-width">
<template slot-scope="scope">
<el-button size="mini" type="text" icon="el-icon-edit" @click="handleUpdate(scope.row)">修改</el-button>
<el-button size="mini" type="text" icon="el-icon-delete" @click="handleDelete(scope.row)">删除</el-button>
</template>
</el-table-column>
</el-table>
<pagination v-show="total > 0" :total="total" :page.sync="queryParams.pageNum" :limit.sync="queryParams.pageSize"
@pagination="getList" />
</div>
<!-- 添加或修改正式订单明细对话框 -->
<el-dialog :title="title" :visible.sync="open" width="500px" append-to-body>
<el-form ref="form" :model="form" :rules="rules" label-width="80px">
<el-form-item label="产品类型" prop="productType">
<el-input v-model="form.productType" placeholder="请输入产品类型" />
</el-form-item>
<el-form-item label="产品数量" prop="productNum">
<el-input v-model="form.productNum" placeholder="请输入产品数量" />
</el-form-item>
<el-form-item label="明细金额" prop="itemAmount">
<el-input size="mini" v-model="form.itemAmount" placeholder="请输入明细金额" />
</el-form-item>
<el-form-item label="规格要求" prop="specRequire">
<el-input v-model="form.specRequire" placeholder="请输入规格要求" />
</el-form-item>
<el-form-item label="特殊要求" prop="specialRequire">
<el-input v-model="form.specialRequire" type="textarea" placeholder="请输入内容" />
</el-form-item>
<el-form-item label="备注" prop="remark">
<el-input v-model="form.remark" placeholder="请输入备注" />
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button :loading="buttonLoading" type="primary" @click="submitForm"> </el-button>
<el-button @click="cancel"> </el-button>
</div>
</el-dialog>
</div>
</template>
<script>
import { listOrderItem, getOrderItem, delOrderItem, addOrderItem, updateOrderItem } from "@/api/crm/orderItem";
export default {
name: "OrderItem",
props: {
orderId: {
type: String,
required: true
}
},
data() {
return {
// 按钮loading
buttonLoading: false,
// 遮罩层
loading: true,
// 选中数组
ids: [],
// 非单个禁用
single: true,
// 非多个禁用
multiple: true,
// 显示搜索条件
showSearch: true,
// 总条数
total: 0,
// 正式订单明细表格数据
orderItemList: [],
// 弹出层标题
title: "",
// 是否显示弹出层
open: false,
// 查询参数
queryParams: {
pageNum: 1,
pageSize: 10,
orderId: this.orderId,
productType: undefined,
specRequire: undefined,
productNum: undefined,
specialRequire: undefined,
itemAmount: undefined,
},
// 表单参数
form: {},
// 表单校验
rules: {
productType: [
{ required: true, message: "请输入产品类型", trigger: "blur" }
],
productNum: [
{ required: true, message: "请输入产品数量", trigger: "blur" }
],
itemAmount: [
{ required: true, message: "请输入明细金额", trigger: "blur" },
// 必须是数字,最多两位小数,使用自定义的校验规则
{ validator: (rule, value, callback) => {
if (!/^\d+(\.\d{1,2})?$/.test(value)) {
callback(new Error("请输入最多两位小数的数字"));
} else {
callback();
}
}, trigger: "input" }
],
}
};
},
watch: {
orderId: {
handler(newVal, oldVal) {
if (newVal !== oldVal) {
this.queryParams.orderId = newVal;
this.getList();
}
},
immediate: true
}
},
methods: {
/** 查询正式订单明细列表 */
getList() {
this.loading = true;
listOrderItem(this.queryParams).then(response => {
this.orderItemList = response.rows;
this.total = response.total;
this.loading = false;
});
},
// 取消按钮
cancel() {
this.open = false;
this.reset();
},
// 表单重置
reset() {
this.form = {
itemId: undefined,
orderId: this.orderId,
productType: undefined,
specRequire: undefined,
productNum: undefined,
specialRequire: undefined,
itemAmount: undefined,
remark: undefined,
createBy: undefined,
createTime: undefined,
updateBy: undefined,
updateTime: undefined,
delFlag: undefined
};
this.resetForm("form");
},
/** 搜索按钮操作 */
handleQuery() {
this.queryParams.pageNum = 1;
this.getList();
},
/** 重置按钮操作 */
resetQuery() {
this.resetForm("queryForm");
this.handleQuery();
},
// 多选框选中数据
handleSelectionChange(selection) {
this.ids = selection.map(item => item.itemId)
this.single = selection.length !== 1
this.multiple = !selection.length
},
/** 新增按钮操作 */
handleAdd() {
this.reset();
this.open = true;
this.title = "添加正式订单明细";
},
/** 修改按钮操作 */
handleUpdate(row) {
this.loading = true;
this.reset();
const itemId = row.itemId || this.ids
getOrderItem(itemId).then(response => {
this.loading = false;
this.form = response.data;
this.open = true;
this.title = "修改正式订单明细";
});
},
/** 提交按钮 */
submitForm() {
this.$refs["form"].validate(valid => {
if (valid) {
this.buttonLoading = true;
if (this.form.itemId != null) {
updateOrderItem(this.form).then(response => {
this.$modal.msgSuccess("修改成功");
this.open = false;
this.getList();
}).finally(() => {
this.buttonLoading = false;
});
} else {
addOrderItem(this.form).then(response => {
this.$modal.msgSuccess("新增成功");
this.open = false;
this.getList();
}).finally(() => {
this.buttonLoading = false;
});
}
}
});
},
/** 删除按钮操作 */
handleDelete(row) {
const itemIds = row.itemId || this.ids;
this.$modal.confirm('是否确认删除正式订单明细编号为"' + itemIds + '"的数据项?').then(() => {
this.loading = true;
return delOrderItem(itemIds);
}).then(() => {
this.loading = false;
this.getList();
this.$modal.msgSuccess("删除成功");
}).catch(() => {
}).finally(() => {
this.loading = false;
});
},
/** 导出按钮操作 */
handleExport() {
this.download('crm/orderItem/export', {
...this.queryParams
}, `orderItem_${new Date().getTime()}.xlsx`)
}
}
};
</script>

View File

@@ -0,0 +1,284 @@
<template>
<div class="app-container">
<el-row :gutter="20">
<el-col :span="5" style="border-right: 1px solid #e4e7ed;">
<div style="font-weight: 900;">客户列表</div>
<div style="display: flex; align-items: center; gap: 5px; margin-top: 10px;">
<!-- 主搜索和添加 -->
<el-input style="flex: 1;" prefix-icon="el-icon-search" placeholder="输入客户编码搜索"
v-model="queryParams.customerCode"></el-input>
<el-button icon="el-icon-search" @click="toggleQuery"></el-button>
<el-button type="primary" icon="el-icon-plus" style="margin-left: 0;" @click="handleAdd"></el-button>
</div>
<div v-show="showQuery" style="display: flex; align-items: center; gap: 5px; margin-top: 10px;">
<!-- 查询区通过上方的查询按钮控制显示隐藏 -->
<!-- 客户行业和客户等级的下拉选 -->
<el-select style="width: 100px;" v-model="queryParams.industry" placeholder="客户行业" clearable>
<el-option v-for="item in dict.type.customer_industry" :key="item.value" :label="item.label"
:value="item.value" />
</el-select>
<el-select style="width: 100px;" v-model="queryParams.customerLevel" placeholder="客户等级" clearable>
<el-option v-for="item in dict.type.customer_level" :key="item.value" :label="item.label"
:value="item.value" />
</el-select>
</div>
<div>
<!-- 列表区域 -->
<KLPList :listData="customerList" listKey="customerId" :loading="customerLoading" info1Field="customerCode" info4Field="companyName" />
</div>
</el-col>
<el-col :span="19">
<el-tabs v-model="activeTab" type="border-card">
<el-tab-pane label="客户详情" name="detail">
<!-- 客户详情区域 -->
<el-descriptions :column="2" v-if="activeTab === 'detail'">
<el-descriptions-item label="客户编号">
{{ currentCustomer.customerNum }}
</el-descriptions-item>
<el-descriptions-item label="公司">
{{ currentCustomer.company }}
</el-descriptions-item>
<el-descriptions-item label="联系人">
{{ currentCustomer.contact }}
</el-descriptions-item>
<el-descriptions-item label="客户联系电话">{{ currentCustomer.phone }}</el-descriptions-item>
<el-descriptions-item label="客户联系邮箱">{{ currentCustomer.email }}</el-descriptions-item>
<el-descriptions-item label="客户行业">
<dict-tag :value="currentCustomer.industry" :options="dict.type.customer_industry"></dict-tag>
</el-descriptions-item>
<el-descriptions-item label="客户等级">
<dict-tag :value="currentCustomer.level" :options="dict.type.customer_level"></dict-tag>
</el-descriptions-item>
<el-descriptions-item label="客户地址" v-hasPermi="['crm:customer:address']">{{ currentCustomer.address
}}</el-descriptions-item>
</el-descriptions>
</el-tab-pane>
<el-tab-pane label="信息编辑" name="edit">
<!-- 客户联系人区域 -->
<el-form label-position="top" v-if="activeTab === 'edit'">
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="客户编号" prop="customerNum">
<el-input v-model="currentCustomer.customerNum" placeholder="请输入客户编号" @change="handleDetailChange"/>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="公司" prop="company">
<el-input v-model="currentCustomer.company" placeholder="请输入公司名称" @change="handleDetailChange"/>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="联系人" prop="contact">
<el-input v-model="currentCustomer.contact" placeholder="请输入联系人" @change="handleDetailChange"/>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="客户联系电话" prop="phone">
<el-input v-model="currentCustomer.phone" placeholder="请输入客户联系电话" @change="handleDetailChange"/>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="客户联系邮箱" prop="email">
<el-input v-model="currentCustomer.email" placeholder="请输入客户联系邮箱" @change="handleDetailChange"/>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="客户行业" prop="industry">
<el-select v-model="currentCustomer.industry" placeholder="请选择客户行业" clearable @change="handleDetailChange">
<el-option v-for="item in dict.type.customer_industry" :key="item.value" :label="item.label"
:value="item.value" />
</el-select>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="客户等级" prop="level">
<el-select v-model="currentCustomer.level" placeholder="请选择客户等级" clearable @change="handleDetailChange">
<el-option v-for="item in dict.type.customer_level" :key="item.value" :label="item.label"
:value="item.value" />
</el-select>
</el-form-item>
</el-col>
<el-col :span="12" v-hasPermi="['crm:customer:address']">
<el-form-item label="客户地址" prop="address">
<el-input v-model="currentCustomer.address" placeholder="请输入客户地址" @change="handleDetailChange"/>
</el-form-item>
</el-col>
</el-row>
</el-form>
</el-tab-pane>
<el-tab-pane label="历史订单" name="transaction">
<!-- 客户交易记录区域 -->
<div v-if="activeTab === 'transaction'">
<el-descriptions :column="2">
<el-descriptions-item label="客户总数">{{ currentCustomer.totalCount }}</el-descriptions-item>
<el-descriptions-item label="已成交订单数">{{ currentCustomer.dealCount }}</el-descriptions-item>
<el-descriptions-item label="待成交订单数">{{ currentCustomer.waitCount }}</el-descriptions-item>
<el-descriptions-item label="取消订单数">{{ currentCustomer.cancelCount }}</el-descriptions-item>
</el-descriptions>
<el-table></el-table>
</div>
</el-tab-pane>
</el-tabs>
</el-col>
</el-row>
<!-- 添加或修改客户信息对话框 -->
<el-dialog title="录入客户" :visible.sync="open" width="500px" append-to-body>
<el-form ref="form" :model="form" :rules="rules" label-width="80px">
<el-form-item label="客户编码" prop="customerCode">
<el-input v-model="form.customerCode" placeholder="请输入客户编码" />
</el-form-item>
<el-form-item label="公司名称" prop="companyName">
<el-input v-model="form.companyName" placeholder="请输入公司名称" />
</el-form-item>
<el-form-item label="联系人" prop="contactPerson">
<el-input v-model="form.contactPerson" placeholder="请输入联系人" />
</el-form-item>
<el-form-item label="联系方式" prop="contactWay">
<el-input v-model="form.contactWay" placeholder="请输入联系方式" />
</el-form-item>
<el-form-item label="所属行业" prop="industry">
<el-select v-model="form.industry" placeholder="请选择所属行业" clearable>
<el-option v-for="item in dict.type.customer_industry" :key="item.value" :label="item.label"
:value="item.value" />
</el-select>
</el-form-item>
<el-form-item label="客户等级" prop="customerLevel">
<el-select v-model="form.customerLevel" placeholder="请选择客户等级" clearable>
<el-option v-for="item in dict.type.customer_level" :key="item.value" :label="item.label"
:value="item.value" />
</el-select>
</el-form-item>
<el-form-item label="客户地址" prop="address">
<el-input v-model="form.address" placeholder="请输入客户地址" />
</el-form-item>
<el-form-item label="备注" prop="remark">
<el-input v-model="form.remark" placeholder="请输入备注" />
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button :loading="buttonLoading" type="primary" @click="submitForm"> </el-button>
<el-button @click="cancel"> </el-button>
</div>
</el-dialog>
</div>
</template>
<script>
import KLPList from '@/components/KLPUI/KLPList/index.vue'
import { listCustomer, addCustomer } from '@/api/crm/customer'
export default {
name: 'CustomerPage',
components: {
KLPList
},
dicts: ['customer_industry', 'customer_level'],
data() {
return {
customerList: [],
showQuery: false,
queryParams: {
industry: '',
customerLevel: '',
customerCode: '',
pageNum: 1,
pageSize: 10
},
total: 0,
activeTab: 'detail',
customerLoading: false,
currentCustomer: {},
open: false,
form: {},
buttonLoading: false,
rules: {
customerCode: [{ required: true, message: '请输入客户编码', trigger: 'blur' }],
companyName: [{ required: true, message: '请输入公司名称', trigger: 'blur' }],
contactPerson: [{ required: true, message: '请输入联系人', trigger: 'blur' }],
contactWay: [{ required: true, message: '请输入联系方式', trigger: 'blur' }],
industry: [{ required: true, message: '请选择所属行业', trigger: 'change' }],
customerLevel: [{ required: true, message: '请选择客户等级', trigger: 'change' }],
address: [{ required: true, message: '请输入客户地址', trigger: 'blur' }],
}
}
},
computed: {
currentCustomerId() {
return this.currentCustomer.customerId || undefined
}
},
mounted() {
this.getCustomerList();
},
methods: {
toggleQuery() {
this.showQuery = !this.showQuery
},
handleDetailChange() {
// 发送网络请求更新客户信息
},
getCustomerList() {
this.customerLoading = true;
listCustomer(this.queryParams).then(response => {
this.customerList = response.rows || [];
this.customerLoading = false;
});
},
// 表单重置
reset() {
this.form = {
customerId: undefined,
customerCode: undefined,
companyName: undefined,
contactPerson: undefined,
contactWay: undefined,
industry: undefined,
customerLevel: undefined,
address: undefined,
bankInfo: undefined,
remark: undefined,
createBy: undefined,
createTime: undefined,
updateBy: undefined,
updateTime: undefined,
delFlag: undefined
};
this.resetForm("form");
},
/** 新增按钮操作 */
handleAdd() {
this.reset();
this.open = true;
},
submitForm() {
this.$refs.form.validate(valid => {
if (valid) {
this.buttonLoading = true;
// 提交表单数据
addCustomer(this.form).then(response => {
this.$message({
message: '客户录入成功',
type: 'success'
});
this.buttonLoading = false;
this.open = false;
this.getCustomerList();
}).finally(() => {
this.buttonLoading = false;
});
}
});
},
/** 取消按钮操作 */
cancel() {
this.reset();
this.open = false;
},
},
}
</script>
<style></style>

View File

@@ -0,0 +1,26 @@
// 需要被记录的操作
const actions = {
// 创建预订单
createPreOrder: {
type: 'createPreOrder',
name: '创建预订单',
description: '创建一个预订单',
// 预订单的相关信息
async handler(payload, ) {
}
},
// 修改预订单
// 预订单明细变更
// 预订单取消
// 预订单审批为正式订单
// 直接创建正式订单
// 正式订单修改
// 正式订单明细修改
}

View File

@@ -0,0 +1,21 @@
// 订单状态
export const ORDER_STATUS = {
'待生产': 0,
'生产中': 1,
'部分发货': 2,
'已发货': 3,
'已签收': 4,
}
// 预订单状态
export const PRE_ORDER_STATUS = {
'待审核': 0,
'已审核': 1,
'已取消': 2,
}
// 订单类型
export const ORDER_TYPE = {
'预订单': 0,
'正式订单': 1,
}

View File

@@ -0,0 +1,104 @@
<template>
<div class="app-container">
<el-row :gutter="20">
<el-col :span="5" style="border-right: 1px solid #e4e7ed;">
<div style="font-weight: 900;">订单列表</div>
<div style="display: flex; align-items: center; gap: 5px; margin-top: 10px;">
<!-- 主搜索和添加 -->
<el-input style="flex: 1;" prefix-icon="el-icon-search" placeholder="输入订单编号搜索"
v-model="queryParams.orderNum"></el-input>
<el-button icon="el-icon-search" @click="toggleQuery"></el-button>
<el-button type="primary" icon="el-icon-plus" style="margin-left: 0;"></el-button>
</div>
<div v-show="showQuery"
style="display: flex; align-items: center; gap: 5px; margin-top: 10px; flex-wrap: wrap;">
<!-- 查询区通过上方的查询按钮控制显示隐藏 -->
<!-- 客户行业和客户等级的下拉选 -->
<el-select style="width: 100px;" v-model="queryParams.customerId" placeholder="客户" clearable>
<el-option v-for="item in dict.type.customer_industry" :key="item.value" :label="item.label"
:value="item.value" />
</el-select>
<el-select style="width: 100px;" v-model="queryParams.salesman" placeholder="销售员" clearable>
<el-option v-for="item in dict.type.customer_level" :key="item.value" :label="item.label"
:value="item.value" />
</el-select>
<el-select style="width: 100px;" v-model="queryParams.orderStatus" placeholder="订单状态" clearable>
<el-option v-for="item in dict.type.customer_level" :key="item.value" :label="item.label"
:value="item.value" />
</el-select>
<el-select style="width: 100px;" v-model="queryParams.financeStatus" placeholder="财务状态" clearable>
<el-option v-for="item in dict.type.customer_level" :key="item.value" :label="item.label"
:value="item.value" />
</el-select>
</div>
<div>
<!-- 列表区域 -->
<KLPList :listData="orderList" listKey="orderId" :loading="orderLoading" />
</div>
</el-col>
<el-col :span="19">
<el-tabs v-model="activeTab" type="border-card">
<el-tab-pane label="订单详情" name="detail">
<div class="order-detail" v-if="activeTab === 'detail'">
<!-- 订单详情内容 -->
</div>
</el-tab-pane>
<el-tab-pane label="财务状态" name="finance">
<div class="order-finance" v-if="activeTab === 'finance'">
<!-- 财务状态内容 -->
</div>
</el-tab-pane>
<el-tab-pane label="订单异议" name="dispute">
<div class="order-dispute" v-if="activeTab === 'dispute'">
<!-- 订单异议内容 -->
</div>
</el-tab-pane>
<el-tab-pane label="操作记录" name="record">
<div class="order-record" v-if="activeTab === 'record'">
<!-- 操作记录内容 -->
</div>
</el-tab-pane>
<el-tab-pane label="钢卷追溯" name="trace">
<div class="order-trace" v-if="activeTab === 'trace'">
<!-- 钢卷追溯内容 -->
</div>
</el-tab-pane>
</el-tabs>
</el-col>
</el-row>
</div>
</template>
<script>
import KLPList from '@/components/KLPUI/KLPList/index.vue'
export default {
name: 'OrderPage',
components: {
KLPList
},
dicts: ['customer_level', 'customer_industry'],
data() {
return {
showQuery: false,
queryParams: {
orderNum: '',
customerId: '',
salesman: '',
orderStatus: '',
financeStatus: ''
},
activeTab: 'detail',
currentOrder: {},
orderList: [],
orderLoading: false
}
},
methods: {
toggleQuery() {
this.showQuery = !this.showQuery
},
}
}
</script>

View File

@@ -0,0 +1,366 @@
<template>
<div class="app-container">
<el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="68px">
<el-form-item label="订单编号" prop="orderCode">
<el-input
v-model="queryParams.orderCode"
placeholder="请输入订单编号"
clearable
@keyup.enter.native="handleQuery"
/>
</el-form-item>
<el-form-item label="销售员" prop="salesman">
<el-input
v-model="queryParams.salesman"
placeholder="请输入销售员"
clearable
@keyup.enter.native="handleQuery"
/>
</el-form-item>
<el-form-item>
<el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
<el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
</el-form-item>
</el-form>
<el-row :gutter="10" class="mb8">
<el-col :span="1.5">
<el-button
type="primary"
plain
icon="el-icon-plus"
size="mini"
@click="handleAdd"
>新增</el-button>
</el-col>
<el-col :span="1.5">
<el-button
type="success"
plain
icon="el-icon-edit"
size="mini"
:disabled="single"
@click="handleUpdate"
>修改</el-button>
</el-col>
<el-col :span="1.5">
<el-button
type="danger"
plain
icon="el-icon-delete"
size="mini"
:disabled="multiple"
@click="handleDelete"
>删除</el-button>
</el-col>
<el-col :span="1.5">
<el-button
type="warning"
plain
icon="el-icon-download"
size="mini"
@click="handleExport"
>导出</el-button>
</el-col>
<right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
</el-row>
<el-table v-loading="loading" :data="orderList" height="400px" highlight-current-row @row-click="handleRowClick">
<el-table-column type="selection" width="55" align="center" />
<el-table-column label="订单编号" align="center" prop="orderCode" />
<el-table-column label="客户" align="center" prop="customerId" />
<el-table-column label="总金额" align="center" prop="orderAmount" />
<el-table-column label="销售员" align="center" prop="salesman" />
<el-table-column label="交货日期" align="center" prop="deliveryDate" width="180">
<template slot-scope="scope">
<span>{{ parseTime(scope.row.deliveryDate, '{y}-{m}-{d}') }}</span>
</template>
</el-table-column>
<el-table-column label="状态" align="center" prop="preOrderStatus">
<template slot-scope="scope">
<span v-if="scope.row.preOrderStatus === 0">待审核</span>
<span v-else-if="scope.row.preOrderStatus === 1">已审核</span>
<span v-else-if="scope.row.preOrderStatus === 2">已取消</span>
<span v-else>未知状态</span>
</template>
</el-table-column>
<el-table-column label="审核人" align="center" prop="auditUser" />
<el-table-column label="审核时间" align="center" prop="auditTime" width="180">
<template slot-scope="scope">
<span>{{ parseTime(scope.row.auditTime, '{y}-{m}-{d}') }}</span>
</template>
</el-table-column>
<el-table-column label="操作" align="center" class-name="small-padding fixed-width">
<template slot-scope="scope">
<el-button
size="mini"
type="text"
icon="el-icon-check"
@click="handleApprove(scope.row)"
>审批</el-button>
<el-button
size="mini"
type="text"
icon="el-icon-edit"
@click="handleUpdate(scope.row)"
>修改</el-button>
<el-button
size="mini"
type="text"
icon="el-icon-delete"
@click="handleDelete(scope.row)"
>删除</el-button>
</template>
</el-table-column>
</el-table>
<pagination
v-show="total>0"
:total="total"
:page.sync="queryParams.pageNum"
:limit.sync="queryParams.pageSize"
@pagination="getList"
/>
<!-- 正式订单明细列表组件 -->
<OrderDetailList ref="orderDetailList" :orderId="orderId" />
<!-- 添加或修改正式订单主对话框 -->
<el-dialog :title="title" :visible.sync="open" width="500px" append-to-body>
<el-form ref="form" :model="form" :rules="rules" label-width="80px">
<el-form-item label="订单编号" prop="orderCode">
<el-input v-model="form.orderCode" placeholder="请输入订单编号" />
</el-form-item>
<el-form-item label="客户" prop="customerId">
<el-input v-model="form.customerId" placeholder="请输入客户" />
</el-form-item>
<el-form-item label="订单总金额" prop="orderAmount">
<el-input v-model="form.orderAmount" placeholder="请输入订单总金额" />
</el-form-item>
<el-form-item label="销售员" prop="salesman">
<el-input v-model="form.salesman" placeholder="请输入销售员" />
</el-form-item>
<el-form-item label="交货日期" prop="deliveryDate">
<el-date-picker clearable
v-model="form.deliveryDate"
type="datetime"
value-format="yyyy-MM-dd HH:mm:ss"
placeholder="请选择交货日期">
</el-date-picker>
</el-form-item>
<el-form-item label="备注" prop="remark">
<el-input v-model="form.remark" placeholder="请输入备注" />
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button :loading="buttonLoading" type="primary" @click="submitForm"> </el-button>
<el-button @click="cancel"> </el-button>
</div>
</el-dialog>
</div>
</template>
<script>
import { listOrder, getOrder, delOrder, addOrder, updateOrder } from "@/api/crm/order";
import OrderDetailList from '@/views/crm/components/OrderDetail.vue'
import { ORDER_TYPE } from "../js/enum";
export default {
name: "Order",
components: {
OrderDetailList
},
data() {
return {
// 按钮loading
buttonLoading: false,
// 遮罩层
loading: true,
// 选中数组
ids: [],
// 非单个禁用
single: true,
// 非多个禁用
multiple: true,
// 显示搜索条件
showSearch: true,
// 总条数
total: 0,
// 正式订单主表格数据
orderList: [],
// 弹出层标题
title: "",
// 是否显示弹出层
open: false,
// 查询参数
queryParams: {
pageNum: 1,
pageSize: 10,
orderCode: undefined,
orderType: ORDER_TYPE['预订单'],
customerId: undefined,
orderAmount: undefined,
salesman: undefined,
deliveryDate: undefined,
preOrderStatus: undefined,
auditUser: undefined,
auditTime: undefined,
orderStatus: undefined,
financeStatus: undefined,
unpaidAmount: undefined,
},
// 表单参数
form: {},
// 表单校验
rules: {
}
};
},
created() {
this.getList();
},
methods: {
/** 查询正式订单主列表 */
getList() {
this.loading = true;
listOrder(this.queryParams).then(response => {
this.orderList = response.rows;
this.total = response.total;
this.loading = false;
});
},
// 取消按钮
cancel() {
this.open = false;
this.reset();
},
// 行点击事件
handleRowClick(row) {
this.orderId = row.orderId;
},
handleApprove(row) {
this.loading = true;
this.$confirm("确定审批订单吗?", "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning"
}).then(() => {
updateOrder({
...row,
orderType: ORDER_TYPE['正式订单'],
}).then(response => {
this.$modal.msgSuccess("审批成功");
this.getList();
}).finally(() => {
this.loading = false;
});
});
},
// 表单重置
reset() {
this.form = {
orderId: undefined,
orderCode: undefined,
orderType: ORDER_TYPE['预订单'],
customerId: undefined,
orderAmount: undefined,
salesman: undefined,
deliveryDate: undefined,
preOrderStatus: undefined,
auditUser: undefined,
auditTime: undefined,
orderStatus: undefined,
financeStatus: undefined,
unpaidAmount: undefined,
remark: undefined,
createBy: undefined,
createTime: undefined,
updateBy: undefined,
updateTime: undefined,
delFlag: undefined
};
this.resetForm("form");
},
/** 搜索按钮操作 */
handleQuery() {
this.queryParams.pageNum = 1;
this.getList();
},
/** 重置按钮操作 */
resetQuery() {
this.resetForm("queryForm");
this.handleQuery();
},
// 多选框选中数据
handleSelectionChange(selection) {
this.ids = selection.map(item => item.orderId)
this.single = selection.length!==1
this.multiple = !selection.length
},
/** 新增按钮操作 */
handleAdd() {
this.reset();
this.open = true;
this.title = "添加正式订单主";
},
/** 修改按钮操作 */
handleUpdate(row) {
this.loading = true;
this.reset();
const orderId = row.orderId || this.ids
getOrder(orderId).then(response => {
this.loading = false;
this.form = response.data;
this.open = true;
this.title = "修改正式订单主";
});
},
/** 提交按钮 */
submitForm() {
this.$refs["form"].validate(valid => {
if (valid) {
this.buttonLoading = true;
if (this.form.orderId != null) {
updateOrder(this.form).then(response => {
this.$modal.msgSuccess("修改成功");
this.open = false;
this.getList();
}).finally(() => {
this.buttonLoading = false;
});
} else {
addOrder(this.form).then(response => {
this.$modal.msgSuccess("新增成功");
this.open = false;
this.getList();
}).finally(() => {
this.buttonLoading = false;
});
}
}
});
},
/** 删除按钮操作 */
handleDelete(row) {
const orderIds = row.orderId || this.ids;
this.$modal.confirm('是否确认删除正式订单主编号为"' + orderIds + '"的数据项?').then(() => {
this.loading = true;
return delOrder(orderIds);
}).then(() => {
this.loading = false;
this.getList();
this.$modal.msgSuccess("删除成功");
}).catch(() => {
}).finally(() => {
this.loading = false;
});
},
/** 导出按钮操作 */
handleExport() {
this.download('crm/order/export', {
...this.queryParams
}, `order_${new Date().getTime()}.xlsx`)
}
}
};
</script>

View File

@@ -335,7 +335,7 @@ export default {
},
// 跳转详情页
goToDetail(scriptId) {
this.$router.push({ path: `/shop/rich/${scriptId}` });
this.$router.push({ path: `/crm/rich/${scriptId}` });
},
handleGenerateScript() {
this.generateScriptLoading = true;