| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553 |
- import { add, update, getDetail } from '@/api/order/order'
- import { getList as getOrderItemList } from '@/api/order/order-item'
- import {
- ORDER_TYPES,
- ORDER_STATUS,
- ORDER_TYPE_OPTIONS,
- ORDER_STATUS_OPTIONS
- } from '@/constants/order'
- /**
- * @typedef {import('./types').OrderFormModel} OrderFormModel
- * @typedef {import('./types').ValidationRule} ValidationRule
- * @typedef {import('./types').OrderFormRules} OrderFormRules
- * @typedef {import('./types').OrderFormData} OrderFormMixinData
- */
- /**
- * @typedef {Object} ApiResponse
- * @property {number} code - 响应状态码
- * @property {string} message - 响应消息
- * @property {*} data - 响应数据
- */
- /**
- * @typedef {import('./types').OrderTypeOption} OrderTypeOption
- * @typedef {import('./types').OrderStatusOption} OrderStatusOption
- */
- /**
- * 订单表单混入组件
- * @description 提供订单表单的数据管理、验证规则和业务逻辑的混入组件
- * @mixin
- */
- export default {
- /**
- * 组件响应式数据
- * @description 定义组件的响应式数据状态
- * @returns {OrderFormMixinData} 组件数据对象
- */
- data() {
- return {
- /**
- * 订单表单数据模型
- * @description 存储订单表单的所有字段数据
- * @type {OrderFormModel}
- */
- formData: this.createInitialFormData(),
- /**
- * 保存操作加载状态
- * @description 控制保存按钮的加载状态,防止重复提交
- * @type {boolean}
- */
- saveLoading: false,
- /**
- * 订单类型选项列表
- * @description 订单类型下拉选择器的选项数据
- * @type {OrderTypeOption[]}
- */
- orderTypeOptions: Object.freeze([...ORDER_TYPE_OPTIONS]),
- /**
- * 订单状态选项列表
- * @description 订单状态下拉选择器的选项数据
- * @type {OrderStatusOption[]}
- */
- orderStatusOptions: Object.freeze([...ORDER_STATUS_OPTIONS])
- }
- },
- /**
- * 计算属性
- * @description 组件的响应式计算属性
- */
- computed: {
- /**
- * 订单表单验证规则
- * @description 定义订单表单各字段的验证规则,支持必填、长度、格式等验证
- * @returns {OrderFormRules} 完整的表单验证规则对象
- */
- formRules() {
- return {
- orderCode: [
- {
- required: true,
- message: '请输入订单编码',
- trigger: 'blur'
- },
- {
- min: 3,
- max: 50,
- message: '订单编码长度在 3 到 50 个字符',
- trigger: 'blur'
- }
- ],
- orgCode: [
- {
- required: true,
- message: '请输入组织编码',
- trigger: 'blur'
- },
- {
- min: 2,
- max: 20,
- message: '组织编码长度在 2 到 20 个字符',
- trigger: 'blur'
- }
- ],
- orgName: [
- {
- required: true,
- message: '请输入组织名称',
- trigger: 'blur'
- },
- {
- min: 2,
- max: 100,
- message: '组织名称长度在 2 到 100 个字符',
- trigger: 'blur'
- }
- ],
- customerCode: [
- {
- required: true,
- message: '请输入客户编码',
- trigger: 'blur'
- },
- {
- min: 3,
- max: 50,
- message: '客户编码长度在 3 到 50 个字符',
- trigger: 'blur'
- }
- ],
- customerName: [
- {
- required: true,
- message: '请输入客户名称',
- trigger: 'blur'
- },
- {
- min: 2,
- max: 100,
- message: '客户名称长度在 2 到 100 个字符',
- trigger: 'blur'
- }
- ],
- orderType: [
- {
- required: true,
- message: '请选择订单类型',
- trigger: 'change'
- }
- ],
- totalAmount: [
- {
- required: true,
- message: '请输入订单总金额',
- trigger: 'blur'
- },
- {
- type: 'number',
- min: 0.01,
- message: '订单总金额必须大于0',
- trigger: 'blur'
- }
- ],
- totalQuantity: [
- {
- required: true,
- message: '请输入订单总数量',
- trigger: 'blur'
- },
- {
- type: 'number',
- min: 0.0001,
- message: '订单总数量必须大于0',
- trigger: 'blur'
- }
- ],
- receiverName: [
- {
- required: true,
- message: '请输入收货人姓名',
- trigger: 'blur'
- },
- {
- min: 2,
- max: 50,
- message: '收货人姓名长度在 2 到 50 个字符',
- trigger: 'blur'
- }
- ],
- receiverPhone: [
- {
- required: true,
- message: '请输入收货人电话',
- trigger: 'blur'
- },
- {
- pattern: /^1[3-9]\d{9}$/,
- message: '请输入正确的手机号码',
- trigger: 'blur'
- }
- ],
- receiverAddress: [
- {
- required: true,
- message: '请输入收货地址',
- trigger: 'blur'
- },
- {
- min: 5,
- max: 500,
- message: '收货地址长度在 5 到 500 个字符',
- trigger: 'blur'
- }
- ],
- remark: [
- {
- max: 1000,
- message: '备注信息不能超过 1000 个字符',
- trigger: 'blur'
- }
- ]
- }
- }
- },
- /**
- * 组件方法
- * @description 组件的业务逻辑方法集合
- */
- methods: {
- /**
- * 创建初始表单数据
- * @description 创建订单表单的初始数据结构
- * @returns {OrderFormModel} 初始化的表单数据对象
- * @private
- */
- createInitialFormData() {
- return {
- id: null,
- orderCode: '',
- orgCode: '',
- orgName: '',
- customerCode: '',
- customerName: '',
- orderType: ORDER_TYPES.NORMAL,
- totalAmount: null,
- totalQuantity: null,
- receiverName: '',
- receiverPhone: '',
- receiverAddress: '',
- status: ORDER_STATUS.DRAFT,
- remark: ''
- }
- },
- /**
- * 初始化表单数据
- * @description 根据编辑模式初始化表单,编辑模式加载数据,新增模式重置表单
- * @returns {Promise<void>}
- * @public
- */
- async initForm() {
- try {
- if (this.isEdit && this.orderId) {
- await this.loadOrderDetail(this.orderId)
- } else {
- this.resetForm()
- }
- } catch (error) {
- this.$message.error('初始化表单失败,请刷新页面重试')
- }
- },
- /**
- * 重置表单数据
- * @description 将表单数据重置为初始状态,并清除所有验证错误信息
- * @returns {Promise<void>}
- * @public
- */
- async resetForm() {
- try {
- // 重置表单数据为初始状态
- this.formData = this.createInitialFormData()
- // 等待DOM更新后清除表单验证
- await this.$nextTick()
- if (this.$refs.orderForm && typeof this.$refs.orderForm.clearValidate === 'function') {
- this.$refs.orderForm.clearValidate()
- }
- } catch (error) {
- // 重置表单时发生错误,静默处理
- }
- },
- /**
- * 加载订单详情数据
- * @description 根据订单ID从服务器获取订单详情并填充到表单中,同时加载物料明细数据
- * @param {string|number} orderId - 订单唯一标识
- * @returns {Promise<void>}
- * @throws {Error} 当API调用失败或数据格式错误时抛出异常
- * @public
- */
- async loadOrderDetail(orderId) {
- if (!orderId) {
- throw new Error('订单ID不能为空')
- }
- try {
- // 并行加载订单详情和物料明细数据
- const [orderResponse, materialResponse] = await Promise.all([
- getDetail(orderId),
- this.loadMaterialDetails(orderId)
- ])
- if (!orderResponse || !orderResponse.data || !orderResponse.data.data) {
- throw new Error('服务器返回数据格式错误')
- }
- const orderData = orderResponse.data.data
- // 安全地映射订单数据到表单,确保数据类型正确
- this.formData = this.mapOrderDataToForm(orderData)
- // 设置物料明细数据
- this.materialDetails = materialResponse
- } catch (error) {
- const errorMessage = error.message || '加载订单详情失败'
- this.$message.error(`${errorMessage},请重试`)
- throw error
- }
- },
- /**
- * 加载订单物料明细数据
- * @description 根据订单ID从服务器获取物料明细列表,用于编辑模式下的数据回显
- * @param {string|number} orderId - 订单唯一标识符
- * @returns {Promise<OrderItemRecord[]>} 物料明细记录列表,失败时返回空数组
- * @private
- */
- async loadMaterialDetails(orderId) {
- try {
- const response = await getOrderItemList(1, 1000, { orderId })
- if (!response || !response.data || !response.data.data) {
- throw new Error('物料明细数据格式错误')
- }
- return response.data.data.records || []
- } catch (error) {
- this.$message.warning('加载物料明细失败,请稍后重试')
- return []
- }
- },
- /**
- * 映射订单数据到表单格式
- * @description 将API返回的订单数据安全地映射为表单数据格式
- * @param {Object} orderData - 从API获取的原始订单数据
- * @returns {OrderFormModel} 格式化后的表单数据
- * @private
- */
- mapOrderDataToForm(orderData) {
- return {
- id: orderData.id || null,
- orderCode: String(orderData.orderCode || ''),
- orgCode: String(orderData.orgCode || ''),
- orgName: String(orderData.orgName || ''),
- customerCode: String(orderData.customerCode || ''),
- customerName: String(orderData.customerName || ''),
- orderType: Number(orderData.orderType) || ORDER_TYPES.NORMAL,
- totalAmount: orderData.totalAmount ? Number(orderData.totalAmount) : null,
- totalQuantity: orderData.totalQuantity ? Number(orderData.totalQuantity) : null,
- receiverName: String(orderData.receiverName || ''),
- receiverPhone: String(orderData.receiverPhone || ''),
- receiverAddress: String(orderData.receiverAddress || ''),
- status: Number(orderData.status) || ORDER_STATUS.DRAFT,
- remark: String(orderData.remark || '')
- }
- },
- /**
- * 处理返回列表操作
- * @description 触发返回列表事件,通知父组件关闭表单
- * @returns {void}
- * @public
- * @emits back 返回列表事件
- */
- handleBack() {
- /**
- * 返回列表事件
- * @event back
- * @description 用户点击返回按钮时触发
- */
- this.$emit('back')
- },
- /**
- * 处理表单保存操作
- * @description 验证表单数据并提交到服务器,支持新增和编辑模式
- * @returns {Promise<void>}
- * @throws {Error} 当表单验证失败或API调用失败时抛出异常
- * @public
- * @emits save-success 保存成功事件
- */
- async handleSave() {
- if (this.saveLoading) {
- return // 防止重复提交
- }
- try {
- // 表单验证
- const isValid = await this.validateForm()
- if (!isValid) {
- return
- }
- this.saveLoading = true
- // 准备提交数据
- const submitData = this.prepareSubmitData()
- // 调用相应的API
- const response = await this.submitOrderData(submitData)
- // 显示成功提示
- const successMessage = this.isEdit ? '订单更新成功' : '订单创建成功'
- this.$message.success(successMessage)
- /**
- * 保存成功事件
- * @event save-success
- * @param {Object} data - 保存后的订单数据
- * @description 订单保存成功后触发,携带最新的订单数据
- */
- this.$emit('save-success', response.data.data)
- // 返回列表
- this.handleBack()
- } catch (error) {
- const errorMessage = this.isEdit ? '订单更新失败,请重试' : '订单创建失败,请重试'
- this.$message.error(errorMessage)
- throw error
- } finally {
- this.saveLoading = false
- }
- },
- /**
- * 提交订单数据到服务器
- * @description 根据编辑模式调用相应的API接口
- * @param {Object} submitData - 要提交的订单数据
- * @returns {Promise<ApiResponse>} API响应结果
- * @private
- */
- async submitOrderData(submitData) {
- if (this.isEdit) {
- return await update(submitData)
- } else {
- return await add(submitData)
- }
- },
- /**
- * 验证表单数据
- * @description 使用AvueJS表单的验证功能验证所有字段
- * @returns {Promise<boolean>} 验证结果,true表示验证通过,false表示验证失败
- * @public
- */
- async validateForm() {
- if (!this.$refs.orderForm) {
- return false
- }
- try {
- // 使用更简洁的Promise包装器函数
- const isValid = await this.validateFormFields()
- if (!isValid) {
- this.$message.warning('请检查表单填写是否正确')
- }
- return isValid
- } catch (error) {
- this.$message.warning('请检查表单填写是否正确')
- return false
- }
- },
- /**
- * 验证表单字段
- * @description 封装表单验证逻辑,提供更清晰的异步处理
- * @returns {Promise<boolean>} 验证结果
- * @private
- */
- validateFormFields() {
- return new Promise((resolve) => {
- this.$refs.orderForm.validate((valid) => {
- resolve(Boolean(valid))
- })
- })
- },
- /**
- * 准备提交数据
- * @description 处理表单数据,移除空值字段并确保数据类型正确
- * @returns {Object} 格式化后的提交数据对象
- * @public
- */
- prepareSubmitData() {
- const submitData = { ...this.formData }
- // 清理和格式化数据
- return this.cleanAndFormatSubmitData(submitData)
- },
- /**
- * 清理和格式化提交数据
- * @description 移除空值字段并确保数据类型正确
- * @param {OrderFormModel} data - 原始表单数据
- * @returns {Object} 清理后的数据对象
- * @private
- */
- cleanAndFormatSubmitData(data) {
- const cleanedData = {}
- Object.keys(data).forEach(key => {
- const value = data[key]
- // 跳过null、undefined和空字符串,但保留备注字段
- if (value === null || value === undefined || (value === '' && key !== 'remark')) {
- return
- }
- // 确保数字类型字段的正确性
- if (['totalAmount', 'totalQuantity', 'orderType', 'status'].includes(key)) {
- cleanedData[key] = Number(value) || 0
- } else {
- cleanedData[key] = value
- }
- })
- return cleanedData
- }
- }
- }
|