소스 검색

feat(order): 实现批量订单导入和提交功能

- 添加 Excel 文件导入功能,支持商品编号和数量解析
- 集成 xlsx 库实现 Excel 文件读取和解析
- 实现导入模板下载功能
- 添加导入按钮加载状态显示
- 实现订单提交功能,包括收货地址选择
- 重构订单提交接口调用逻辑
- 添加 Element Plus 中文语言包支持
- 更新订单流程相关 API 参数类型支持字符串 ID
- 移除不必要的地区数据依赖包
- 添加 Place Order Type 字段标识下单方式
肖路 1 개월 전
부모
커밋
b92a4f71fe
8개의 변경된 파일320개의 추가작업 그리고 99개의 파일을 삭제
  1. 105 17
      package-lock.json
  2. 2 1
      package.json
  3. 1 2
      src/api/goods/index.ts
  4. 4 4
      src/api/pc/enterprise/order.ts
  5. 9 0
      src/main.ts
  6. 197 75
      src/views/order/batchOrder/index.vue
  7. BIN
      src/views/order/batchOrder/商品导入模版.xlsx
  8. 2 0
      src/views/trad/index.vue

+ 105 - 17
package-lock.json

@@ -18,7 +18,6 @@
         "axios": "1.13.1",
         "crypto-js": "4.2.0",
         "echarts": "5.6.0",
-        "element-china-area-data": "^6.1.0",
         "element-plus": "2.11.7",
         "file-saver": "2.0.5",
         "highlight.js": "11.11.1",
@@ -34,7 +33,8 @@
         "vue-json-pretty": "2.6.0",
         "vue-router": "4.6.3",
         "vue-types": "6.0.0",
-        "vxe-table": "4.17.7"
+        "vxe-table": "4.17.7",
+        "xlsx": "^0.18.5"
       },
       "devDependencies": {
         "@iconify/json": "^2.2.403",
@@ -3515,6 +3515,15 @@
         "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0"
       }
     },
+    "node_modules/adler-32": {
+      "version": "1.3.1",
+      "resolved": "https://registry.npmmirror.com/adler-32/-/adler-32-1.3.1.tgz",
+      "integrity": "sha512-ynZ4w/nUUv5rrsR8UUGoe1VC9hZj6V5hU9Qw1HlMDJGEJw5S7TfTErWTjMys6M7vr0YWcPqs3qAr4ss0nDfP+A==",
+      "license": "Apache-2.0",
+      "engines": {
+        "node": ">=0.8"
+      }
+    },
     "node_modules/ajv": {
       "version": "6.12.6",
       "resolved": "https://registry.npmmirror.com/ajv/-/ajv-6.12.6.tgz",
@@ -3819,6 +3828,19 @@
         }
       ]
     },
+    "node_modules/cfb": {
+      "version": "1.2.2",
+      "resolved": "https://registry.npmmirror.com/cfb/-/cfb-1.2.2.tgz",
+      "integrity": "sha512-KfdUZsSOw19/ObEWasvBP/Ac4reZvAGauZhs6S/gqNhXhI7cKwvlH7ulj+dOEYnca4bm4SGo8C1bTAQvnTjgQA==",
+      "license": "Apache-2.0",
+      "dependencies": {
+        "adler-32": "~1.3.0",
+        "crc-32": "~1.2.0"
+      },
+      "engines": {
+        "node": ">=0.8"
+      }
+    },
     "node_modules/chai": {
       "version": "5.3.3",
       "resolved": "https://registry.npmmirror.com/chai/-/chai-5.3.3.tgz",
@@ -3860,12 +3882,6 @@
         "node": ">= 16"
       }
     },
