addDrawer.vue 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786
  1. <template>
  2. <!-- 新增对账详情抽屉 -->
  3. <el-drawer v-model="drawer.visible" size="75%" direction="rtl" :before-close="handleDrawerClose" :close-on-click-modal="true">
  4. <template #header>
  5. <div class="drawer-header">
  6. <span class="order-title">新增对账</span>
  7. </div>
  8. </template>
  9. <div class="drawer-content">
  10. <el-form ref="formRef" :model="form" :rules="rules" label-width="120px">
  11. <!-- 基本信息 -->
  12. <el-divider content-position="left">
  13. <span style="color: #409eff; font-weight: 600">基本信息</span>
  14. </el-divider>
  15. <el-row :gutter="20">
  16. <el-col :span="8" v-if="isEdit">
  17. <el-form-item label="对账单号" prop="statementOrderNo">
  18. <el-input v-model="form.statementOrderNo" disabled />
  19. </el-form-item>
  20. </el-col>
  21. <el-col :span="8" v-if="isEdit">
  22. <el-form-item label="对账状态" prop="statementStatus">
  23. <el-input v-model="form.statementStatus" disabled />
  24. </el-form-item>
  25. </el-col>
  26. <el-col :span="8">
  27. <el-form-item label="伙伴商名称" prop="customerId">
  28. <el-select
  29. v-model="form.customerId"
  30. filterable
  31. remote
  32. reserve-keyword
  33. placeholder="请输入伙伴商名称"
  34. :remote-method="remoteSearchCustomer"
  35. :loading="customerLoading"
  36. clearable
  37. style="width: 100%"
  38. @change="handleCustomerChange"
  39. >
  40. <el-option v-for="item in customerOptions" :key="item.id" :label="item.customerName" :value="item.id" />
  41. </el-select>
  42. </el-form-item>
  43. </el-col>
  44. </el-row>
  45. <el-row :gutter="20">
  46. <el-col :span="8">
  47. <el-form-item label="对账单金额" prop="amount">
  48. <el-input v-model="form.amount" disabled />
  49. </el-form-item>
  50. </el-col>
  51. <el-col :span="8">
  52. <el-form-item label="对账人" prop="statementSelfId">
  53. <el-select
  54. v-model="form.statementSelfId"
  55. placeholder="请选择对账人"
  56. clearable
  57. filterable
  58. style="width: 100%"
  59. @change="handleStaffChange"
  60. >
  61. <el-option v-for="staff in staffOptions" :key="staff.staffId" :label="staff.staffName" :value="staff.staffId" />
  62. </el-select>
  63. </el-form-item>
  64. </el-col>
  65. <el-col :span="8">
  66. <el-form-item label="对账人联系方式" prop="statementSelfPhone">
  67. <el-input v-model="form.statementSelfPhone" placeholder="请填写对账人联系方式" clearable />
  68. </el-form-item>
  69. </el-col>
  70. </el-row>
  71. <el-row :gutter="20">
  72. <el-col :span="8">
  73. <el-form-item label="对账日期" prop="statementDate">
  74. <el-date-picker v-model="form.statementDate" type="date" placeholder="请选择对账日期" style="width: 100%" value-format="YYYY-MM-DD" />
  75. </el-form-item>
  76. </el-col>
  77. <el-col :span="8">
  78. <el-form-item label="支付状态" prop="isPaymentStatus">
  79. <el-select v-model="form.isPaymentStatus" placeholder="请选择支付状态" clearable style="width: 100%">
  80. <el-option v-for="dict in payment_status" :key="dict.value" :label="dict.label" :value="dict.value" />
  81. </el-select>
  82. </el-form-item>
  83. </el-col>
  84. <el-col :span="8">
  85. <el-form-item label="发票状态" prop="isInvoiceStatus">
  86. <el-select v-model="form.isInvoiceStatus" placeholder="请选择发票状态" clearable style="width: 100%">
  87. <el-option v-for="dict in invoice_issuance_status" :key="dict.value" :label="dict.label" :value="dict.value" />
  88. </el-select>
  89. </el-form-item>
  90. </el-col>
  91. </el-row>
  92. <el-row :gutter="20">
  93. <el-col :span="24">
  94. <el-form-item label="备注" prop="remark">
  95. <el-input v-model="form.remark" type="textarea" :rows="3" placeholder="请输入备注" maxlength="500" show-word-limit />
  96. </el-form-item>
  97. </el-col>
  98. </el-row>
  99. <!-- 对账明细 -->
  100. <el-divider content-position="left">
  101. <span style="color: #409eff; font-weight: 600">对账明细</span>
  102. </el-divider>
  103. <div class="table-actions" style="margin-bottom: 15px">
  104. <el-button type="primary" icon="Plus" @click="handleAddDetail">选择订单</el-button>
  105. </div>
  106. <el-table :data="form.detailList" border style="width: 100%; margin-bottom: 20px">
  107. <el-table-column type="index" label="序号" width="60" align="center" />
  108. <el-table-column prop="orderNo" label="订单编号" min-width="150" align="center" />
  109. <el-table-column prop="deliverCode" label="发货单编号" min-width="150" align="center" />
  110. <el-table-column prop="amount" label="金额" min-width="120" align="center" />
  111. <el-table-column prop="orderTime" label="下单日期" min-width="120" align="center" />
  112. <el-table-column prop="userName" label="下单人" min-width="100" align="center" />
  113. <el-table-column prop="userDept" label="部门" min-width="120" align="center" />
  114. </el-table>
  115. <!--
  116. <div v-if="form.detailList.length === 0" class="empty-data">
  117. <el-empty description="暂无数据" :image-size="100" />
  118. </div> -->
  119. <!-- 商品清单 -->
  120. <el-divider content-position="left">
  121. <span style="color: #409eff; font-weight: 600">商品清单</span>
  122. </el-divider>
  123. <el-table :data="pagedProductList" border style="width: 100%; margin-bottom: 20px">
  124. <el-table-column
  125. type="index"
  126. label="序号"
  127. width="60"
  128. align="center"
  129. :index="(index) => (productPage.pageNum - 1) * productPage.pageSize + index + 1"
  130. />
  131. <el-table-column prop="orderNo" label="订单编号" min-width="120" align="center" />
  132. <el-table-column prop="productNo" label="商品编号" min-width="120" align="center" />
  133. <el-table-column prop="itemName" label="商品名称" min-width="180" align="center" />
  134. <el-table-column prop="unitName" label="单位" width="80" align="center" />
  135. <el-table-column prop="quantity" label="数量" width="100" align="center" />
  136. <el-table-column prop="unitPrice" label="单价" width="100" align="center">
  137. <template #default="scope">
  138. {{ scope.row.unitPrice ? Number(scope.row.unitPrice).toFixed(2) : '0.00' }}
  139. </template>
  140. </el-table-column>
  141. <el-table-column label="小计" width="120" align="center">
  142. <template #default="scope">
  143. {{ (Number(scope.row.quantity || 0) * Number(scope.row.unitPrice || 0)).toFixed(2) }}
  144. </template>
  145. </el-table-column>
  146. </el-table>
  147. <!-- 分页 -->
  148. <el-pagination
  149. v-if="form.productList.length > 0"
  150. v-model:current-page="productPage.pageNum"
  151. v-model:page-size="productPage.pageSize"
  152. :page-sizes="[10, 20, 50, 100]"
  153. layout="total, sizes, prev, pager, next, jumpers"
  154. :total="productPage.total"
  155. @size-change="handleProductSizeChange"
  156. @current-change="handleProductCurrentChange"
  157. style="margin-top: 15px"
  158. />
  159. <!-- 对账附件 -->
  160. <el-divider content-position="left">
  161. <span style="color: #409eff; font-weight: 600">对账附件</span>
  162. </el-divider>
  163. <el-upload
  164. :action="uploadAction"
  165. :on-success="handleUploadSuccess"
  166. :before-upload="beforeUpload"
  167. :show-file-list="false"
  168. multiple
  169. style="margin-bottom: 10px"
  170. >
  171. <el-button type="primary" icon="Upload">点击上传</el-button>
  172. </el-upload>
  173. <el-table :data="fileList" border style="width: 100%; margin-bottom: 20px">
  174. <el-table-column type="index" label="序号" width="80" align="center" />
  175. <el-table-column prop="name" label="文件名称" min-width="200" align="center" />
  176. <el-table-column prop="url" label="文件地址" min-width="250" align="center">
  177. <template #default="scope">
  178. {{ scope.row.url || '暂无地址' }}
  179. </template>
  180. </el-table-column>
  181. <el-table-column label="操作" width="250" align="center">
  182. <template #default="scope">
  183. <el-button type="primary" link @click="handleDownloadFile(scope.row)">下载</el-button>
  184. <el-button type="primary" link @click="handlePreviewFile(scope.row)">预览</el-button>
  185. <el-button type="danger" link @click="handleRemoveFile(scope.$index)">删除</el-button>
  186. </template>
  187. </el-table-column>
  188. </el-table>
  189. <!--
  190. <div v-if="fileList.length === 0" class="empty-data">
  191. <el-empty description="暂无附件" :image-size="100" />
  192. </div> -->
  193. </el-form>
  194. </div>
  195. <template #footer>
  196. <div class="drawer-footer">
  197. <el-button @click="handleDrawerClose(() => (drawer.visible = false))">取消</el-button>
  198. <el-button type="primary" :loading="buttonLoading" @click="handleSubmit">确定</el-button>
  199. </div>
  200. </template>
  201. </el-drawer>
  202. <!-- 客户订单抽屉 -->
  203. <OrderMainDrawer ref="orderMainDrawerRef" @success="handleOrderSelected" />
  204. </template>
  205. <script setup name="AddDrawer" lang="ts">
  206. import { addStatementOrder, updateStatementOrder } from '@/api/bill/statementOrder';
  207. import { StatementOrderForm } from '@/api/bill/statementOrder/types';
  208. import { StatementDetailForm } from '@/api/bill/statementDetail/types';
  209. import { getListBycustomerName } from '@/api/customer/customerFile/customerInfo';
  210. import { CustomerInfoVO } from '@/api/customer/customerFile/customerInfo/types';
  211. import { listOrderMain, getOrderMain } from '@/api/order/orderMain';
  212. import { OrderMainVO, OrderMainQuery, OrderMainForm } from '@/api/order/orderMain/types';
  213. import { OrderDeliverVO } from '@/api/order/orderDeliver/types';
  214. import { listComStaff } from '@/api/company/comStaff';
  215. import { ComStaffVO, ComStaffQuery } from '@/api/company/comStaff/types';
  216. import OrderMainDrawer from './orderMainDrawer.vue';
  217. import { getCustomerDeliverOrders } from '@/api/order/orderDeliver';
  218. const { proxy } = getCurrentInstance() as ComponentInternalInstance;
  219. const { statement_status, invoice_issuance_status, payment_status } = toRefs<any>(
  220. proxy?.useDict('statement_status', 'statement_order_type', 'invoice_issuance_status', 'payment_status')
  221. );
  222. const initFormData: StatementOrderForm = {
  223. id: undefined,
  224. statementOrderNo: undefined,
  225. customerId: undefined,
  226. customerNo: undefined,
  227. customerName: undefined,
  228. amount: undefined,
  229. statementSelfId: undefined,
  230. statementSelf: undefined,
  231. statementSelfPhone: undefined,
  232. statementStatus: undefined,
  233. isPaymentStatus: '1',
  234. isInvoiceStatus: '0',
  235. statementDate: undefined,
  236. annexAddress: undefined,
  237. rejectRemark: undefined,
  238. statementType: '',
  239. remark: undefined,
  240. detailList: [],
  241. productList: []
  242. };
  243. const emit = defineEmits(['success']);
  244. const formRef = ref<any>();
  245. const buttonLoading = ref(false);
  246. const form = ref<
  247. StatementOrderForm & {
  248. actualAmount?: string;
  249. accountingVerification?: string;
  250. skuProductName?: string;
  251. skuProductModel?: string;
  252. attachmentRemark?: string;
  253. }
  254. >({ ...initFormData });
  255. const rules = reactive({
  256. customerName: [{ required: true, message: '请输入伙伴商名称', trigger: 'blur' }],
  257. statementSelfId: [{ required: true, message: '请选择对账人', trigger: 'blur' }],
  258. statementSelfPhone: [
  259. { required: true, message: '请输入对账人手机号', trigger: 'blur' },
  260. { pattern: /^1[3-9]\d{9}$/ as RegExp, message: '请输入正确的手机号格式', trigger: 'blur' }
  261. ]
  262. } as any);
  263. const fileList = ref<any[]>([]);
  264. const productPage = reactive({
  265. pageNum: 1,
  266. pageSize: 10,
  267. total: 0
  268. });
  269. const drawer = reactive<DialogOption>({
  270. visible: false,
  271. title: '新增对账'
  272. });
  273. const isEdit = ref(false); // 是否为编辑模式
  274. const customerLoading = ref(false);
  275. const customerOptions = ref<CustomerInfoVO[]>([]);
  276. const staffOptions = ref<ComStaffVO[]>([]);
  277. const orderMainDrawerRef = ref<any>();
  278. const uploadAction = import.meta.env.VITE_APP_BASE_API + '/resource/oss/upload';
  279. const currentSelectedOrders = ref<OrderDeliverVO[]>([]);
  280. const preloadedOrders = ref<OrderDeliverVO[]>([]); // 预加载的订单列表
  281. /** 计算当前页的商品列表 */
  282. const pagedProductList = computed(() => {
  283. const start = (productPage.pageNum - 1) * productPage.pageSize;
  284. const end = start + productPage.pageSize;
  285. return form.value.productList?.slice(start, end) || [];
  286. });
  287. const preloadedTotal = ref(0); // 预加载的订单总数
  288. /** 打开新增/编辑对账详情抽屉 */
  289. const open = (id?: string | number, data?: StatementOrderForm) => {
  290. reset();
  291. if (id && data) {
  292. // 编辑模式
  293. isEdit.value = true;
  294. drawer.title = '编辑对账';
  295. Object.assign(form.value, data);
  296. // 将客户信息添加到下拉选项中,以便回显
  297. if (data.customerId && data.customerName) {
  298. customerOptions.value = [
  299. {
  300. id: data.customerId,
  301. customerName: data.customerName,
  302. customerNo: data.customerNo || ''
  303. } as CustomerInfoVO
  304. ];
  305. }
  306. // 解析附件地址并回显附件列表
  307. if (data.annexAddress) {
  308. const urls = data.annexAddress.split(',').filter((url) => url.trim());
  309. fileList.value = urls.map((url, index) => {
  310. const fileName = url.split('/').pop() || `附件${index + 1}`;
  311. return {
  312. name: fileName,
  313. url: url.trim(),
  314. id: undefined
  315. };
  316. });
  317. }
  318. // 设置商品列表分页总数
  319. if (data.productList && data.productList.length > 0) {
  320. productPage.total = data.productList.length;
  321. }
  322. } else {
  323. // 新增模式
  324. isEdit.value = false;
  325. drawer.title = '新增对账';
  326. }
  327. // 先打开抽屉
  328. drawer.visible = true;
  329. // 异步加载员工列表
  330. getStaffList();
  331. // 编辑模式下,如果有客户ID,异步预加载订单列表
  332. if (id && data?.customerId) {
  333. preloadOrders(data.customerId);
  334. }
  335. };
  336. /** 表单重置 */
  337. const reset = () => {
  338. form.value = { ...initFormData };
  339. fileList.value = [];
  340. productPage.pageNum = 1;
  341. productPage.pageSize = 10;
  342. productPage.total = 0;
  343. customerOptions.value = [];
  344. currentSelectedOrders.value = [];
  345. preloadedOrders.value = [];
  346. preloadedTotal.value = 0;
  347. formRef.value?.clearValidate();
  348. };
  349. /** 远程搜索客户 */
  350. const remoteSearchCustomer = async (query: string) => {
  351. if (query) {
  352. customerLoading.value = true;
  353. try {
  354. const res = await getListBycustomerName(query);
  355. customerOptions.value = res.data;
  356. } catch (error) {
  357. console.error(error);
  358. } finally {
  359. customerLoading.value = false;
  360. }
  361. } else {
  362. customerOptions.value = [];
  363. }
  364. };
  365. /** 客户变更 */
  366. const handleCustomerChange = async (customerId: string | number) => {
  367. if (customerId) {
  368. const customer = customerOptions.value.find((item) => item.id === customerId);
  369. if (customer) {
  370. form.value.customerName = customer.customerName;
  371. form.value.customerNo = customer.customerNo;
  372. }
  373. // 预加载订单列表
  374. await preloadOrders(customerId);
  375. } else {
  376. form.value.customerName = undefined;
  377. form.value.customerNo = undefined;
  378. preloadedOrders.value = [];
  379. preloadedTotal.value = 0;
  380. }
  381. };
  382. /** 预加载订单列表 */
  383. const preloadOrders = async (customerId: string | number) => {
  384. try {
  385. const res = await getCustomerDeliverOrders(customerId);
  386. preloadedOrders.value = res.rows || [];
  387. preloadedTotal.value = res.total || 0;
  388. } catch (error) {
  389. console.error('预加载订单列表失败:', error);
  390. preloadedOrders.value = [];
  391. preloadedTotal.value = 0;
  392. }
  393. };
  394. /** 选择订单 */
  395. const handleSelectOrder = () => {
  396. if (!form.value.customerId) {
  397. proxy?.$modal.msgWarning('请先选择伙伴商');
  398. return;
  399. }
  400. // 传递当前已选中的订单、产品列表、预加载的订单列表和总数
  401. orderMainDrawerRef.value?.open(
  402. form.value.customerId,
  403. currentSelectedOrders.value,
  404. form.value.productList,
  405. preloadedOrders.value,
  406. preloadedTotal.value
  407. );
  408. };
  409. /** 获取员工列表 */
  410. const getStaffList = async () => {
  411. try {
  412. const res = await listComStaff();
  413. staffOptions.value = res.rows || [];
  414. } catch (error) {
  415. console.error('获取员工列表失败:', error);
  416. }
  417. };
  418. /** 员工变更 */
  419. const handleStaffChange = (staffId: string | number) => {
  420. if (staffId) {
  421. const staff = staffOptions.value.find((item) => item.staffId === staffId);
  422. if (staff) {
  423. form.value.statementSelf = staff.staffName || '';
  424. form.value.statementSelfPhone = staff.phone || '';
  425. }
  426. } else {
  427. form.value.statementSelf = undefined;
  428. form.value.statementSelfPhone = '';
  429. }
  430. };
  431. /** 订单选择成功回调 */
  432. const handleOrderSelected = (data: any) => {
  433. const { orders, products } = data;
  434. if (orders && orders.length > 0) {
  435. let totalAmount = 0;
  436. // 保存当前选中的订单
  437. currentSelectedOrders.value = orders;
  438. // 清空现有数据
  439. form.value.detailList = [];
  440. form.value.productList = [];
  441. // 填充对账明细
  442. orders.forEach((order: any) => {
  443. totalAmount += Number(order.totalAmount || 0);
  444. const detail: any = {
  445. id: undefined,
  446. statementOrderId: undefined,
  447. orderNo: order.orderCode,
  448. deliverCode: order.deliverCode || '',
  449. orderTime: order.orderTime || '',
  450. amount: order.totalAmount,
  451. type: order.orderType || '',
  452. orderId: order.id,
  453. signingDate: order.receivingTime || order.signingDate || '',
  454. userId: order.createBy,
  455. userName: order.createName || '',
  456. userDeptId: order.createDept,
  457. userDept: order.createDeptName || ''
  458. };
  459. form.value.detailList?.push(detail);
  460. });
  461. // 设置总金额
  462. form.value.amount = totalAmount;
  463. // 直接使用传递过来的产品列表
  464. if (products && products.length > 0) {
  465. form.value.productList = products;
  466. productPage.total = products.length;
  467. }
  468. }
  469. };
  470. /** 添加对账明细 */
  471. const handleAddDetail = () => {
  472. if (!form.value.customerId) {
  473. proxy?.$modal.msgWarning('请先选择伙伴商');
  474. return;
  475. }
  476. // 传递当前已选中的订单、产品列表、预加载的订单列表和总数
  477. orderMainDrawerRef.value?.open(
  478. form.value.customerId,
  479. currentSelectedOrders.value,
  480. form.value.productList,
  481. preloadedOrders.value,
  482. preloadedTotal.value
  483. );
  484. };
  485. /** 产品分页大小改变 */
  486. const handleProductSizeChange = (val: number) => {
  487. productPage.pageSize = val;
  488. };
  489. /** 产品分页页码改变 */
  490. const handleProductCurrentChange = (val: number) => {
  491. productPage.pageNum = val;
  492. };
  493. /** 上传前校验 */
  494. const beforeUpload = (file: any) => {
  495. const isLt50M = file.size / 1024 / 1024 < 50;
  496. if (!isLt50M) {
  497. proxy?.$modal.msgWarning('上传文件大小不能超过 50MB!');
  498. }
  499. return isLt50M;
  500. };
  501. /** 上传成功回调 */
  502. const handleUploadSuccess = (response: any, file: any) => {
  503. if (response.code === 200) {
  504. fileList.value.push({
  505. name: file.name,
  506. url: response.data.url,
  507. id: undefined
  508. });
  509. // 更新表单中的附件地址
  510. form.value.annexAddress = fileList.value
  511. .map((f) => f.url)
  512. .filter(Boolean)
  513. .join(',');
  514. proxy?.$modal.msgSuccess('上传成功');
  515. } else {
  516. proxy?.$modal.msgError(response.msg || '上传失败');
  517. }
  518. };
  519. /** 删除文件 */
  520. const handleRemoveFile = (index: number) => {
  521. fileList.value.splice(index, 1);
  522. // 更新表单中的附件地址
  523. form.value.annexAddress = fileList.value
  524. .map((f) => f.url)
  525. .filter(Boolean)
  526. .join(',');
  527. };
  528. /** 下载文件 */
  529. const handleDownloadFile = async (file: any) => {
  530. if (!file.url) {
  531. proxy?.$modal.msgWarning('文件地址不存在');
  532. return;
  533. }
  534. try {
  535. // 使用fetch获取文件
  536. const response = await fetch(file.url);
  537. const blob = await response.blob();
  538. // 创建Blob URL
  539. const blobUrl = window.URL.createObjectURL(blob);
  540. // 创建下载链接
  541. const link = document.createElement('a');
  542. link.href = blobUrl;
  543. link.download = file.name || '附件';
  544. document.body.appendChild(link);
  545. link.click();
  546. // 清理
  547. document.body.removeChild(link);
  548. window.URL.revokeObjectURL(blobUrl);
  549. } catch (error) {
  550. console.error('下载失败:', error);
  551. // 如果fetch失败,回退到直接打开链接的方式
  552. const link = document.createElement('a');
  553. link.href = file.url;
  554. link.download = file.name || '附件';
  555. link.target = '_blank';
  556. document.body.appendChild(link);
  557. link.click();
  558. document.body.removeChild(link);
  559. }
  560. };
  561. /** 预览文件 */
  562. const handlePreviewFile = (file: any) => {
  563. if (!file.url) {
  564. proxy?.$modal.msgWarning('文件地址不存在');
  565. return;
  566. }
  567. // 在新窗口打开文件
  568. window.open(file.url, '_blank');
  569. };
  570. /** 提交表单 */
  571. const handleSubmit = async () => {
  572. if (!formRef.value) return;
  573. console.log(form.value);
  574. await formRef.value.validate(async (valid) => {
  575. if (valid) {
  576. buttonLoading.value = true;
  577. try {
  578. if (isEdit.value) {
  579. // 编辑模式
  580. await updateStatementOrder(form.value);
  581. proxy?.$modal.msgSuccess('修改成功');
  582. } else {
  583. // 新增模式
  584. await addStatementOrder(form.value);
  585. proxy?.$modal.msgSuccess('新增成功');
  586. }
  587. drawer.visible = false;
  588. emit('success');
  589. } catch (error) {
  590. console.error(error);
  591. } finally {
  592. buttonLoading.value = false;
  593. }
  594. }
  595. });
  596. };
  597. /** 关闭抽屉前的回调 */
  598. const handleDrawerClose = (done: () => void) => {
  599. if (buttonLoading.value) {
  600. return;
  601. }
  602. done();
  603. reset();
  604. };
  605. defineExpose({
  606. open
  607. });
  608. </script>
  609. <style scoped lang="scss">
  610. .drawer-header {
  611. display: flex;
  612. align-items: center;
  613. gap: 10px;
  614. .order-title {
  615. font-size: 16px;
  616. font-weight: 600;
  617. color: #303133;
  618. }
  619. }
  620. .drawer-content {
  621. padding: 0 20px 20px;
  622. height: calc(100% - 60px);
  623. overflow-y: auto;
  624. }
  625. .assign-dialog-content {
  626. padding: 0 10px;
  627. }
  628. .assign-target-section {
  629. margin-bottom: 20px;
  630. .target-input-wrapper {
  631. display: flex;
  632. align-items: center;
  633. gap: 8px;
  634. .required-mark {
  635. color: #f56c6c;
  636. font-size: 14px;
  637. }
  638. .label {
  639. font-size: 14px;
  640. color: #606266;
  641. white-space: nowrap;
  642. }
  643. }
  644. .or-divider {
  645. display: flex;
  646. align-items: center;
  647. justify-content: center;
  648. font-size: 14px;
  649. color: #909399;
  650. }
  651. }
  652. .product-list-section {
  653. margin-top: 20px;
  654. }
  655. .detail-header {
  656. padding: 15px 20px;
  657. background-color: #f5f7fa;
  658. border-radius: 4px;
  659. margin-bottom: 20px;
  660. .info-item {
  661. display: flex;
  662. flex-direction: column;
  663. gap: 5px;
  664. .label {
  665. font-size: 12px;
  666. color: #909399;
  667. }
  668. .value {
  669. font-size: 14px;
  670. color: #303133;
  671. font-weight: 500;
  672. }
  673. }
  674. }
  675. .detail-tabs {
  676. .tab-actions {
  677. margin-bottom: 15px;
  678. }
  679. }
  680. :deep(.el-alert__title) {
  681. font-size: 13px;
  682. }
  683. .empty-data {
  684. padding: 20px 0;
  685. text-align: center;
  686. }
  687. .drawer-footer {
  688. display: flex;
  689. justify-content: flex-end;
  690. gap: 10px;
  691. padding: 15px 20px;
  692. border-top: 1px solid #e4e7ed;
  693. }
  694. :deep(.el-upload__tip) {
  695. margin-top: 8px;
  696. font-size: 12px;
  697. color: #909399;
  698. }
  699. </style>