index.vue 31 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938
  1. <template>
  2. <div class="p-2">
  3. <!-- 订单流程 -->
  4. <el-card shadow="never" class="mb-2">
  5. <div class="order-steps">
  6. <span class="step-title">A10订单流程</span>
  7. </div>
  8. </el-card>
  9. <!-- 订单基本信息 -->
  10. <el-card shadow="never" class="mb-2">
  11. <template #header>
  12. <div class="card-header">
  13. <span>订单基本信息</span>
  14. <span> 订单日期:<el-date-picker v-model="form.orderTime" type="date" value-format="YYYY-MM-DD" /></span>
  15. </div>
  16. </template>
  17. <el-form ref="orderMainFormRef" :model="form" :rules="rules" label-width="100px">
  18. <el-row :gutter="20">
  19. <!-- 第一行 -->
  20. <el-col :span="8">
  21. <el-form-item label="归属公司" prop="companyId">
  22. <el-select v-model="form.companyId" placeholder="请选择" style="width: 100%" filterable>
  23. <el-option v-for="company in companyList" :key="company.id" :label="company.companyName" :value="company.id" />
  24. </el-select>
  25. </el-form-item>
  26. </el-col>
  27. <el-col :span="8">
  28. <el-form-item label="客户名称" prop="customerId">
  29. <el-select
  30. v-model="form.customerId"
  31. placeholder="请选择客户"
  32. style="width: 100%"
  33. filterable
  34. :disabled="!form.companyId"
  35. :loading="customerLoading"
  36. @change="handleCustomerChange"
  37. >
  38. <el-option v-for="customer in customerList" :key="customer.id" :label="customer.customerName" :value="customer.id" />
  39. </el-select>
  40. </el-form-item>
  41. </el-col>
  42. </el-row>
  43. <el-row :gutter="20">
  44. <!-- 第二行 -->
  45. <el-col :span="8"> </el-col>
  46. <el-col :span="8">
  47. <el-form-item label="信用额度" prop="creditLimit">
  48. <el-input v-model="form.creditLimit" placeholder="0" disabled />
  49. </el-form-item>
  50. </el-col>
  51. <el-col :span="8">
  52. <el-form-item label="剩余额度">
  53. <el-input value="0" disabled />
  54. </el-form-item>
  55. </el-col>
  56. </el-row>
  57. <el-row :gutter="20">
  58. <!-- 第三行 -->
  59. <el-col :span="8">
  60. <el-form-item label="业务人员" prop="businessStaff">
  61. <el-input v-model="form.businessStaff" placeholder="请选择" disabled />
  62. </el-form-item>
  63. </el-col>
  64. <el-col :span="8">
  65. <el-form-item label="客服人员" prop="customerService">
  66. <el-input v-model="form.customerService" placeholder="请选择" disabled />
  67. </el-form-item>
  68. </el-col>
  69. <el-col :span="8">
  70. <el-form-item label="业务部门" prop="businessDept">
  71. <el-input v-model="form.businessDept" placeholder="请选择" disabled />
  72. </el-form-item>
  73. </el-col>
  74. </el-row>
  75. <el-row :gutter="20">
  76. <!-- 第四行 -->
  77. <el-col :span="8">
  78. <el-form-item label="发票类型" prop="invoiceType">
  79. <el-select v-model="form.invoiceType" placeholder="请选择" style="width: 100%" disabled>
  80. <el-option label="普通发票" value="1" />
  81. <el-option label="增值税发票" value="2" />
  82. </el-select>
  83. </el-form-item>
  84. </el-col>
  85. <el-col :span="8">
  86. <el-form-item label="支付方式" prop="payType">
  87. <el-select v-model="form.payType" placeholder="请选择" style="width: 100%">
  88. <el-option v-for="dict in pay_method" :key="dict.value" :label="dict.label" :value="dict.value" />
  89. </el-select>
  90. </el-form-item>
  91. </el-col>
  92. <el-col :span="8">
  93. <el-form-item label="预收货日" prop="expectedDeliveryTime">
  94. <el-date-picker
  95. v-model="form.expectedDeliveryTime"
  96. type="date"
  97. placeholder="请选择"
  98. value-format="YYYY-MM-DD"
  99. style="width: 100%"
  100. :disabled-date="disabledDeliveryDate"
  101. />
  102. </el-form-item>
  103. </el-col>
  104. </el-row>
  105. <el-row :gutter="20">
  106. <!-- 第五行 -->
  107. <el-col :span="8">
  108. <el-form-item label="发货仓库" prop="warehouseId">
  109. <el-select v-model="form.warehouseId" placeholder="请选择" style="width: 100%" filterable>
  110. <el-option
  111. v-for="warehouse in warehouseList"
  112. :key="warehouse.id"
  113. :label="`${warehouse.warehouseCode},${warehouse.warehouseName}`"
  114. :value="warehouse.id"
  115. />
  116. </el-select>
  117. </el-form-item>
  118. </el-col>
  119. <el-col :span="8">
  120. <el-form-item label="费用类型" prop="expenseType">
  121. <el-select v-model="form.expenseType" placeholder="请选择" style="width: 100%">
  122. <el-option v-for="dict in fee_type" :key="dict.value" :label="dict.label" :value="dict.value" />
  123. </el-select>
  124. </el-form-item>
  125. </el-col>
  126. <el-col :span="8">
  127. <el-form-item label="下单部门" prop="userDept">
  128. <el-select v-model="form.userDept" placeholder="请选择" style="width: 100%" :disabled="!form.customerId">
  129. <el-option v-for="dept in customerDeptList" :key="dept.id" :label="dept.deptName" :value="dept.id" />
  130. </el-select>
  131. </el-form-item>
  132. </el-col>
  133. </el-row>
  134. <el-row :gutter="20">
  135. <!-- 第六行 -->
  136. <el-col :span="24">
  137. <el-form-item label="采购事由" prop="purchaseReason">
  138. <el-input v-model="form.purchaseReason" placeholder="请输入采购事由" type="textarea" :rows="2" />
  139. </el-form-item>
  140. </el-col>
  141. </el-row>
  142. <el-row :gutter="20">
  143. <!-- 第七行 -->
  144. <el-col :span="24">
  145. <el-form-item label="订单备注" prop="remark">
  146. <el-input v-model="form.remark" placeholder="请输入订单备注" type="textarea" :rows="2" />
  147. </el-form-item>
  148. </el-col>
  149. </el-row>
  150. <el-row :gutter="20">
  151. <!-- 第八行 -->
  152. <el-col :span="24">
  153. <el-form-item label="附件" prop="attachmentPath">
  154. <el-upload class="upload-demo" action="#" :auto-upload="false">
  155. <el-button type="primary" plain>上传附件</el-button>
  156. </el-upload>
  157. </el-form-item>
  158. </el-col>
  159. </el-row>
  160. </el-form>
  161. </el-card>
  162. <!-- 收货地址 -->
  163. <el-card shadow="never" class="mb-2">
  164. <template #header>
  165. <div class="card-header">
  166. <span>收货地址</span>
  167. <div>
  168. <el-button type="primary" plain @click="addAddress">添加收货地址</el-button>
  169. <el-button type="primary" plain @click="chooseAddress">选择收货地址</el-button>
  170. </div>
  171. </div>
  172. </template>
  173. <el-form :model="form" label-width="100px">
  174. <el-row :gutter="20">
  175. <el-col :span="8">
  176. <el-form-item label="收货人姓名">
  177. <el-input v-model="addressDisplay.receiverName" disabled />
  178. </el-form-item>
  179. </el-col>
  180. <el-col :span="8">
  181. <el-form-item label="手机号码">
  182. <el-input v-model="addressDisplay.receiverPhone" disabled />
  183. </el-form-item>
  184. </el-col>
  185. </el-row>
  186. <el-row :gutter="20">
  187. <el-col :span="8">
  188. <el-form-item label="详细地址">
  189. <el-input v-model="addressDisplay.receiverProvince" disabled />
  190. </el-form-item>
  191. </el-col>
  192. <el-col :span="8">
  193. <el-form-item>
  194. <el-input v-model="addressDisplay.addressDetail" disabled />
  195. </el-form-item>
  196. </el-col>
  197. </el-row>
  198. </el-form>
  199. </el-card>
  200. <!-- 商品明细 -->
  201. <el-card shadow="never" class="mb-2">
  202. <template #header>
  203. <div class="card-header">
  204. <span>商品明细</span>
  205. <div>
  206. <el-button type="primary" plain @click="handleAddProduct">添加商品</el-button>
  207. <el-button type="primary" plain>导入</el-button>
  208. </div>
  209. </div>
  210. </template>
  211. <el-table :data="productList" border style="width: 100%">
  212. <el-table-column prop="productCode" label="产品编码" width="130" align="center" />
  213. <el-table-column label="商品图片" align="center">
  214. <template #default="scope">
  215. <el-image v-if="scope.row.productImage" :src="scope.row.productImage" style="width: 60px; height: 60px" fit="cover" />
  216. <span v-else>暂无图片</span>
  217. </template>
  218. </el-table-column>
  219. <el-table-column prop="productName" label="产品信息" align="center" />
  220. <el-table-column prop="taxRate" label="税率" align="center">
  221. <template #default="scope"> 增值税{{ scope.row.taxRate }}% </template>
  222. </el-table-column>
  223. <el-table-column prop="unit" label="单位" align="center" />
  224. <el-table-column prop="price" label="单价" align="center" />
  225. <el-table-column prop="certificatePrice" label="最低售价" align="center" />
  226. <el-table-column prop="minOrderQuantity" label="起订量" align="center" />
  227. <el-table-column prop="unitPrice" label="含税单价" align="center">
  228. <template #default="scope">
  229. <el-input-number
  230. v-model="scope.row.unitPrice"
  231. :min="scope.row.certificatePrice"
  232. :precision="2"
  233. :controls="false"
  234. @blur="handleUnitPriceChange(scope.$index)"
  235. />
  236. </template>
  237. </el-table-column>
  238. <el-table-column prop="quantity" label="数量" align="center">
  239. <template #default="scope">
  240. <el-input-number
  241. v-model="scope.row.quantity"
  242. :min="scope.row.minOrderQuantity || 1"
  243. :precision="0"
  244. :controls="false"
  245. @change="handleQuantityChange(scope.$index)"
  246. />
  247. </template>
  248. </el-table-column>
  249. <el-table-column prop="amount" label="小计" align="center" />
  250. <el-table-column label="操作" align="center">
  251. <template #default="scope">
  252. <el-button link type="danger" size="small" @click="handleDeleteProduct(scope.$index)">删除</el-button>
  253. </template>
  254. </el-table-column>
  255. </el-table>
  256. <div class="mt-2 text-right">
  257. <span>商品数:{{ totalQuantity }} 合计金额:¥ {{ totalAmount.toFixed(2) }}</span>
  258. </div>
  259. </el-card>
  260. <!-- 信息汇总 -->
  261. <el-card shadow="never" class="mb-2">
  262. <template #header>
  263. <div class="card-header">
  264. <span>信息汇总</span>
  265. </div>
  266. </template>
  267. <el-table :data="summaryData" border style="width: 100%">
  268. <el-table-column prop="quantity" label="商品数量" align="center" />
  269. <el-table-column prop="shippingFee" label="运费" align="center" />
  270. <el-table-column prop="totalAmount" label="订单总金额" align="center" />
  271. <el-table-column prop="payableAmount" label="应付款金额" align="center" />
  272. </el-table>
  273. </el-card>
  274. <!-- 底部按钮 -->
  275. <div class="text-center mt-4">
  276. <el-button @click="cancel">取消</el-button>
  277. <el-button type="primary" :loading="buttonLoading" @click="submitForm">确定</el-button>
  278. </div>
  279. <!-- 选择地址对话框 -->
  280. <ChooseAddress v-model="showAddressDialog" :customer-id="form.customerId" :address-list="addressList" @confirm="handleAddressConfirm" />
  281. <!-- 添加地址对话框 -->
  282. <AddAddress v-model="showAddAddressDialog" :customer-id="form.customerId" @success="handleAddAddressSuccess" />
  283. <!-- 选择商品对话框 -->
  284. <ChooseProduct v-model="showProductDialog" @confirm="handleProductConfirm" />
  285. </div>
  286. </template>
  287. <script setup name="OrderMain" lang="ts">
  288. import { listOrderMain, getOrderMain, delOrderMain, addOrderMain, updateOrderMain } from '@/api/order/orderMain';
  289. import { OrderMainVO, OrderMainQuery, OrderMainForm } from '@/api/order/orderMain/types';
  290. import { listCompany } from '@/api/company/company';
  291. import { listCustomerDept } from '@/api/customer/customerFile/customerDept';
  292. import { CustomerDeptVO } from '@/api/customer/customerFile/customerDept/types';
  293. import { CompanyVO } from '@/api/company/company/types';
  294. import { listWarehouse, getWarehouse } from '@/api/company/warehouse';
  295. import { WarehouseVO, WarehouseQuery } from '@/api/company/warehouse/types';
  296. import { listCustomerInfo, getCustomerInfo } from '@/api/customer/customerFile/customerInfo';
  297. import { CustomerInfoVO, CustomerInfoQuery, CustomerInfoForm } from '@/api/customer/customerFile/customerInfo/types';
  298. import { listShippingAddress } from '@/api/customer/customerFile/shippingAddress';
  299. import { ShippingAddressVO, ShippingAddressQuery } from '@/api/customer/customerFile/shippingAddress/types';
  300. import ChooseAddress from './components/chooseAddress.vue';
  301. import AddAddress from './components/addressDialog.vue';
  302. import ChooseProduct from './components/chooseProduct.vue';
  303. import { BaseVO } from '@/api/product/base/types';
  304. const { proxy } = getCurrentInstance() as ComponentInternalInstance;
  305. const { order_status, fee_type, pay_method } = toRefs<any>(proxy?.useDict('order_status', 'fee_type', 'pay_method'));
  306. import { regionData } from 'element-china-area-data';
  307. const buttonLoading = ref(false);
  308. const loading = ref(true);
  309. const ids = ref<Array<string | number>>([]);
  310. const single = ref(true);
  311. const multiple = ref(true);
  312. const router = useRouter();
  313. const queryFormRef = ref<ElFormInstance>();
  314. const orderMainFormRef = ref<ElFormInstance>();
  315. const dialog = reactive<DialogOption>({
  316. visible: false,
  317. title: ''
  318. });
  319. // 商品列表数据
  320. const productList = ref([]);
  321. // 地址选择对话框
  322. const showAddressDialog = ref(false);
  323. // 添加地址对话框
  324. const showAddAddressDialog = ref(false);
  325. // 选择商品对话框
  326. const showProductDialog = ref(false);
  327. // 计算商品总数(所有商品的数量之和)
  328. const totalQuantity = computed(() => {
  329. return productList.value.reduce((sum, item) => {
  330. return sum + (Number(item.quantity) || 0);
  331. }, 0);
  332. });
  333. // 计算商品总金额(所有商品的小计之和)
  334. const totalAmount = computed(() => {
  335. return productList.value.reduce((sum, item) => {
  336. return sum + (Number(item.amount) || 0);
  337. }, 0);
  338. });
  339. // 计算应付款金额(订单总金额 + 运费)
  340. const payableAmount = computed(() => {
  341. const shipping = Number(form.value.shippingFee) || 0;
  342. return totalAmount.value + shipping;
  343. });
  344. // 汇总数据(用于表格显示)
  345. const summaryData = computed(() => {
  346. return [
  347. {
  348. quantity: totalQuantity.value,
  349. shippingFee: `¥${(Number(form.value.shippingFee) || 0).toFixed(2)}`,
  350. totalAmount: `¥${totalAmount.value.toFixed(2)}`,
  351. payableAmount: `¥${payableAmount.value.toFixed(2)}`
  352. }
  353. ];
  354. });
  355. // 公司列表
  356. const companyList = ref<CompanyVO[]>([]);
  357. // 仓库列表
  358. const warehouseList = ref<WarehouseVO[]>([]);
  359. // 客户列表
  360. const customerList = ref<CustomerInfoVO[]>([]);
  361. const customerLoading = ref(false);
  362. // 客户部门列表
  363. const customerDeptList = ref<CustomerDeptVO[]>([]);
  364. const addressList = ref<ShippingAddressVO[]>([]);
  365. // 收货地址显示信息(仅用于显示,不提交)
  366. const addressDisplay = ref({
  367. receiverName: '',
  368. receiverPhone: '',
  369. receiverProvince: '',
  370. addressDetail: ''
  371. });
  372. // 禁用预收货日期的函数(只能选择订单日期之后的日期)
  373. const disabledDeliveryDate = (time: Date) => {
  374. if (!form.value.orderTime) {
  375. // 如果没有选择订单日期,禁用今天之前的日期
  376. return time.getTime() < Date.now() - 8.64e7;
  377. }
  378. // 将订单日期转换为时间戳进行比较
  379. const orderDate = new Date(form.value.orderTime);
  380. orderDate.setHours(0, 0, 0, 0);
  381. const compareTime = time.getTime();
  382. const orderTime = orderDate.getTime();
  383. // 禁用订单日期及之前的日期
  384. return compareTime <= orderTime;
  385. };
  386. const initFormData: OrderMainForm = {
  387. id: undefined,
  388. orderNo: undefined,
  389. shipmentNo: undefined,
  390. subOrderNo: undefined,
  391. companyId: undefined,
  392. customerId: undefined,
  393. customerCode: undefined,
  394. userId: undefined,
  395. shippingAddressId: undefined,
  396. purchaseReason: undefined,
  397. invoiceType: undefined,
  398. payType: '0',
  399. warehouseId: undefined,
  400. creditLimit: undefined,
  401. expectedDeliveryTime: undefined,
  402. businessStaff: undefined,
  403. customerService: undefined,
  404. businessDept: undefined,
  405. userDept: undefined,
  406. productQuantity: undefined,
  407. shippingFee: undefined,
  408. totalAmount: undefined,
  409. payableAmount: undefined,
  410. paymentStatus: undefined,
  411. orderSource: '1',
  412. orderStatus: undefined,
  413. orderTime: new Date().toISOString().split('T')[0], // 默认今天,格式:YYYY-MM-DD
  414. confirmTime: undefined,
  415. shippingTime: undefined,
  416. receivingTime: undefined,
  417. shippedQuantity: undefined,
  418. unshippedQuantity: undefined,
  419. packageCount: undefined,
  420. signedQuantity: undefined,
  421. afterSaleCompleted: undefined,
  422. afterSalePending: undefined,
  423. deliveryDesc: undefined,
  424. pushStatus: undefined,
  425. attachmentPath: undefined,
  426. deliveryType: undefined,
  427. orderCategory: undefined,
  428. productCode: undefined,
  429. cancelReason: undefined,
  430. expenseType: undefined,
  431. userNo: undefined,
  432. status: undefined,
  433. remark: undefined,
  434. customerSalesInfoVo: {
  435. salesPerson: '',
  436. serviceStaff: '',
  437. belongingDepartment: ''
  438. }
  439. };
  440. const data = reactive<PageData<OrderMainForm, OrderMainQuery>>({
  441. form: { ...initFormData },
  442. queryParams: {
  443. pageNum: 1,
  444. pageSize: 10,
  445. orderNo: undefined,
  446. shipmentNo: undefined,
  447. subOrderNo: undefined,
  448. companyId: undefined,
  449. customerId: undefined,
  450. customerCode: undefined,
  451. userId: undefined,
  452. shippingAddressId: undefined,
  453. params: {}
  454. },
  455. rules: {
  456. companyId: [{ required: true, message: '归属公司不能为空', trigger: 'blur' }],
  457. customerId: [{ required: true, message: '客户名称不能为空', trigger: 'blur' }],
  458. payType: [{ required: true, message: '支付方式不能为空', trigger: 'change' }],
  459. warehouseId: [{ required: true, message: '发货仓库不能为空', trigger: 'change' }],
  460. expectedDeliveryTime: [{ required: true, message: '预计送达时间不能为空', trigger: 'blur' }],
  461. shippingFee: [{ required: true, message: '运费不能为空', trigger: 'blur' }],
  462. confirmTime: [{ required: true, message: '确认时间不能为空', trigger: 'blur' }],
  463. shippingTime: [{ required: true, message: '发货时间不能为空', trigger: 'blur' }],
  464. expenseType: [{ required: true, message: '费用类型不能为空', trigger: 'change' }],
  465. purchaseReason: [{ required: true, message: '采购事由不能为空', trigger: 'change' }]
  466. }
  467. });
  468. const { queryParams, form, rules } = toRefs(data);
  469. // 监听公司变化,加载该公司的客户列表
  470. watch(
  471. () => form.value.companyId,
  472. (newVal, oldVal) => {
  473. if (newVal !== oldVal) {
  474. // 清空客户选择和相关信息
  475. form.value.customerId = undefined;
  476. form.value.customerCode = undefined;
  477. customerList.value = [];
  478. customerDeptList.value = [];
  479. form.value.creditLimit = undefined;
  480. form.value.shippingAddressId = undefined;
  481. form.value.userDept = undefined;
  482. form.value.businessStaff = undefined;
  483. form.value.customerService = undefined;
  484. form.value.businessDept = undefined;
  485. // 清空收货地址显示信息
  486. addressDisplay.value = {
  487. receiverName: '',
  488. receiverPhone: '',
  489. addressDetail: ''
  490. } as any;
  491. // 如果选择了公司,加载该公司的客户列表
  492. if (newVal) {
  493. loadCustomerListByCompany(newVal);
  494. }
  495. }
  496. }
  497. );
  498. /** 取消按钮 */
  499. const cancel = () => {
  500. reset();
  501. dialog.visible = false;
  502. };
  503. /** 表单重置 */
  504. const reset = () => {
  505. form.value = { ...initFormData };
  506. orderMainFormRef.value?.resetFields();
  507. };
  508. /** 搜索按钮操作 */
  509. const handleQuery = () => {
  510. queryParams.value.pageNum = 1;
  511. };
  512. /** 重置按钮操作 */
  513. const resetQuery = () => {
  514. queryFormRef.value?.resetFields();
  515. handleQuery();
  516. };
  517. /** 多选框选中数据 */
  518. const handleSelectionChange = (selection: OrderMainVO[]) => {
  519. ids.value = selection.map((item) => item.id);
  520. single.value = selection.length != 1;
  521. multiple.value = !selection.length;
  522. };
  523. /** 新增按钮操作 */
  524. const handleAdd = () => {
  525. reset();
  526. dialog.visible = true;
  527. dialog.title = '添加订单主信息';
  528. };
  529. /** 修改按钮操作 */
  530. const handleUpdate = async (row?: OrderMainVO) => {
  531. reset();
  532. const _id = row?.id || ids.value[0];
  533. const res = await getOrderMain(_id);
  534. Object.assign(form.value, res.data);
  535. dialog.visible = true;
  536. dialog.title = '修改订单主信息';
  537. };
  538. /** 提交按钮 */
  539. const submitForm = () => {
  540. orderMainFormRef.value?.validate(async (valid: boolean) => {
  541. if (valid) {
  542. // 验证是否有商品
  543. if (!productList.value || productList.value.length === 0) {
  544. proxy?.$modal.msgWarning('请至少添加一个商品');
  545. return;
  546. }
  547. buttonLoading.value = true;
  548. try {
  549. // 组装订单商品明细数据
  550. const orderProductList = productList.value.map((product) => ({
  551. productId: product.id,
  552. productNo: product.productCode, // 产品编号
  553. productName: product.productName, // 产品名称
  554. productUnit: product.unit, // 产品单位
  555. productImage: product.productImage, // 产品图片
  556. platformPrice: product.price, // 平台价格(单价)
  557. minOrderQuantity: product.minOrderQuantity, // 最小起订量
  558. orderPrice: product.unitPrice, // 订单单价(含税单价)
  559. orderQuantity: product.quantity, // 订购数量
  560. subtotal: product.amount, // 行小计金额
  561. minSellingPrice: product.certificatePrice, // 最低销售价
  562. preDeliveryDate: form.value.expectedDeliveryTime, // 预计送达时间
  563. status: '0' // 状态(0正常)
  564. }));
  565. if (form.value.payType == '0') {
  566. //如果选项信用支付 则订单状态为待发货
  567. form.value.orderStatus = '2';
  568. }
  569. // 组装提交数据
  570. const submitData = {
  571. ...form.value,
  572. productQuantity: totalQuantity.value, // 商品总数量
  573. totalAmount: totalAmount.value, // 订单总金额
  574. payableAmount: payableAmount.value, // 应付金额
  575. shippingFee: Number(form.value.shippingFee) || 0, // 运费
  576. orderProductBos: orderProductList // 订单商品明细列表
  577. };
  578. if (form.value.id) {
  579. await updateOrderMain(submitData);
  580. } else {
  581. await addOrderMain(submitData);
  582. }
  583. proxy?.$modal.msgSuccess('操作成功');
  584. // 可以在这里添加跳转逻辑,比如返回列表页
  585. router.push('/order-center/order-list');
  586. } catch (error) {
  587. console.error('提交订单失败:', error);
  588. proxy?.$modal.msgError('提交订单失败,请检查数据后重试');
  589. } finally {
  590. buttonLoading.value = false;
  591. }
  592. }
  593. });
  594. };
  595. /** 删除按钮操作 */
  596. const handleDelete = async (row?: OrderMainVO) => {
  597. const _ids = row?.id || ids.value;
  598. await proxy?.$modal.confirm('是否确认删除订单主信息编号为"' + _ids + '"的数据项?').finally(() => (loading.value = false));
  599. await delOrderMain(_ids);
  600. proxy?.$modal.msgSuccess('删除成功');
  601. };
  602. /** 导出按钮操作 */
  603. const handleExport = () => {
  604. proxy?.download(
  605. 'system/orderMain/export',
  606. {
  607. ...queryParams.value
  608. },
  609. `orderMain_${new Date().getTime()}.xlsx`
  610. );
  611. };
  612. /** 选择收货地址 */
  613. const chooseAddress = () => {
  614. if (!form.value.customerId) {
  615. proxy?.$modal.msgWarning('请先选择客户');
  616. return;
  617. }
  618. showAddressDialog.value = true;
  619. };
  620. /** 添加收货地址 */
  621. const addAddress = () => {
  622. if (!form.value.customerId) {
  623. proxy?.$modal.msgWarning('请先选择客户');
  624. return;
  625. }
  626. showAddAddressDialog.value = true;
  627. };
  628. /** 添加地址成功回调 */
  629. const handleAddAddressSuccess = () => {
  630. proxy?.$modal.msgSuccess('添加地址成功');
  631. };
  632. /** 打开添加商品对话框 */
  633. const handleAddProduct = () => {
  634. showProductDialog.value = true;
  635. };
  636. /** 确认选择商品 */
  637. const handleProductConfirm = (product: BaseVO) => {
  638. // 将商品添加到商品列表,按照新的字段映射
  639. const newProduct = {
  640. id: product.id,
  641. productCode: product.productNo, // 产品编码
  642. productImage: product.productImage, // 商品图片
  643. productName: product.itemName, // 产品信息
  644. taxRate: product.taxRate || 0, // 税率
  645. unit: product.unitId, // 单位
  646. price: product.standardPrice || 0, // 单价(使用平档价)
  647. certificatePrice: product.certificatePrice || 0, // 最低售价
  648. minOrderQuantity: product.minOrderQuantity || 1, // 起订量
  649. unitPrice: product.certificatePrice || 0, // 含税单价(默认使用最低售价)
  650. quantity: product.minOrderQuantity || 1, // 数量(默认使用起订量)
  651. amount: ((product.certificatePrice || 0) * (product.minOrderQuantity || 1)).toFixed(2) // 小计 = 含税单价 × 数量
  652. };
  653. productList.value.push(newProduct);
  654. proxy?.$modal.msgSuccess('添加商品成功');
  655. };
  656. /** 删除商品 */
  657. const handleDeleteProduct = (index: number) => {
  658. productList.value.splice(index, 1);
  659. proxy?.$modal.msgSuccess('删除成功');
  660. };
  661. /** 含税单价变化时验证最低售价 */
  662. const handleUnitPriceChange = (index: number) => {
  663. const product = productList.value[index];
  664. if (product) {
  665. // 如果含税单价小于最低售价,自动设置为最低售价
  666. if (Number(product.unitPrice) < Number(product.certificatePrice)) {
  667. product.unitPrice = product.certificatePrice;
  668. }
  669. // 重新计算小计:小计 = 数量 × 含税单价
  670. product.amount = (Number(product.quantity) * Number(product.unitPrice)).toFixed(2);
  671. }
  672. };
  673. /** 数量变化时重新计算金额 */
  674. const handleQuantityChange = (index: number) => {
  675. const product = productList.value[index];
  676. if (product) {
  677. // 小计 = 数量 × 含税单价
  678. product.amount = (Number(product.quantity) * Number(product.unitPrice)).toFixed(2);
  679. }
  680. };
  681. /** 确认选择地址 */
  682. const handleAddressConfirm = (address: ShippingAddressVO) => {
  683. form.value.shippingAddressId = address.id;
  684. // 更新地址显示信息
  685. addressDisplay.value = {
  686. receiverName: address.consignee,
  687. receiverPhone: address.phone,
  688. receiverProvince: address.provincialCityCountry,
  689. addressDetail: address.address
  690. };
  691. };
  692. /** 获取公司列表 */
  693. const getCompanyList = async () => {
  694. try {
  695. const res = await listCompany({
  696. isShow: '0',
  697. pageNum: 1,
  698. pageSize: 1000
  699. });
  700. companyList.value = res.rows || [];
  701. } catch (error) {
  702. console.error('获取公司列表失败:', error);
  703. companyList.value = [];
  704. }
  705. };
  706. /** 获取仓库列表 */
  707. const getWarehouseList = async () => {
  708. try {
  709. const res = await listWarehouse({
  710. isShow: '0',
  711. pageNum: 1,
  712. pageSize: 1000
  713. });
  714. warehouseList.value = res.rows || [];
  715. } catch (error) {
  716. console.error('获取仓库列表失败:', error);
  717. warehouseList.value = [];
  718. }
  719. };
  720. /** 根据公司ID加载客户列表 */
  721. const loadCustomerListByCompany = async (companyId: string | number) => {
  722. customerLoading.value = true;
  723. try {
  724. const params: CustomerInfoQuery = {
  725. belongCompanyId: companyId,
  726. pageNum: 1,
  727. pageSize: 1000 // 加载所有客户
  728. };
  729. const res = await listCustomerInfo(params);
  730. customerList.value = res.rows || [];
  731. } catch (error) {
  732. console.error('加载客户列表失败:', error);
  733. customerList.value = [];
  734. } finally {
  735. customerLoading.value = false;
  736. }
  737. };
  738. /** 客户变化时获取客户详情 */
  739. const handleCustomerChange = async (customerId: string | number) => {
  740. if (!customerId) {
  741. // 清空客户相关信息
  742. form.value.creditLimit = undefined;
  743. form.value.shippingAddressId = undefined;
  744. form.value.userDept = undefined;
  745. form.value.businessStaff = undefined;
  746. form.value.customerService = undefined;
  747. form.value.businessDept = undefined;
  748. customerDeptList.value = [];
  749. // 清空收货地址显示信息
  750. addressDisplay.value = {
  751. receiverName: '',
  752. receiverPhone: '',
  753. addressDetail: ''
  754. } as any;
  755. return;
  756. }
  757. try {
  758. // 获取客户详情
  759. const res = await getCustomerInfo(customerId);
  760. const customerInfo = res.data;
  761. form.value.customerCode = customerInfo.customerNo;
  762. // 填充客户相关信息
  763. if (customerInfo.customerSalesInfoVo) {
  764. const salesInfo = customerInfo.customerSalesInfoVo;
  765. form.value.creditLimit = salesInfo.remainingQuota || salesInfo.creditAmount;
  766. // 填充业务人员、客服人员、业务部门
  767. form.value.businessStaff = salesInfo.salesPerson;
  768. form.value.customerService = salesInfo.serviceStaff;
  769. form.value.businessDept = salesInfo.belongingDepartment;
  770. }
  771. // 获取客户部门列表
  772. await getCustomerDeptList(customerId);
  773. // 获取客户收货地址列表
  774. await loadAddressList(customerId);
  775. } catch (error) {
  776. console.error('获取客户详情失败:', error);
  777. }
  778. };
  779. /** 获取客户部门列表 */
  780. const getCustomerDeptList = async (customerId: string | number) => {
  781. try {
  782. const res = await listCustomerDept({
  783. customerId: customerId
  784. });
  785. customerDeptList.value = res.rows || [];
  786. } catch (error) {
  787. console.error('获取客户部门列表失败:', error);
  788. customerDeptList.value = [];
  789. }
  790. };
  791. // 加载地址列表
  792. const loadAddressList = async (customerId: string | number) => {
  793. if (!customerId) {
  794. addressList.value = [];
  795. return;
  796. }
  797. try {
  798. const queryParams: any = {
  799. customerId: customerId
  800. };
  801. const res = await listShippingAddress(queryParams);
  802. addressList.value = res.rows || [];
  803. console.log(addressList.value);
  804. } catch (error) {
  805. console.error('加载地址列表失败:', error);
  806. addressList.value = [];
  807. }
  808. };
  809. onMounted(() => {
  810. getCompanyList();
  811. getWarehouseList();
  812. });
  813. </script>
  814. <style scoped lang="scss">
  815. .order-steps {
  816. padding: 10px 0;
  817. .step-title {
  818. font-size: 16px;
  819. font-weight: bold;
  820. color: #303133;
  821. }
  822. }
  823. .card-header {
  824. display: flex;
  825. justify-content: space-between;
  826. align-items: center;
  827. font-weight: bold;
  828. }
  829. .mb-2 {
  830. margin-bottom: 16px;
  831. }
  832. .mt-2 {
  833. margin-top: 16px;
  834. }
  835. .mt-4 {
  836. margin-top: 32px;
  837. }
  838. .text-right {
  839. text-align: right;
  840. }
  841. .text-center {
  842. text-align: center;
  843. }
  844. :deep(.el-form-item__label) {
  845. font-weight: normal;
  846. }
  847. :deep(.el-card__header) {
  848. padding: 12px 20px;
  849. background-color: #f5f7fa;
  850. }
  851. </style>