-    "node_modules/china-division": {
-      "version": "2.7.0",
-      "resolved": "https://registry.npmjs.org/china-division/-/china-division-2.7.0.tgz",
-      "integrity": "sha512-4uUPAT+1WfqDh5jytq7omdCmHNk3j+k76zEG/2IqaGcYB90c2SwcixttcypdsZ3T/9tN1TTpBDoeZn+Yw/qBEA==",
-      "license": "MIT"
-    },
     "node_modules/chokidar": {
       "version": "4.0.3",
       "resolved": "https://registry.npmmirror.com/chokidar/-/chokidar-4.0.3.tgz",
@@ -3881,6 +3897,15 @@
         "url": "https://paulmillr.com/funding/"
       }
     },
+    "node_modules/codepage": {
+      "version": "1.15.0",
+      "resolved": "https://registry.npmmirror.com/codepage/-/codepage-1.15.0.tgz",
+      "integrity": "sha512-3g6NUTPd/YtuuGrhMnOMRjFc+LJw/bnMp3+0r/Wcz3IXUuCosKRJvMphm5+Q+bvTVGcJJuRvVLuYba+WojaFaA==",
+      "license": "Apache-2.0",
+      "engines": {
+        "node": ">=0.8"
+      }
+    },
     "node_modules/color-convert": {
       "version": "2.0.1",
       "resolved": "https://registry.npmmirror.com/color-convert/-/color-convert-2.0.1.tgz",
@@ -3966,6 +3991,18 @@
         "url": "https://github.com/sponsors/mesqueeb"
       }
     },
+    "node_modules/crc-32": {
+      "version": "1.2.2",
+      "resolved": "https://registry.npmmirror.com/crc-32/-/crc-32-1.2.2.tgz",
+      "integrity": "sha512-ROmzCKrTnOwybPcJApAA6WBWij23HVfGVNKqqrZpuyZOHqK2CwHSvpGuyt/UNNvaIjEd8X5IFGp4Mh+Ie1IHJQ==",
+      "license": "Apache-2.0",
+      "bin": {
+        "crc32": "bin/crc32.njs"
+      },
+      "engines": {
+        "node": ">=0.8"
+      }
+    },
     "node_modules/cross-spawn": {
       "version": "7.0.6",
       "resolved": "https://registry.npmmirror.com/cross-spawn/-/cross-spawn-7.0.6.tgz",
@@ -4283,15 +4320,6 @@
       "integrity": "sha512-0Drusm6MVRXSOJpGbaSVgcQsuB4hEkMpHXaVstcPmhu5LIedxs1xNK/nIxmQIU/RPC0+1/o0AVZfBTkTNJOdUw==",
       "dev": true
     },
-    "node_modules/element-china-area-data": {
-      "version": "6.1.0",
-      "resolved": "https://registry.npmjs.org/element-china-area-data/-/element-china-area-data-6.1.0.tgz",
-      "integrity": "sha512-IkpcjwQv2A/2AxFiSoaISZ+oMw1rZCPUSOg5sOCwT5jKc96TaawmKZeY81xfxXsO0QbKxU5LLc6AirhG52hUmg==",
-      "license": "MIT",
-      "dependencies": {
-        "china-division": "^2.7.0"
-      }
-    },
     "node_modules/element-plus": {
       "version": "2.11.7",
       "resolved": "https://registry.npmmirror.com/element-plus/-/element-plus-2.11.7.tgz",
@@ -5047,6 +5075,15 @@
         "node": ">= 6"
       }
     },
+    "node_modules/frac": {
+      "version": "1.1.2",
+      "resolved": "https://registry.npmmirror.com/frac/-/frac-1.1.2.tgz",
+      "integrity": "sha512-w/XBfkibaTl3YDqASwfDUqkna4Z2p9cFSr1aHDt0WoMTECnRfBOv2WArlZILlqgWlmdIlALXGpM2AOhEk5W3IA==",
+      "license": "Apache-2.0",
+      "engines": {
+        "node": ">=0.8"
+      }
+    },
     "node_modules/fraction.js": {
       "version": "4.3.7",
       "resolved": "https://registry.npmmirror.com/fraction.js/-/fraction.js-4.3.7.tgz",
@@ -6467,6 +6504,18 @@
         "node": ">=0.10.0"
       }
     },
