zhuangyunsheng hace 3 días
padre
commit
79a40199de

+ 21 - 0
src/api/model/sales.js

@@ -18,6 +18,27 @@ export default {
             return await http.post(`${this.url}/update`, data);
         },
 
+        del: async function (data = {}) {
+            return await http.post(`${this.url}/remove`, data);
+        }
+    },
+
+    order: {
+        name: "销售订单",
+        url: `${config.API_URL}/mes/saleOrder`,
+        
+        get: async function (data = {}) {
+            return await http.post(`${this.url}/getPage`, data);
+        },
+
+        add: async function (data = {}) {
+            return await http.post(`${this.url}/save`, data);
+        },
+
+        edit: async function (data = {}) {
+            return await http.post(`${this.url}/update`, data);
+        },
+
         del: async function (data = {}) {
             return await http.post(`${this.url}/remove`, data);
         }

+ 3 - 3
src/components/scFormTable/detail.vue

@@ -13,6 +13,7 @@
 import XEUtils from "xe-utils";
 import processTable from "@/views/workmanship/process/index";
 import materialTable from "@/views/basic/material/index";
+import customerTable from "@/views/basic/customer/index";
 
 const props = defineProps({
     tableKey: { type: String, default: "" },
@@ -25,13 +26,14 @@ const visible = ref(false);
 const compDic = reactive({
     stage: { title: "工序选择", compName: processTable },
     material: { title: "产品选择", compName: materialTable },
+    customer: { title: "客户选择", compName: customerTable },
 });
 
 const tableRef = ref();
 const tableOptions = reactive({
     checkedRows: [],
     maxHeight: 1048,
-    toolbarConfig: { enabled: true, print: false, zoom: false },
+    toolbarConfig: { enabled: true, print: false, zoom: false, custom: false },
     ...props.options
 });
 
@@ -42,8 +44,6 @@ const setData = data => {
 
 const submit = () => {
     const selectedRows = tableRef.value?.getSelectRows() || [];
-    if (!props.multiple && selectedRows.length > 1) return ElMessage.warning("只能选择一条数据!");
-    
     visible.value = false;
     $emit("success", selectedRows);
 }

+ 1 - 0
src/components/scTable/index.vue

@@ -183,6 +183,7 @@ const gridOptions = reactive({
         ...props.editConfig
     },
     pagerConfig: {
+        enabled: true,
         pageSizes: config.pageSizes,
         layouts: config.layouts,
         currentPage: 1,

+ 0 - 123
src/components/scTableSelect/index.vue

@@ -1,123 +0,0 @@
-<!--
- * @Descripttion: form-input-table
- * @version: 1.1
- * @Date: 2025年12月02日10:00:06
- * ******未完成******
--->
-
-<template>
-    <div class="sc-table-select">
-        <vxe-table-select v-model="defaultValue" size="medium" :columns="columns" :options="tableData" :grid-config="gridConfig" transfer :placeholder="placeholder" @change="change">
-            <template #prefix><sc-iconify icon="mingcute:more-3-line"></sc-iconify></template>
-            
-            <template #queryAction>
-                <el-button type="primary" auto-insert-space @click="searchData">查询</el-button>
-                <el-button auto-insert-space @click="resetData">重置</el-button>
-            </template>
-        </vxe-table-select>
-    </div>
-</template>
-
-<script setup>
-import XEUtils from "xe-utils";
-import config from "@/config/table";
-import configSelect from "@/config/tableSelect";
-
-const $emit = defineEmits(["update:modelValue"]);
-const props = defineProps({
-    modelValue: { type: Object, default: () => {} },
-    apiObj: { type: Object, default: () => {} },
-    apiKey: { type: String, default: () => "all" },
-    optionsProps: { type: Object, default: () => configSelect.props },
-    placeholder: { type: String, default: "请选择" },
-    formConfig: { type: Object, default: () => {} },
-    paramsColums: { type: Array, default: () => [] },
-    columns: { type: Array, default: () => [] },
-    pagerConfig: { type: Object, default: () => {} },
-    options: { type: Object, default: () => {} }
-});
-
-const defaultValue = ref(XEUtils.get(props.modelValue, props.optionsProps.value, null));
-
-const tableData = ref([]);
-
-const gridConfig = reactive({
-    border: "full",
-    size: "mini",
-    showOverflow: true,
-    keepSource: true,
-    formConfig: {
-        enabled: true,
-        className: "vxe-table-query",
-        titleAlign: "right",
-        collapseStatus: true,
-        span: 12,
-        items: [
-            ...XEUtils.map(XEUtils.orderBy(XEUtils.get(props, "formConfig.items", []), "orderBy"), (formItem, formIndex) => {
-                return {
-                    ...formItem,
-                    className: ({ $grid, item, data }) => {
-                        const showItems = XEUtils.filter(XEUtils.orderBy(XEUtils.get(props, "formConfig.items", []), "orderBy"), f_item => (XEUtils.isUndefined(f_item.visible) || f_item.visible) && (XEUtils.isUndefined(f_item.visibleMethod) || f_item.visibleMethod({ data })));
-                        const index = XEUtils.findIndexOf(showItems, f_item => f_item.field == item.field);
-                        item.folding = index > 2;
-                        XEUtils.set(formItem, "folding", index > 2);
-                        return "";
-                    }
-                }
-            })
-        ],
-        ...XEUtils.omit(XEUtils.get(props, "formConfig", {}), "items")
-    },
-    rowConfig: {
-        keyField: props.optionsProps.value,
-        useKey: true,
-        isHover: true
-    },
-    columnConfig: {
-        useKey: true,
-        resizable: true // 列宽拖动功能
-    },
-    headerCellConfig: {
-        height: 36
-    },
-    cellConfig: {
-        height: 36
-    },
-    tooltipConfig: {
-        enterable: true
-    },
-    pagerConfig: {
-        pageSizes: config.pageSizes,
-        layouts: config.layouts,
-        currentPage: 1,
-        pageSize: config.pageSize,
-        total: 0
-    },
-})
-
-// 获取数据
-const getData = () => {
-    return new Promise((resolve, reject) => {
-        if (!props.apiObj) tableData.value = [];
-        
-        const reqData = config.queryData(gridConfig, props.paramsColums);
-        props.apiObj[props.apiKey](reqData).then(res => {
-            const response = config.parseData(res);
-            tableData.value = XEUtils.map(response.data || [], item => ({ ...item, label: item.name,value: item.id }));
-        }).catch(error => {
-            tableData.value = [];
-        });
-    });
-}
-getData();
-
-const change = ({ row }) => $emit("update:modelValue", row);
-</script>
-
-<style scoped>
-.sc-table-select, .sc-table-select .vxe-table-select {width: 100%;}
-.sc-table-select :deep(.vxe-input) {flex-direction: row-reverse;}
-.sc-table-select :deep(.vxe-input) .vxe-input--suffix {display: none;}
-.sc-table-select :deep(.vxe-input) .vxe-input--prefix {border-radius: 0 var(--vxe-ui-base-border-radius) var(--vxe-ui-base-border-radius) 0;}
-.sc-table-select .el-input__inner::placeholder {color: var(--vxe-ui-input-placeholder-color);}
-</style>

+ 2 - 2
src/config/table.js

@@ -7,8 +7,8 @@ export default {
 	layouts: ["PrevJump", "PrevPage", "Jump", "PageCount", "NextPage", "NextJump", "Sizes", "Total"],	        // 表格分页布局
     exportExcludeFields: ["checkbox", "radio"],
     
-    queryData: function ({ formConfig: { data }, pagerConfig: { currentPage, pageSize } }, paramsColumns) {
-        const query = { current: currentPage, size: pageSize }
+    queryData: function ({ formConfig: { data }, pagerConfig: { enabled, currentPage, pageSize } }, paramsColumns) {
+        const query = enabled && { current: currentPage, size: pageSize } || {}
         XEUtils.arrayEach(paramsColumns, item => {
             if (item.defaultValue) XEUtils.set(query, item.column, item.defaultValue)
             if (!valueIsNull(data, item.field || item.column)) XEUtils.set(query, item.column, XEUtils.get(data, item.field || item.column))

+ 1 - 1
src/layout/index.vue

@@ -158,7 +158,6 @@ export default {
         },
 
         currentMenu: {
-            immediate: true,
             handler(val) {
                 this.tabsName = XEUtils.get(val, "path", "")
             }
@@ -187,6 +186,7 @@ export default {
     },
 
     created() {
+        this.tabsName = XEUtils.get(this.currentMenu, "path", "")
         this.onLayoutResize();
         window.addEventListener("resize", this.onLayoutResize);
     },

+ 11 - 3
src/utils/basicDic.js

@@ -129,17 +129,25 @@ export const customerDic = {
     }
 }
 
-export const planDic = {
-    type: {
+export const salesDic = {
+    planType: {
         year: "年度",
         quarter: "季度",
         month: "月度"
     },
 
-    status: {
+    planStatus: {
         pending: "未开始",
         executing: "进行中",
         finished: "已结束"
+    },
+    
+    orderStatus: {
+        pending: "未开始",
+        processing: "备货中",
+        partially: "部分发货",
+        shipped: "已发货",
+        complete: "已完成"
     }
 }
 

+ 17 - 5
src/views/basic/customer/index.vue

@@ -1,8 +1,8 @@
 <template>
 	<el-container class="is-vertical">
-        <sc-page-header @add="table_add"></sc-page-header>
+        <sc-page-header v-if="!hidePageHeader" @add="table_add"></sc-page-header>
 
-        <scTable ref="xGridTable" :apiObj="$API.basic.customer" :formConfig="formConfig" :paramsColums="paramsColums" :toolbarConfig="toolbarConfig" :columns="columns">
+        <scTable ref="xGridTable" :apiObj="$API.basic.customer" :formConfig="formConfig" :paramsColums="paramsColums" :toolbarConfig="toolbarConfig" :columns="columns" v-bind="options">
             <template #action="{ row }">
                 <el-button type="primary" link @click="table_edit(row)">
                     <template #icon><sc-iconify icon="ant-design:edit-outlined"></sc-iconify></template>修改
@@ -32,6 +32,13 @@ import { statusDic, customerDic, objectToArray } from "@/utils/basicDic";
 import { mapFormItemInput, mapFormItemSelect } from "@/components/scTable/helper";
 import customerDetail from "./detail";
 
+const props = defineProps({
+    options: { type: Object, default: () => {} },
+    hidePageHeader: { type: Boolean, default: false },
+    hideHandler: { type: Boolean, default: false },
+    hideCheckbox: { type: Boolean, default: false }
+});
+
 const toolbarConfig = reactive({
     enabled: true,
     export: true
@@ -64,10 +71,11 @@ const paramsColums = reactive([
 ]);
 
 const columns = reactive([
-    { type: "seq", fixed: "left", width: 60 },
+    { visible: props.hideHandler, type: props.hideCheckbox && "radio" || "checkbox", fixed: "left", width: 40 },
+    { visible: !props.hideHandler, type: "seq", fixed: "left", width: 60 },
     { type: "html", field: "name", title: "客户名称", fixed: "left", minWidth: 150, sortable: true },
     { type: "html", field: "code", title: "客户编号", fixed: "left", minWidth: 150, sortable: true },
-    { field: "status", title: "客户状态", minWidth: 100, editRender: { name: "$cell-tag", options: statusDic } },
+    { visible: !props.hideHandler, field: "status", title: "客户状态", minWidth: 100, editRender: { name: "$cell-tag", options: statusDic } },
     { type: "html", field: "type", title: "客户分类", minWidth: 120, sortable: true, formatter: ({ cellValue }) => XEUtils.get(customerDic.type, cellValue, cellValue) },
     { visible: false, type: "html", field: "valueLevel", title: "客户层级", minWidth: 120, sortable: true, formatter: ({ cellValue }) => XEUtils.get(customerDic.tier, cellValue, cellValue) },
     { visible: false, type: "html", field: "creditLevel", title: "信用等级", minWidth: 120, sortable: true, formatter: ({ cellValue }) => XEUtils.get(customerDic.rating, cellValue, cellValue) },
@@ -76,7 +84,7 @@ const columns = reactive([
     { visible: false, type: "html", field: "email", title: "邮箱", minWidth: 120, sortable: true },
     { type: "html", field: "createTime", title: "创建日期", minWidth: 120, sortable: true, formatter: ({ cellValue }) => TOOL.dateFormat(cellValue, "YYYY-MM-DD") || cellValue },
     { visible: false, type: "html", field: "address", title: "客户地址", minWidth: 300, sortable: true },
-    { title: "操作", fixed: "right", width: 220, slots: { default: "action" } }
+    { visible: !props.hideHandler, title: "操作", fixed: "right", width: 220, slots: { default: "action" } }
 ]);
 
 // 显示隐藏 筛选表单
@@ -127,4 +135,8 @@ const table_change = row => {
         });
     }).catch(() => {});
 }
+
+defineExpose({
+    getSelectRows: () => xGridTable.value.getSelectRows()
+});
 </script>

+ 3 - 4
src/views/basic/material/index.vue

@@ -75,15 +75,15 @@ const paramsColums = reactive([
 
 const columns = reactive([
     { visible: props.hideHandler, type: props.hideCheckbox && "radio" || "checkbox", fixed: "left", width: 40 },
-    { type: "seq", fixed: "left", width: 60 },
+    { visible: !props.hideHandler, type: "seq", fixed: "left", width: 60 },
     { type: "html", field: "name", title: "物料名称", fixed: "left", minWidth: 150, sortable: true },
     { type: "html", field: "code", title: "物料编码", fixed: "left", minWidth: 150, sortable: true },
+    { visible: !props.hideHandler, field: "status", title: "物料状态", minWidth: 100, editRender: { name: "$cell-tag", options: statusDic } },
     { type: "html", field: "materialType", title: "物料类型", minWidth: 120, sortable: true, formatter: ({ cellValue }) => XEUtils.get(materialDic.type, cellValue, cellValue) },
     { type: "html", field: "needType", title: "物料来源", minWidth: 120, sortable: true, formatter: ({ cellValue }) => XEUtils.get(materialDic.needType, cellValue, cellValue) },
     { type: "html", field: "specification", title: "规格型号", minWidth: 120, sortable: true },
     { type: "html", field: "unit", title: "单位", minWidth: 100, sortable: true },
     { visible: false, type: "html", field: "price", title: "标准售价", minWidth: 100, sortable: true },
-    { field: "status", title: "物料状态", minWidth: 100, editRender: { name: "$cell-tag", options: statusDic } },
     { type: "html", field: "createTime", title: "创建日期", minWidth: 120, sortable: true, formatter: ({ cellValue }) => TOOL.dateFormat(cellValue, "YYYY-MM-DD") || cellValue },
     { visible: false, type: "html", field: "remark", title: "备注", minWidth: 300, sortable: true },
     { visible: !props.hideHandler, title: "操作", fixed: "right", width: 220, slots: { default: "action" } }
@@ -95,7 +95,6 @@ const refreshTable = (mode = "add") => {
     xGridTable.value.reloadColumn(columns);
     xGridTable.value.searchData(mode);
 }
-const getSelectRows = () => xGridTable.value.getSelectRows();
 
 const materialRef = ref();
 const dialog = ref(false);
@@ -140,6 +139,6 @@ const table_change = row => {
 }
 
 defineExpose({
-    getSelectRows
+    getSelectRows: () => xGridTable.value.getSelectRows()
 });
 </script>

+ 1 - 1
src/views/production/bom/main.js

@@ -11,7 +11,7 @@ export const tableOptions = reactive({
         { field: "name", title: "物料名称", fixed: "left", minWidth: 150 },
         { field: "specification", title: "规格型号", minWidth: 150 },
         { field: "unit", title: "单位", minWidth: 150 },
-        { field: "quantity", title: "材料用量", minWidth: 100, editRender: { name: "VxeNumberInput", props: { min: 0, type: "float", controlConfig: { enabled: false } }, defaultValue: 1 } },
+        { field: "quantity", title: "材料用量", minWidth: 100, editRender: { name: "VxeNumberInput", props: { min: 1, controlConfig: { enabled: false } }, defaultValue: 1 } },
         { field: "remark", title: "备注", minWidth: 200, editRender: { name: "ElInput", props: { type: "textarea", autosize: true } } }
     ],
     editRules: {

+ 89 - 32
src/views/sales/order/detail.vue

@@ -10,20 +10,35 @@
                             </el-form-item>
                         </el-col>
                         <el-col :md="8" :xs="24">
-                            <el-form-item label="单据日期" prop="orderTime">
-                                <el-date-picker v-model="form.orderTime" :clearable="false" value-format="YYYY-MM-DD" :default-time="new Date()" placeholder="请选择单据日期"></el-date-picker>
+                            <el-form-item label="单据日期" prop="orderDate">
+                                <el-date-picker v-model="form.orderDate" :clearable="false" value-format="YYYY-MM-DD" :default-time="new Date()" placeholder="请选择单据日期"></el-date-picker>
                             </el-form-item>
                         </el-col>
-
                         <el-col :md="8" :xs="24">
                             <el-form-item label="客户" prop="customer.id">
-                                <sc-table-input v-model="form.customer" :hideShow="!!form.id" placeholder="选择客户" valueKey="name" tableKey="customer" :options="selectOptions"></sc-table-input>
+                                <sc-table-input v-model="form.customer" placeholder="选择客户" valueKey="name" tableKey="customer" :options="selectOptions"></sc-table-input>
+                            </el-form-item>
+                        </el-col>
+                        <el-col :md="8" :xs="24">
+                            <el-form-item label="合同编号" prop="contractNo">
+                                <el-input v-model="form.contractNo" maxlength="50" show-word-limit placeholder="请输入合同编号"></el-input>
                             </el-form-item>
                         </el-col>
-
                         <el-col :md="8" :xs="24">
-                            <el-form-item label="预计交期" prop="confirmedDeliveryDate">
-                                <el-date-picker v-model="form.confirmedDeliveryDate" :clearable="false" value-format="YYYY-MM-DD" :default-time="new Date()" placeholder="请选择预计交期"></el-date-picker>
+                            <el-form-item label="预计交期" prop="planReceiveDate">
+                                <el-date-picker v-model="form.planReceiveDate" :clearable="false" value-format="YYYY-MM-DD" :default-time="new Date()" placeholder="请选择预计交期"></el-date-picker>
+                            </el-form-item>
+                        </el-col>
+                        <el-col :md="8" :xs="24">
+                            <el-form-item label="业务员">
+                                <el-select v-model="form.managerId" clearable placeholder="请选择业务员">
+                                    <el-option v-for="item in users" :key="item.id" :label="item.nickName" :value="item.id" />
+                                </el-select>
+                            </el-form-item>
+                        </el-col>
+                        <el-col :md="16" :xs="24">
+                            <el-form-item label="客户收货地址">
+                                <el-input v-model="form.deliveryAddress" type="textarea" maxlength="200" :rows="1" placeholder="请输入客户收货地址"></el-input>
                             </el-form-item>
                         </el-col>
                     </el-row>
@@ -33,6 +48,25 @@
                     <sc-form-table ref="formTableRef" v-model="form.childrenList" v-bind="tableOptions"></sc-form-table>
                 </el-collapse-item>
 
+                <el-collapse-item title="金额信息" name="amount">
+                    <el-row>
+                        <el-col :md="8" :xs="24">
+                            <el-form-item label="整单折扣额">
+                                <el-input-number v-model="form.freePrice" :min="0" :precision="2" :controls="false" clearable placeholder="请输入折扣金额">
+                                    <template #suffix>元</template>
+                                </el-input-number>
+                            </el-form-item>
+                        </el-col>
+                        <el-col :md="8" :xs="24">
+                            <el-form-item label="成交金额" required>
+                                <el-input-number v-model="form.actualPrice" readonly :controls="false">
+                                    <template #suffix>元</template>
+                                </el-input-number>
+                            </el-form-item>
+                        </el-col>
+                    </el-row>
+                </el-collapse-item>
+
                 <el-collapse-item title="其他说明" name="other">
                     <el-row>
                         <el-col :xs="24">
@@ -54,7 +88,7 @@
 
         <template #footer>
             <el-button auto-insert-space @click="visible = false">取消</el-button>
-            <el-button :loading="isSaving" type="primary" auto-insert-space @click="submit">{{ mode == "upgrade" ? "发布" : "保存" }}</el-button>
+            <el-button :loading="isSaving" type="primary" auto-insert-space @click="submit">保存</el-button>
         </template>
     </el-dialog>
 </template>
@@ -73,36 +107,53 @@ const visible = ref(false);
 const isSaving = ref(false);
 const isDel = ref(false);
 
-const activeNames = ref(["basic", "material", "other"]);
+const activeNames = ref(["basic", "material", "amount", "other"]);
 const mode = ref("add");
 const titleMap = reactive({
     add: "新增销售订单",
     edit: "修改销售订单"
 });
 
+const users = ref([]);
 const form = ref({
     id: null,
     code: null,
-    orderTime: moment().format("YYYY-MM-DD HH:mm:ss"),
-    confirmedDeliveryDate: null,
-    customer: {
-        id: null,
-        label: null
-    },
+    orderDate: moment().format("YYYY-MM-DD"),
+    customer: { id: null, name: null },
+    contractNo: null,
+    planReceiveDate: null,
+    managerId: null,
+    deliveryAddress: null,
     childrenList: [],
+    freePrice: null,
+    incomePrice: null,
+    actualPrice: null,
     remark: null,
     fileList: []
 });
 const rules = reactive({
+    orderDate: [{ required: true, message: "请选择单据日期" }],
+    "customer.id": [{ required: true, message: "请选择客户" }],
+    planReceiveDate: [{ required: true, message: "请选择预计交期" }],
+    contractNo: [{ required: true, message: "请输入合同编号" }]
 });
 
+watch(() => XEUtils.pick(form.value, "childrenList", "freePrice"), value => {
+    if (!value.childrenList.length) form.value.incomePrice = null;
+    else {
+        form.value.incomePrice = XEUtils.sum(XEUtils.map(value.childrenList, item => XEUtils.multiply(item.quantity, item.price)));
+        form.value.actualPrice = XEUtils.subtract(form.value.incomePrice, value.freePrice);
+    }
+}, { deep: true });
+
 const open = () => visible.value = true;
 const setData = data => {
     open();
     mode.value = "edit";
     XEUtils.objectEach(form.value, (_, key) => {
-        if (key == "fileList") XEUtils.set(form.value, key, XEUtils.map(XEUtils.get(data, key), item => ({ ...item, name: item.fileName })));
-        else if (key == "childrenList") XEUtils.set(form.value, key, XEUtils.map(XEUtils.get(data, key), item => ({ ...item.stage, ...XEUtils.omit(item, "id", "stage") })));
+        if (key == "customer") XEUtils.set(form.value, key, { id: XEUtils.get(data, "customerId"), name: XEUtils.get(data, "customerName") });
+        else if (key == "childrenList") XEUtils.set(form.value, key, XEUtils.map(XEUtils.get(data, key), item => ({ ...item.material, quantity: item.materialQuantity, price: item.materialPrice })));
+        else if (key == "fileList") XEUtils.set(form.value, key, XEUtils.map(XEUtils.get(data, key), item => ({ ...item, name: item.fileName })));
         else XEUtils.set(form.value, key, XEUtils.get(data, key));
     });
 }
@@ -110,26 +161,26 @@ const setData = data => {
 const formRef = ref();
 const formTableRef = ref();
 const submit = () => {
-    console.log('submit called', form.value.customerId);
     formRef.value.validate(async valid => {
         if (valid) {
             if (!form.value.childrenList.length) return ElMessage.warning("请添加产品信息后再保存");
             
             if (await formTableRef.value.validateFormTable()) {
-                // const data = XEUtils.omit(form.value, "fileList", "childrenList");
-                // const childrenList = XEUtils.map(form.value.childrenList, item => XEUtils.omit(item, "id", "name", "code", "processType"));
-                // const fileList = XEUtils.map(XEUtils.filter(form.value.fileList, item => !item.id), item => ({ ...XEUtils.omit(item, "id", "name"), fileName: item.name, fileType: "processRouteFile" }));
-                // XEUtils.set(data, "childrenList", childrenList);
-                // fileList.length > 0 && XEUtils.set(data, "fileList", fileList);
-    
-                // isSaving.value = true;
-                // API.workmanship.route[mode.value](data).then(res => {
-                //     ElMessage.success("操作成功");
-                //     isSaving.value = false;
-                //     isDel.value = false;
-                //     visible.value = false;
-                //     $emit("success", mode.value);
-                // }).catch(() => isSaving.value = false);
+                const data = XEUtils.omit(form.value, "customer", "childrenList", "fileList");
+                const childrenList = XEUtils.map(form.value.childrenList, item => ({ materialCode: item.code, materialQuantity: item.quantity, materialPrice: item.price }));
+                const fileList = XEUtils.map(XEUtils.filter(form.value.fileList, item => !item.id), item => ({ ...XEUtils.omit(item, "id", "name"), fileName: item.name, fileType: "salesOrderFile" }));
+                XEUtils.set(data, "customerId", form.value.customer.id);
+                XEUtils.set(data, "childrenList", childrenList);
+                fileList.length > 0 && XEUtils.set(data, "fileList", fileList);
+
+                isSaving.value = true;
+                API.sales.order[mode.value](data).then(res => {
+                    ElMessage.success("操作成功");
+                    isSaving.value = false;
+                    isDel.value = false;
+                    visible.value = false;
+                    $emit("success", mode.value);
+                }).catch(() => isSaving.value = false);
             }
         } else {
             return false;
@@ -141,6 +192,9 @@ const removeSuccess = () => {
     if (form.value.id) isDel.value = true;
 }
 
+const fetchUser = () => API.auth.user.all({ orderBy: "id_desc" }).then(res => users.value = res).catch(() => users.value = []);
+fetchUser();
+
 defineExpose({
     open,
     setData
@@ -149,6 +203,9 @@ defineExpose({
 
 <style scoped>
 .el-form {padding-left: 16px;padding-right: 22px;}
+.el-form .el-input-number {width: 100%;}
+.el-form .el-input-number :deep(.el-input__inner) {text-align: unset;}
+.el-form .el-input-number :deep(.el-input__suffix) {font-size: 12px;}
 
 .el-collapse {border: none;}
 .el-collapse-item {margin-top: 15px;padding: 0 24px;background-color: var(--el-fill-color-blank);border: 1px solid var(--el-border-color-light);border-radius: 4px;color: var(--el-text-color-primary);box-shadow: var(--el-box-shadow-light);transition: var(--el-transition-duration);}

+ 19 - 34
src/views/sales/order/index.vue

@@ -2,7 +2,7 @@
 	<el-container class="is-vertical">
         <sc-page-header @add="table_add"></sc-page-header>
 
-        <scTable ref="xGridTable" :apiObj="$API.workmanship.route" :formConfig="formConfig" :paramsColums="paramsColums" :toolbarConfig="toolbarConfig" :columns="columns">
+        <scTable ref="xGridTable" :apiObj="$API.sales.order" :formConfig="formConfig" :paramsColums="paramsColums" :toolbarConfig="toolbarConfig" :columns="columns">
             <template #code_link="{ row }">
                 <vxe-text status="primary" @click="table_detail(row)">{{ row.code }}</vxe-text>
             </template>
@@ -11,13 +11,7 @@
                 <el-button type="primary" link @click="table_edit(row)">
                     <template #icon><sc-iconify icon="ant-design:edit-outlined"></sc-iconify></template>修改
                 </el-button>
-                <el-button v-if="row.status == 'enable'" type="primary" link @click="table_change(row)">
-                    <template #icon><sc-iconify icon="material-symbols:lock-outline"></sc-iconify></template>停用
-                </el-button>
-                <el-button v-else type="primary" link @click="table_change(row)">
-                    <template #icon><sc-iconify icon="material-symbols:lock-open-outline"></sc-iconify></template>启用
-                </el-button>
-                <el-button v-if="!row.isHaveHistory" type="primary" link @click="table_del(row)">
+                <el-button type="primary" link @click="table_del(row)">
                     <template #icon><sc-iconify icon="ant-design:delete-outlined"></sc-iconify></template>删除
                 </el-button>
             </template>
@@ -34,7 +28,7 @@ import XEUtils from "xe-utils";
 
 import API from "@/api";
 import TOOL from "@/utils/tool";
-import { statusDic, workmanshipDic, objectToArray } from "@/utils/basicDic";
+import { salesDic, objectToArray } from "@/utils/basicDic";
 import { mapFormItemInput, mapFormItemSelect, mapFormItemDatePicker } from "@/components/scTable/helper";
 import orderDetail from "./detail";
 import orderDesc from "./desc";
@@ -45,7 +39,7 @@ const toolbarConfig = reactive({
 });
 
 const selectConfig = reactive({
-    options: objectToArray(statusDic),
+    options: objectToArray(salesDic.orderStatus),
     events: {
         change: data => XEUtils.merge(formConfig.data, data)
     }
@@ -65,8 +59,8 @@ const formConfig = reactive({
     data: {},
     items: [
         mapFormItemInput("codeLike", "单据编号"),
-        mapFormItemSelect("status", "工艺路线状态", selectConfig),
-        mapFormItemDatePicker("createTime", "创建日期", daterangeConfig)
+        mapFormItemSelect("status", "单据状态", selectConfig),
+        mapFormItemDatePicker("orderDate", "单据日期", daterangeConfig)
     ]
 });
 
@@ -74,17 +68,24 @@ const paramsColums = reactive([
     { column: "orderBy", defaultValue: "code_asc" },
     { column: "codeLike" },
     { column: "status" },
-    { column: "createTimeBegin", field: "createTime[0]" },
-    { column: "createTimeEnd", field: "createTime[1]" }
+    { column: "orderDateBegin", field: "orderDate[0]" },
+    { column: "orderDateEnd", field: "orderDate[1]" }
 ]);
 
 const columns = reactive([
     { type: "checkbox", fixed: "left", width: 40 },
     { type: "seq", fixed: "left", width: 60 },
     { field: "code", title: "单据编号", fixed: "left", minWidth: 150, sortable: true, className: "vxe-table-link-cell", slots: { default: "code_link" } },
-    { field: "status", title: "工艺路线状态", minWidth: 120, editRender: { name: "$cell-tag", options: statusDic } },
-    { type: "html", field: "", title: "质检方案", minWidth: 160, sortable: true },
-    { type: "html", field: "createTime", title: "创建日期", minWidth: 120, sortable: true, formatter: ({ cellValue }) => TOOL.dateFormat(cellValue, "YYYY-MM-DD") || cellValue },
+    { type: "html", field: "orderDate", title: "单据日期", fixed: "left", minWidth: 120, sortable: true },
+    { field: "status", title: "单据状态", minWidth: 120, editRender: { name: "$cell-tag", options: salesDic.orderStatus } },
+    { type: "html", field: "customerName", title: "客户", minWidth: 150, sortable: true },
+    { type: "html", field: "contractNo", title: "合同编号", minWidth: 150, sortable: true },
+    { type: "html", field: "managerName", title: "业务员", minWidth: 150, sortable: true },
+    { visible: false, type: "html", field: "freePrice", title: "整单折扣额", minWidth: 120, sortable: true },
+    { type: "html", field: "actualPrice", title: "成交金额", minWidth: 120, sortable: true },
+    { type: "html", field: "planReceiveDate", title: "预计交期", minWidth: 120, sortable: true },
+    { visible: false, type: "html", field: "createTime", title: "创建日期", minWidth: 120, sortable: true, formatter: ({ cellValue }) => TOOL.dateFormat(cellValue, "YYYY-MM-DD") || cellValue },
+    { visible: false, type: "html", field: "deliveryAddress", title: "客户收货地址", minWidth: 300, sortable: true },
     { visible: false, type: "html", field: "remark", title: "概要", minWidth: 300, sortable: true },
     { title: "操作", fixed: "right", width: 320, slots: { default: "action" } }
 ]);
@@ -124,23 +125,7 @@ const table_del = ({ id }) => {
         confirmButtonText: "确定",
         cancelButtonText: "取消"
     }).then(() => {
-        API.workmanship.route.del({ id }).then(() => {
-            ElMessage.success("操作成功");
-            refreshTable();
-        });
-    }).catch(() => {});
-}
-
-const table_change = row => {
-    const status = row.status == "enable" && "disable" || "enable";
-    const msg = row.status == "enable" && "停用" || "启用";
-
-    ElMessageBox.confirm(`是否确认${msg}该销售订单?`, `${msg}警告`, {
-        type: "warning",
-        confirmButtonText: "确定",
-        cancelButtonText: "取消"
-    }).then(() => {
-        API.workmanship.route.edit({ id: row.id, status }).then(() => {
+        API.sales.order.del({ id }).then(() => {
             ElMessage.success("操作成功");
             refreshTable();
         });

+ 16 - 40
src/views/sales/order/main.js

@@ -1,6 +1,5 @@
 import XEUtils from "xe-utils";
-import TOOL from "@/utils/tool";
-import { materialDic, customerDic } from "@/utils/basicDic";
+import { materialDic } from "@/utils/basicDic";
 import { mapFormItemInput } from "@/components/scTable/helper";
 
 export const tableOptions = reactive({
@@ -8,61 +7,38 @@ export const tableOptions = reactive({
 
     columns: [
         { type: "seq", fixed: "left", width: 80, className: "vxe-table-seq-cell__handler", footerAlign: "right", showOverflow: false, params: { hide_del: row => XEUtils.get(row, "isHaveChildren", false) }, slots: { default: "seq_del" } },
-        { field: "code", title: "物料编码", fixed: "left", minWidth: 150 },
-        { field: "name", title: "物料名称", fixed: "left", minWidth: 150 },
-        { field: "specification", title: "规格型号", minWidth: 150 },
+        { field: "code", title: "产品编码", fixed: "left", minWidth: 150 },
+        { field: "name", title: "产品名称", fixed: "left", minWidth: 150 },
         { field: "unit", title: "单位", minWidth: 150 },
-        { field: "quantity", title: "材料用量", minWidth: 100, editRender: { name: "VxeNumberInput", props: { min: 0, type: "float", controlConfig: { enabled: false } }, defaultValue: 1 } },
-        { field: "remark", title: "备注", minWidth: 200, editRender: { name: "ElInput", props: { type: "textarea", autosize: true } } }
+        { field: "quantity", title: "数量", minWidth: 100, editRender: { name: "VxeNumberInput", props: { min: 1, controlConfig: { enabled: false } }, defaultValue: 1 } },
+        { field: "price", title: "单价", minWidth: 100, editRender: { name: "VxeNumberInput", props: { min: 0, type: "float", controlConfig: { enabled: false } }, defaultValue: 1 } }
     ],
     editRules: {
-        quantity: [{ required: true, message: "必须填写" }]
+        quantity: [{ required: true, message: "必须填写" }],
+        price: [{ required: true, message: "必须填写" }]
     },
-    footerField: ["quantity"],
-    mergeFooterItems: [{ row: 0, col: 0, rowspan: 1, colspan: 5 }],
+    footerField: ["quantity", "price"],
+    mergeFooterItems: [{ row: 0, col: 0, rowspan: 1, colspan: 4 }],
 
     selectOptions: {
         formConfig: {
             data: { status: "enable", materialTypeIn: ["finished_product", "trade_goods"] },
             items: [
-                mapFormItemInput("nameLike", "物料名称"),
-                mapFormItemInput("codeLike", "物料编码")
+                mapFormItemInput("nameLike", "产品名称"),
+                mapFormItemInput("codeLike", "产品编码")
             ]
         }
     },
 
-    add_success: (oldValue, newValue) => XEUtils.map(newValue, (item, index) => XEUtils.pick(item, "id", "code", "name", "specification", "unit"))
+    add_success: (oldValue, newValue) => XEUtils.map(newValue, (item, index) => XEUtils.pick(item, "id", "code", "name", "unit", "price"))
 })
 
 export const selectOptions = reactive({
-    optionsProps: { label: "name", value: "id" },
-    placeholder: "请选择客户",
     formConfig: {
-        data: { status: "enable", customerType: "customer" },
+        data: { status: "enable" },
         items: [
             mapFormItemInput("nameLike", "客户名称"),
-            mapFormItemInput("codeLike", "客户编")
+            mapFormItemInput("codeLike", "客户编")
         ]
-    },
-    paramsColums: [
-        { column: "orderBy", defaultValue: "code_asc" },
-        { column: "nameLike" },
-        { column: "codeLike" },
-        { column: "status" },
-        { column: "type" }
-    ],
-
-    columns: [
-        { type: "radio", fixed: "left", width: 40 },
-        { type: "html", field: "name", title: "客户名称", minWidth: 150, sortable: true },
-        { type: "html", field: "code", title: "客户编号", minWidth: 150, sortable: true },
-        { type: "html", field: "type", title: "客户分类", minWidth: 120, sortable: true, formatter: ({ cellValue }) => XEUtils.get(customerDic.type, cellValue, cellValue) },
-        { visible: false, type: "html", field: "valueLevel", title: "客户层级", minWidth: 120, sortable: true, formatter: ({ cellValue }) => XEUtils.get(customerDic.tier, cellValue, cellValue) },
-        { visible: false, type: "html", field: "creditLevel", title: "信用等级", minWidth: 120, sortable: true, formatter: ({ cellValue }) => XEUtils.get(customerDic.rating, cellValue, cellValue) },
-        { type: "html", field: "managerName", title: "联系人", minWidth: 120, sortable: true },
-        { type: "html", field: "managerPhone", title: "联系方式", minWidth: 120, sortable: true },
-        { visible: false, type: "html", field: "email", title: "邮箱", minWidth: 120, sortable: true },
-        { type: "html", field: "createTime", title: "创建日期", minWidth: 120, sortable: true, formatter: ({ cellValue }) => TOOL.dateFormat(cellValue, "YYYY-MM-DD") || cellValue },
-        { visible: false, type: "html", field: "address", title: "客户地址", minWidth: 300, sortable: true },
-    ]
-});
+    }
+})

+ 5 - 5
src/views/sales/plan/detail.vue

@@ -74,7 +74,7 @@ import moment from "moment";
 import XEUtils from "xe-utils";
 
 import API from "@/api";
-import { planDic } from "@/utils/basicDic";
+import { salesDic } from "@/utils/basicDic";
 
 const $emit = defineEmits(["success", "closed"]);
 const visible = ref(false);
@@ -135,11 +135,11 @@ const setData = (parent, data, model = "add") => {
 }
 
 const mapRadio = computed((() => {
-    if (form.value.children.length) return XEUtils.pick(planDic.type, form.value.type);
+    if (form.value.children.length) return XEUtils.pick(salesDic.planType, form.value.type);
 
-    if (parentType.value == "year") return XEUtils.omit(planDic.type, "year");
-    if (parentType.value == "quarter") return XEUtils.pick(planDic.type, "month");
-    return planDic.type;
+    if (parentType.value == "year") return XEUtils.omit(salesDic.planType, "year");
+    if (parentType.value == "quarter") return XEUtils.pick(salesDic.planType, "month");
+    return salesDic.planType;
 }));
 
 const monthDisabled = month => {

+ 4 - 4
src/views/sales/plan/index.vue

@@ -26,7 +26,7 @@ import XEUtils from "xe-utils";
 
 import API from "@/api";
 import TOOL from "@/utils/tool";
-import { planDic, objectToArray } from "@/utils/basicDic";
+import { salesDic, objectToArray } from "@/utils/basicDic";
 import { mapFormItemInput, mapFormItemSelect, mapFormItemDatePicker } from "@/components/scTable/helper";
 import planDetail from "./detail";
 
@@ -46,7 +46,7 @@ const options = reactive({
 })
 
 const selectConfig = reactive({
-    options: objectToArray(planDic.type),
+    options: objectToArray(salesDic.planType),
     events: {
         change: data => XEUtils.merge(formConfig.data, data)
     }
@@ -87,8 +87,8 @@ const columns = reactive([
     { type: "seq", fixed: "left", width: 80 },
     { type: "html", field: "name", title: "计划名称", fixed: "left", minWidth: 160, treeNode: true, headerAlign: "center", align: "left", sortable: true },
     { type: "html", field: "code", title: "计划编号", fixed: "left", minWidth: 150, sortable: true },
-    { type: "html", field: "type", title: "计划类型", minWidth: 120, sortable: true, formatter: ({ cellValue }) => XEUtils.get(planDic.type, cellValue, cellValue) },
-    { field: "status", title: "计划状态", minWidth: 120, editRender: { name: "$cell-tag", options: planDic.status, formatter: row => formatStatus(row) } },
+    { type: "html", field: "type", title: "计划类型", minWidth: 120, sortable: true, formatter: ({ cellValue }) => XEUtils.get(salesDic.planType, cellValue, cellValue) },
+    { field: "status", title: "计划状态", minWidth: 120, editRender: { name: "$cell-tag", options: salesDic.planStatus, formatter: row => formatStatus(row) } },
     { type: "html", field: "beginDate", title: "计划开始日期", minWidth: 150, sortable: true },
     { type: "html", field: "endDate", title: "计划结束日期", minWidth: 150, sortable: true },
     { type: "html", field: "saleAmount", title: "计划销售金额(万)", minWidth: 150, sortable: true },

+ 1 - 1
src/views/workmanship/line/detail.vue

@@ -148,7 +148,7 @@ const submit = () => {
             if (!form.value.detailList.length) return ElMessage.warning("请添加加工路线信息后再保存");
             
             if (await formTableRef.value.validateFormTable()) {
-                const data = XEUtils.omit(form.value, "fileList", "detailList");
+                const data = XEUtils.omit(form.value, "detailList", "fileList");
                 const detailList = XEUtils.map(form.value.detailList, item => XEUtils.omit(item, "id", "name", "code", "processType"));
                 const fileList = XEUtils.map(XEUtils.filter(form.value.fileList, item => !item.id), item => ({ ...XEUtils.omit(item, "id", "name"), fileName: item.name, fileType: "processRouteFile" }));
                 XEUtils.set(data, "detailList", detailList);

+ 2 - 2
src/views/workmanship/line/main.js

@@ -15,10 +15,10 @@ export const tableOptions = reactive({
         { field: "readyTimeHour", title: "准备时间", minWidth: 100, editRender: { name: "VxeNumberInput", props: { min: 0, type: "float", controlConfig: { enabled: false } }, defaultValue: 0 } },
         { title:  "定额工时", headerAlign: "center",
             children: [
-                { field: "processNum", title: "加工批量", minWidth: 100, editRender: { name: "VxeNumberInput", props: { min: 0, type: "float", controlConfig: { enabled: false } }, defaultValue: 1 } },
+                { field: "processNum", title: "加工批量", minWidth: 100, editRender: { name: "VxeNumberInput", props: { min: 0, controlConfig: { enabled: false } }, defaultValue: 1 } },
                 { field: "processTimeHour", minWidth: 100, title: "加工工时", editRender: { name: "VxeNumberInput", props: { min: 0, type: "float", controlConfig: { enabled: false } }, defaultValue: 1 } },
                 { field: "moveNum", minWidth: 100, title: "搬运工时", editRender: { name: "VxeNumberInput", props: { min: 0, type: "float", controlConfig: { enabled: false } }, defaultValue: 0 } },
-                { field: "moveTimeHour", minWidth: 100, title: "搬运批量", editRender: { name: "VxeNumberInput", props: { min: 0, type: "float", controlConfig: { enabled: false } }, defaultValue: 0 } }
+                { field: "moveTimeHour", minWidth: 100, title: "搬运批量", editRender: { name: "VxeNumberInput", props: { min: 0, controlConfig: { enabled: false } }, defaultValue: 0 } }
             ] 
         },
         { field: "isReport", title: "是否汇报", minWidth: 100, cellRender: { name: "VxeCheckbox" } },

+ 3 - 4
src/views/workmanship/process/index.vue

@@ -85,10 +85,10 @@ const paramsColums = reactive([
 
 const columns = reactive([
     { visible: props.hideHandler, type: props.hideCheckbox && "radio" || "checkbox", fixed: "left", width: 40 },
-    { type: "seq", fixed: "left", width: 60 },
+    { visible: !props.hideHandler, type: "seq", fixed: "left", width: 60 },
     { type: "html", field: "name", title: "工序名称", fixed: "left", minWidth: 150, sortable: true },
     { type: "html", field: "code", title: "工序编号", fixed: "left", minWidth: 150, sortable: true },
-    { field: "status", title: "工序状态", minWidth: 100, editRender: { name: "$cell-tag", options: statusDic } },
+    { visible: !props.hideHandler, field: "status", title: "工序状态", minWidth: 100, editRender: { name: "$cell-tag", options: statusDic } },
     { type: "html", field: "category", title: "工序分类", minWidth: 100, sortable: true, formatter: ({ cellValue }) => XEUtils.get(workmanshipDic.category, cellValue, cellValue) },
     { type: "html", field: "directorName", title: "工序负责人", minWidth: 120, sortable: true },
     { visible: false, type: "html", field: "directorPhone", title: "联系方式", minWidth: 120, sortable: true },
@@ -105,7 +105,6 @@ const refreshTable = (mode = "add") => {
     xGridTable.value.reloadColumn(columns);
     xGridTable.value.searchData(mode);
 }
-const getSelectRows = () => xGridTable.value.getSelectRows();
 
 const processRef = ref();
 const dialog = ref(false);
@@ -155,6 +154,6 @@ const dialogClose = isDel => {
 }
 
 defineExpose({
-    getSelectRows
+    getSelectRows: () => xGridTable.value.getSelectRows()
 });
 </script>