+    "node_modules/ssf": {
+      "version": "0.11.2",
+      "resolved": "https://registry.npmmirror.com/ssf/-/ssf-0.11.2.tgz",
+      "integrity": "sha512-+idbmIXoYET47hH+d7dfm2epdOMUDjqcB4648sTZ+t2JwoyBFL/insLfB/racrDmsKB3diwsDA696pZMieAC5g==",
+      "license": "Apache-2.0",
+      "dependencies": {
+        "frac": "~1.1.2"
+      },
+      "engines": {
+        "node": ">=0.8"
+      }
+    },
     "node_modules/stackback": {
       "version": "0.0.2",
       "resolved": "https://registry.npmmirror.com/stackback/-/stackback-0.0.2.tgz",
@@ -7921,6 +7970,24 @@
         "node": ">=8"
       }
     },
+    "node_modules/wmf": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmmirror.com/wmf/-/wmf-1.0.2.tgz",
+      "integrity": "sha512-/p9K7bEh0Dj6WbXg4JG0xvLQmIadrner1bi45VMJTfnbVHsc7yIajZyoSoK60/dtVBs12Fm6WkUI5/3WAVsNMw==",
+      "license": "Apache-2.0",
+      "engines": {
+        "node": ">=0.8"
+      }
+    },
+    "node_modules/word": {
+      "version": "0.3.0",
+      "resolved": "https://registry.npmmirror.com/word/-/word-0.3.0.tgz",
+      "integrity": "sha512-OELeY0Q61OXpdUfTp+oweA/vtLVg5VDOXh+3he3PNzLGG/y0oylSOC1xRVj0+l4vQ3tj/bB1HVHv1ocXkQceFA==",
+      "license": "Apache-2.0",
+      "engines": {
+        "node": ">=0.8"
+      }
+    },
     "node_modules/word-wrap": {
       "version": "1.2.5",
       "resolved": "https://registry.npmmirror.com/word-wrap/-/word-wrap-1.2.5.tgz",
@@ -7950,6 +8017,27 @@
       "resolved": "https://registry.npmmirror.com/xe-utils/-/xe-utils-3.8.4.tgz",
       "integrity": "sha512-1X5k3nUcMatNo+99fZsHFrZ/WW4k4E6tT1ODO6wRncXOdq10QfVaqc70mFwOrHE/P1W8hDhbrnWXxSHwWY3rFQ=="
     },
+    "node_modules/xlsx": {
+      "version": "0.18.5",
+      "resolved": "https://registry.npmmirror.com/xlsx/-/xlsx-0.18.5.tgz",
+      "integrity": "sha512-dmg3LCjBPHZnQp5/F/+nnTa+miPJxUXB6vtk42YjBBKayDNagxGEeIdWApkYPOf3Z3pm3k62Knjzp7lMeTEtFQ==",
+      "license": "Apache-2.0",
+      "dependencies": {
+        "adler-32": "~1.3.0",
+        "cfb": "~1.2.1",
+        "codepage": "~1.15.0",
+        "crc-32": "~1.2.1",
+        "ssf": "~0.11.2",
+        "wmf": "~1.0.1",
+        "word": "~0.3.0"
+      },
+      "bin": {
+        "xlsx": "bin/xlsx.njs"
+      },
+      "engines": {
+        "node": ">=0.8"
+      }
+    },
     "node_modules/xml-name-validator": {
       "version": "4.0.0",
       "resolved": "https://registry.npmmirror.com/xml-name-validator/-/xml-name-validator-4.0.0.tgz",

+ 2 - 1
package.json

@@ -62,7 +62,8 @@
     "vue-json-pretty": "2.6.0",
     "vue-router": "4.6.3",
     "vue-types": "6.0.0",
-    "vxe-table": "4.17.7"
+    "vxe-table": "4.17.7",
+    "xlsx": "^0.18.5"
   },
   "devDependencies": {
     "@iconify/json": "^2.2.403",

+ 1 - 2
src/api/goods/index.ts

@@ -99,8 +99,7 @@ export const cancelProductCollect = (query: any) => {
   });
 };
 
-//取消收藏
-
+//提交订单
 export const pcOrdersubmit = (params: any) => {
   return request({
     url: '/order/pcOrder/submit',

+ 4 - 4
src/api/pc/enterprise/order.ts

@@ -170,7 +170,7 @@ export function updateOrderFlow(data: OrderCustomerFlowSaveBo) {
 /**
  * 删除订单流程
  */
-export function deleteOrderFlow(id: number) {
+export function deleteOrderFlow(id: number | string) {
   return request({
     url: `/order/pcOrderFlow/${id}`,
     method: 'delete'
@@ -191,7 +191,7 @@ export function auditOrderFlow(data: OrderCustomerFlowLinkBo) {
 /**
  * 查询订单流程详情
  */
-export function getOrderFlowDetail(id: number) {
+export function getOrderFlowDetail(id: number | string) {
   return request({
     url: `/order/pcOrderFlow/${id}`,
     method: 'get'
@@ -212,7 +212,7 @@ export function getOrderFlowList(params?: any) {
 /**
  * 开启订单流程
  */
-export function startOrderFlow(id: number) {
+export function startOrderFlow(id: number | string) {
   return request({
     url: `/order/pcOrderFlow/startFlow/${id}`,
     method: 'put'
@@ -222,7 +222,7 @@ export function startOrderFlow(id: number) {
 /**
  * 关闭订单流程
  */
-export function closeOrderFlow(id: number) {
+export function closeOrderFlow(id: number | string) {
   return request({
     url: `/order/pcOrderFlow/closeFlow/${id}`,
     method: 'put'

+ 9 - 0
src/main.ts

@@ -4,6 +4,10 @@ import 'virtual:uno.css';
 import 'element-plus/theme-chalk/dark/css-vars.css';
 import '@/assets/styles/index.scss';
 
+// Element Plus 中文语言包
+import zhCn from 'element-plus/dist/locale/zh-cn.mjs';
+import ElementPlus from 'element-plus';
+
 // App、router、store
 import App from './App.vue';
 import store from './store';
@@ -44,6 +48,11 @@ ElDialog.props.closeOnClickModal.default = false;
 
 const app = createApp(App);
 
+// 注册 Element Plus 并配置中文语言
+app.use(ElementPlus, {
+  locale: zhCn
+});
+
 app.use(HighLight);
 app.use(ElementIcons);
 app.use(router);

+ 197 - 75
src/views/order/batchOrder/index.vue

@@ -7,7 +7,9 @@
 
     <div class="action-bar">
       <el-button @click="handleDownloadTemplate">标准导入文件下载</el-button>
-      <el-button type="danger" @click="handleImportProducts">导入订单商品</el-button>
+      <el-button type="danger" @click="handleImportProducts" :loading="importing">导入订单商品</el-button>
+      <!-- 隐藏的文件输入框 -->
+      <input ref="fileInputRef" type="file" accept=".xlsx,.xls" style="display: none" @change="handleFileChange" />
     </div>
 
     <div class="section-title">商品信息</div>
@@ -31,16 +33,12 @@
         <div class="product-price">¥{{ item.price }}</div>
         <div class="product-quantity">{{ item.quantity }}</div>
         <div class="product-subtotal">¥{{ item.subtotal }}</div>
-        <div class="product-action">
-          <span v-if="item.offShelf" class="off-shelf">已下架</span>
-        </div>
       </div>
     </div>
 
     <div class="summary-info">
       共导入<em>{{ totalProducts }}</em
-      >件商品,不可下单商品<em>{{ unavailableProducts }}</em
-      >件
+      >件商品
     </div>
 
     <div class="address-section">
@@ -96,8 +94,7 @@
         >件商品
       </div>
       <div class="total-amount">
-        合计: <span class="amount">¥{{ totalAmount }}</span
-        ><span class="freight">(含运费{{ freight }}元)</span>
+        合计: <span class="amount">¥{{ totalAmount }}</span>
       </div>
       <el-button type="danger" size="large" @click="handleSubmitOrder">去下单</el-button>
     </div>
@@ -105,81 +102,52 @@
 </template>
 
 <script setup lang="ts">
-import { ref, computed } from 'vue';
+import { ref, computed, onMounted } from 'vue';
 import { useRouter } from 'vue-router';
 import { Picture, Location, Setting, ArrowDown } from '@element-plus/icons-vue';
 import { ElMessage } from 'element-plus';
+import * as XLSX from 'xlsx';
+import { getPcProductPage } from '@/api/search/index';
+import { getAddressList } from '@/api/pc/enterprise/index';
+import { pcOrdersubmit } from '@/api/goods/index';
+import templateFile from './商品导入模版.xlsx?url';
 
 const router = useRouter();
 const selectedAddress = ref(0);
 const showAllAddress = ref(false);
 const deliveryDate = ref('');
 const orderRemark = ref('');
+const importing = ref(false);
+const fileInputRef = ref<HTMLInputElement | null>(null);
+
+const productList = ref<any[]>([]);
+
+const addressList = ref<any[]>([]);
 
-const productList = ref([
-  {
-    id: 1,
-    image: '',
-    name: '清华同方超越E500台式机电脑(i3-6100/4G/1T/19.5寸)',
-    spec1: '规格02',
-    spec2: '规格01',
-    price: '181',
-    quantity: 1,
-    subtotal: '181',
-    offShelf: false
-  },
-  {
-    id: 2,
-    image: '',
-    name: '清华同方超越E500台式机电脑(i3-6100/4G/1T/19.5寸)',
-    spec1: '规格02',
-    spec2: '规格01',
-    price: '181',
-    quantity: 1,
-    subtotal: '181',
-    offShelf: true
-  },
-  {
-    id: 3,
-    image: '',
-    name: '清华同方超越E500台式机电脑(i3-6100/4G/1T/19.5寸)',
-    spec1: '规格02',
-    spec2: '规格01',
-    price: '181',
-    quantity: 1,
-    subtotal: '181',
-    offShelf: false
-  },
-  {
-    id: 4,
-    image: '',
-    name: '清华同方超越E500台式机电脑(i3-6100/4G/1T/19.5寸)',
-    spec1: '规格02',
-    spec2: '规格01',
-    price: '181',
-    quantity: 1,
-    subtotal: '181',
-    offShelf: false
-  },
-  {
-    id: 5,
-    image: '',
-    name: '清华同方超越E500台式机电脑(i3-6100/4G/1T/19.5寸)',
-    spec1: '规格02',
-    spec2: '规格01',
-    price: '181',
-    quantity: 1,
-    subtotal: '181',
-    offShelf: true
+const loadAddressList = async () => {
+  try {
+    const res: any = await getAddressList();
+    const list: any[] = res?.rows || res?.data || [];
+    addressList.value = list.map((item: any) => ({
+      ...item,
+      province: item.province || '',
+      city: item.city || '',
+      district: item.district || '',
+      detail: item.detailAddress || '',
+      company: item.consignee || '',
+      phone: item.phone || ''
+    }));
+    if (addressList.value.length > 0) {
+      selectedAddress.value = 0;
+    }
+  } catch (e) {
+    ElMessage.error('收货地址加载失败');
   }
-]);
+};
 
-const addressList = ref([
-  { province: '广东省', city: '广州市', district: '萝岗区科学城11号', detail: '', company: '中国南方电网有限公司', phone: '18062697722' },
-  { province: '广东省', city: '广州市', district: '萝岗区科学城11号', detail: '', company: '中国南方电网有限公司', phone: '18062697722' },
-  { province: '广东省', city: '广州市', district: '萝岗区科学城11号', detail: '', company: '中国南方电网有限公司', phone: '18062697722' },
-  { province: '广东省', city: '广州市', district: '萝岗区科学城11号', detail: '', company: '中国南方电网有限公司', phone: '18062697722' }
-]);
+onMounted(() => {
+  loadAddressList();
+});
 
 const totalProducts = computed(() => productList.value.length);
 const unavailableProducts = computed(() => productList.value.filter((p) => p.offShelf).length);
@@ -187,29 +155,183 @@ const availableProducts = computed(() => productList.value.filter((p) => !p.offS
 const totalAmount = computed(() =>
   productList.value
     .filter((p) => !p.offShelf)
-    .reduce((sum, p) => sum + parseFloat(p.subtotal), 0)
+    .reduce((sum, p) => sum + parseFloat(p.subtotal || '0'), 0)
     .toFixed(2)
 );
 const freight = ref('12.00');
 
+/** 下载标准导入模板 */
 const handleDownloadTemplate = () => {
+  const link = document.createElement('a');
+  link.href = templateFile;
+  link.download = '商品导入模版.xlsx';
+  document.body.appendChild(link);
+  link.click();
+  document.body.removeChild(link);
   ElMessage.success('开始下载模板文件');
 };
+
+/** 点击按钮触发文件选择 */
 const handleImportProducts = () => {
-  ElMessage.info('请选择要导入的文件');
+  fileInputRef.value?.click();
+};
+
+/** 解析 Excel 文件,提取商品编号和数量,调用接口查询商品信息 */
+const handleFileChange = async (event: Event) => {
+  const file = (event.target as HTMLInputElement).files?.[0];
+  if (!file) return;
+
+  // 重置 input,允许再次选择同一文件
+  (event.target as HTMLInputElement).value = '';
+
+  importing.value = true;
+  try {
+    const arrayBuffer = await file.arrayBuffer();
+    const workbook = XLSX.read(arrayBuffer, { type: 'array' });
+    const sheetName = workbook.SheetNames[0];
+    const worksheet = workbook.Sheets[sheetName];
+    // 从第1行(索引0)读取数据,转为对象数组(第一行为表头)
+    const rows: any[] = XLSX.utils.sheet_to_json(worksheet, { defval: '' });
+
+    if (rows.length === 0) {
+      ElMessage.warning('Excel 文件中没有数据');
+      return;
+    }
+
+    // 找到商品编号和商品数量对应的列名(兼容中英文列名)
+    const firstRow = rows[0];
+    const keys = Object.keys(firstRow);
+    const productNoKey = keys.find((k) => k.includes('商品编号') || k.toLowerCase().includes('productno') || k.toLowerCase() === 'no');
+    const quantityKey = keys.find(
+      (k) => k.includes('商品数量') || k.includes('数量') || k.toLowerCase().includes('quantity') || k.toLowerCase() === 'qty'
+    );
+
+    if (!productNoKey) {
+      ElMessage.error('未找到"商品编号"列,请检查模板格式');
+      return;
+    }
+    if (!quantityKey) {
+      ElMessage.error('未找到"商品数量"列,请检查模板格式');
+      return;
+    }
+
+    // 提取有效行(商品编号不为空)
+    const validRows = rows.filter((row) => row[productNoKey] !== '' && row[productNoKey] != null);
+    if (validRows.length === 0) {
+      ElMessage.warning('Excel 中没有有效的商品编号');
+      return;
+    }
+
+    // 逐个查询商品信息
+    const results: any[] = [];
+    for (const row of validRows) {
+      const productNo = String(row[productNoKey]).trim();
+      const quantity = Number(row[quantityKey]) || 1;
+      try {
+        const res = await getPcProductPage({ productNo, pageNum: 1, pageSize: 1 });
+        if (res.code === 200 && res.rows && res.rows.length > 0) {
+          const product = res.rows[0];
+          const price = String(product.price || product.memberPrice || product.minSellingPrice || '0');
+          const subtotal = (parseFloat(price) * quantity).toFixed(2);
+          results.push({
+            id: product.id,
+            image: product.productImage || '',
+            name: product.itemName || productNo,
+            spec1: product.productNo || productNo,
+            spec2: product.unitName || '',
+            price,
+            quantity,
+            subtotal,
+            offShelf: product.productStatus === '0'
+          });
+        } else {
+          // 接口未找到商品,提示下架但不加入列表
+          ElMessage.warning(`商品 ${productNo} 已下架或不存在,未加入当前订单`);
+        }
+      } catch {
+        ElMessage.warning(`商品 ${productNo} 查询失败,可能已下架,未加入当前订单`);
+      }
+    }
+
+    productList.value = results;
+    ElMessage.success(`成功导入 ${results.length} 件商品`);
+  } catch (e) {
+    ElMessage.error('文件解析失败,请检查文件格式');
+  } finally {
+    importing.value = false;
+  }
 };
+
 const handleConfirmAddress = () => {
   ElMessage.success('已确认收货地址');
 };
 const handleManageAddress = () => {
   router.push('/easybuv');
 };
-const handleSubmitOrder = () => {
+const handleSubmitOrder = async () => {
   if (availableProducts.value === 0) {
     ElMessage.warning('没有可下单的商品');
     return;
   }
-  ElMessage.success('订单提交成功');
+
+  if (selectedAddress.value === null || selectedAddress.value === undefined) {
+    ElMessage.warning('请选择收货地址');
+    return;
+  }
+
+  const address = addressList.value[selectedAddress.value];
+  if (!address || !address.id) {
+    ElMessage.warning('收货地址信息不完整');
+    return;
+  }
+
+  // 构建商品信息
+  const productInfo = productList.value
+    .filter((p) => !p.offShelf)
+    .map((p) => ({
+      productId: p.id,
+      productNum: p.quantity
+    }));
+
+  if (productInfo.length === 0) {
+    ElMessage.warning('没有可下单的商品');
+    return;
+  }
+
+  // 格式化配送时间
+  let deliveryDateStr = '';
+  if (deliveryDate.value) {
+    const date = new Date(deliveryDate.value);
+    deliveryDateStr = date.toISOString().split('T')[0]; // yyyy-MM-dd
+  }
+
+  const submitData = {
+    shippingAddressId: address.id,
+    deliveryDate: deliveryDateStr,
+    payType: '', // 支付方式,根据业务需求填写
+    expenseType: '', // 费用类型,根据业务需求填写
+    purchaseReason: '', // 采购事由,根据业务需求填写
+    remark: orderRemark.value,
+    shippingFee: parseFloat(freight.value) || 0,
+    placeOrderType: 2, // 2为直接下单
+    productShoppingCartId: [], // 批量下单不走购物车
+    productInfo: productInfo
+  };
+
+  try {
+    const res: any = await pcOrdersubmit(submitData);
+    if (res.code === 200) {
+      ElMessage.success('订单提交成功');
+      // 清空商品列表
+      productList.value = [];
+      // 可以跳转到订单列表页
+      // router.push('/order/list');
+    } else {
+      ElMessage.error(res.msg || '订单提交失败');
+    }
+  } catch (error: any) {
+    ElMessage.error(error?.message || '订单提交失败,请稍后重试');
+  }
 };
 </script>
 

BIN
src/views/order/batchOrder/商品导入模版.xlsx


+ 2 - 0
src/views/trad/index.vue

@@ -164,6 +164,8 @@ const form = ref<any>({
   purchaseReason: '',
   remark: '',
   shippingFee: 0,
+  // 下单方式  1为购物车下单  2为直接下单
+  placeOrderType: 1,
   productShoppingCartId: []
 });
 const options = [