You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

2012 lines
73 KiB

3 months ago
3 months ago
1 day ago
3 months ago
1 day ago
3 months ago
1 day ago
3 months ago
1 day ago
3 months ago
1 day ago
3 months ago
1 day ago
3 months ago
1 day ago
3 months ago
1 day ago
3 months ago
1 day ago
3 months ago
3 months ago
1 day ago
3 months ago
3 months ago
1 day ago
3 months ago
3 months ago
  1. <template>
  2. <div class="customer-css">
  3. <el-dialog :title="titleCon" :close-on-click-modal="false" :visible.sync="visible"
  4. :width="showPreview ? '1300px' : '600px'" class="customer-dialog" >
  5. <el-form label-position="top">
  6. <el-row :gutter="16">
  7. <el-col :span="12">
  8. <el-form-item label="BU">
  9. <el-select v-model="pageData.buNo" placeholder="请选择" style="width: 100%">
  10. <el-option v-for="i in buList" :key="i.buNo" :label="i.buDesc" :value="i.buNo"></el-option>
  11. </el-select>
  12. </el-form-item>
  13. </el-col>
  14. <el-col :span="4">
  15. <el-form-item label=" ">
  16. </el-form-item>
  17. </el-col>
  18. <el-col :span="8">
  19. <el-form-item label=" " v-if="showPreview">
  20. <div style="margin-top:40px;padding: 10px; background-color: #FFF3E0; border: 1px solid #FFB74D; border-radius: 4px; font-size: 13px; line-height: 1.6;">
  21. <div style="color: #E65100; font-weight: bold; margin-bottom: 5px;">
  22. <i class="el-icon-warning" style="margin-right: 5px;"></i>导入规则
  23. </div>
  24. <div style="color: #666;">
  25. 以下3种情况不读取Excel内容<br/>
  26. 1发票在系统已存在<br/>
  27. 2内销<br/>
  28. 3CargoReady Date为空
  29. </div>
  30. <div style="color: #E65100; font-weight: bold; margin-bottom: 5px;">
  31. <i class="el-icon-warning" style="margin-right: 5px;"></i>保存模板规则
  32. </div>
  33. <div style="color: #666;">
  34. 客户模板名称无修改"保存模板"会修改原模板<br/>
  35. 客户模板名称有修改"保存模板"会另存为新模板
  36. </div>
  37. </div>
  38. </el-form-item>
  39. </el-col>
  40. <el-col :span="20" style="margin-top: 10px">
  41. <el-upload class="customer-upload" drag action="javascript:void(0);" ref="uploadFile" :limit="1" accept=".xlsx,.xls"
  42. :before-upload="beforeUploadHandle" :on-change="onChange" :auto-upload="false" style="text-align: left;">
  43. <i class="el-icon-upload"></i>
  44. <div class="el-upload__text">将文件拖到此处<em>点击上传</em></div>
  45. </el-upload>
  46. </el-col>
  47. </el-row>
  48. </el-form>
  49. <!-- 预览数据表格 -->
  50. <!-- 加载状态 -->
  51. <div v-if="previewLoading" style="margin-top: 20px; text-align: center; padding: 40px;">
  52. <i class="el-icon-loading" style="font-size: 24px; color: #409EFF;"></i>
  53. <p style="margin-top: 10px; color: #666;">正在解析文件请稍候...</p>
  54. </div>
  55. <div v-if="showPreview" style="margin-top: 10px; margin-bottom: 10px;">
  56. <!-- 可导入的发票表格 -->
  57. <div v-if="validInvoices.length > 0">
  58. <div style="display: flex; align-items: center; margin-bottom: 8px;">
  59. <span style="color: #67C23A;">
  60. <i class="el-icon-success" style="margin-right: 8px;"></i>
  61. 可导入的发票 ({{ validInvoices.length }}个发票)
  62. </span>
  63. <el-button
  64. type="danger"
  65. size="mini"
  66. style="margin-left: 15px;"
  67. :disabled="selectedRows.length === 0"
  68. @click="batchDeleteRows">
  69. <i class="el-icon-delete"></i>
  70. 批量删除 <span v-if="selectedRows.length > 0">({{ selectedRows.length }})</span>
  71. </el-button>
  72. </div>
  73. <el-table
  74. :data="validInvoices"
  75. border
  76. style="width: 100%"
  77. max-height="300"
  78. :show-overflow-tooltip="true"
  79. class="delClass valid-table"
  80. ref="validInvoicesTable"
  81. @selection-change="handleSelectionChange">
  82. <el-table-column type="selection" width="40" fixed="left" align="center"></el-table-column>
  83. <!-- <el-table-column label="操作" width="50" fixed="left">
  84. <template slot-scope="scope">
  85. <a type="text" size="small" style="color: red" @click="deleteRow(scope.$index, scope.row)">删除</a>
  86. </template>
  87. </el-table-column>-->
  88. <el-table-column prop="cmcInvoice" label="发票号" width="90" fixed="left">
  89. <template slot-scope="scope">
  90. <div>
  91. <span :style="scope.row.exists ? 'color: red; font-weight: bold;' : ''">
  92. {{ scope.row.cmcInvoice }}
  93. </span>
  94. <div style="margin-top: 2px;">
  95. <el-tag v-if="scope.row.exists" type="warning" size="mini">已存在</el-tag>
  96. </div>
  97. </div>
  98. </template>
  99. </el-table-column>
  100. <el-table-column prop="destination" label="目的地" width="100" :show-overflow-tooltip="true"></el-table-column>
  101. <el-table-column label="客户模板名称" width="150">
  102. <template slot-scope="scope">
  103. <el-input
  104. v-model="scope.row.selectedTemplate"
  105. placeholder="请选择客户模板名称"
  106. @dblclick.native="selectTemplateForRow(scope.row)"
  107. size="small"
  108. style="cursor: pointer;">
  109. </el-input>
  110. </template>
  111. </el-table-column>
  112. <el-table-column label="客户" width="150">
  113. <template slot-scope="scope">
  114. <el-input
  115. v-model="scope.row.selectedCustomer"
  116. placeholder="请选择客户"
  117. @dblclick.native="selectCustomerForRow(scope.row)"
  118. size="small"
  119. style="cursor: pointer;"
  120. readonly>
  121. <i slot="suffix" class="el-icon-edit" style="cursor: pointer;" @click.stop="openEditDialog(scope.row, 'selectedCustomer', '客户', '编辑客户信息')"></i>
  122. </el-input>
  123. </template>
  124. </el-table-column>
  125. <el-table-column label="客户地址" min-width="160">
  126. <template slot-scope="scope">
  127. <el-input
  128. v-model="scope.row.selectedLocalAddress"
  129. placeholder="请选择客户地址"
  130. @dblclick.native="selectLocalAddressForRow(scope.row)"
  131. size="small"
  132. style="cursor: pointer;"
  133. readonly>
  134. <i slot="suffix" class="el-icon-edit" style="cursor: pointer;" @click.stop="openEditDialog(scope.row, 'selectedLocalAddress', '客户地址', '编辑客户地址')"></i>
  135. </el-input>
  136. </template>
  137. </el-table-column>
  138. <el-table-column label="收货单位" width="150">
  139. <template slot-scope="scope">
  140. <el-input
  141. v-model="scope.row.selectedOverseasShipper"
  142. placeholder="请选择收货单位"
  143. @dblclick.native="selectOverseasShipperForRow(scope.row)"
  144. size="small"
  145. style="cursor: pointer;"
  146. readonly>
  147. <i slot="suffix" class="el-icon-edit" style="cursor: pointer;" @click.stop="openEditDialog(scope.row, 'selectedOverseasShipper', '收货单位', '编辑收货单位')"></i>
  148. </el-input>
  149. </template>
  150. </el-table-column>
  151. <el-table-column label="收货单位地址" width="160">
  152. <template slot-scope="scope">
  153. <el-input
  154. v-model="scope.row.selectedOverseasAddress"
  155. placeholder="请选择收货单位地址"
  156. @dblclick.native="selectOverseasAddressForRow(scope.row)"
  157. size="small"
  158. style="cursor: pointer;"
  159. readonly>
  160. <i slot="suffix" class="el-icon-edit" style="cursor: pointer;" @click.stop="openEditDialog(scope.row, 'selectedOverseasAddress', '收货单位地址', '编辑收货单位地址')"></i>
  161. </el-input>
  162. </template>
  163. </el-table-column>
  164. <el-table-column label="运抵国" width="80">
  165. <template slot-scope="scope">
  166. <el-input
  167. v-model="scope.row.selectedCnative"
  168. placeholder="运抵国"
  169. size="small"
  170. style="cursor: pointer;"
  171. readonly>
  172. <i slot="suffix" class="el-icon-edit" style="cursor: pointer;" @click.stop="openEditDialog(scope.row, 'selectedCnative', '运抵国', '编辑运抵国')"></i>
  173. </el-input>
  174. </template>
  175. </el-table-column>
  176. <el-table-column label="贸易国" width="80">
  177. <template slot-scope="scope">
  178. <el-input
  179. v-model="scope.row.selectedSalesArea"
  180. placeholder="贸易国"
  181. size="small"
  182. style="cursor: pointer;"
  183. readonly>
  184. <i slot="suffix" class="el-icon-edit" style="cursor: pointer;" @click.stop="openEditDialog(scope.row, 'selectedSalesArea', '贸易国', '编辑贸易国')"></i>
  185. </el-input>
  186. </template>
  187. </el-table-column>
  188. <el-table-column label="操作" width="60" fixed="right">
  189. <template slot-scope="scope">
  190. <a v-if="scope.row.selectedTemplate"
  191. type="text"
  192. size="small"
  193. @click="saveTemplateChanges(scope.row)">
  194. 保存模板
  195. </a>
  196. <span v-else style="color: #C0C4CC; font-size: 12px;">未选择</span>
  197. </template>
  198. </el-table-column>
  199. </el-table>
  200. </div>
  201. <!-- 物料不存在的发票表格 -->
  202. <div v-if="invalidInvoices.length > 0" style="margin-top: 10px;margin-bottom: 10px">
  203. <span style="color: #F56C6C;">
  204. <i class="el-icon-warning" style="margin-right: 8px;"></i>
  205. 物料不存在的发票 ({{ invalidInvoices.length }}个发票将不会导入)
  206. </span>
  207. <el-table :data="invalidInvoices" border style="width: 100%" max-height="300" :show-overflow-tooltip="true" class="delClass invalid-table">
  208. <el-table-column prop="cmcInvoice" label="发票号" width="120" fixed="left">
  209. <template slot-scope="scope">
  210. <div>
  211. <span
  212. class="clickable-invoice"
  213. style="color: #F56C6C; font-weight: bold;"
  214. @click="showInvalidMaterials(scope.row)">
  215. {{ scope.row.cmcInvoice }}
  216. <i class="el-icon-view" style="margin-left: 4px; font-size: 12px;"></i>
  217. </span>
  218. <div style="margin-top: 2px;">
  219. <el-tag type="danger" size="mini">物料不存在</el-tag>
  220. </div>
  221. </div>
  222. </template>
  223. </el-table-column>
  224. <el-table-column prop="destination" label="目的地" width="100"></el-table-column>
  225. <el-table-column label="状态" width="100">
  226. <template slot-scope="scope">
  227. <div style="color: #F56C6C;">
  228. <el-tag type="danger" size="small">物料不存在</el-tag>
  229. <div style="font-size: 12px; margin-top: 2px;">将不会导入</div>
  230. </div>
  231. </template>
  232. </el-table-column>
  233. <el-table-column label="不存在物料" width="150">
  234. <template slot-scope="scope">
  235. <div style="color: #F56C6C;">
  236. <el-tag type="danger" size="small">{{ scope.row.invalidMaterials ? scope.row.invalidMaterials.length : 0 }}个物料</el-tag>
  237. <div style="font-size: 12px; margin-top: 2px;">
  238. 点击发票号查看详情
  239. </div>
  240. </div>
  241. </template>
  242. </el-table-column>
  243. <el-table-column label="客户信息" width="150">
  244. <template slot-scope="scope">
  245. <div style="color: #999; font-size: 12px;">
  246. 无需填写
  247. </div>
  248. </template>
  249. </el-table-column>
  250. <el-table-column prop="readyDate" label="Ready Date" width="160"></el-table-column>
  251. <el-table-column prop="totalQty" label="总数量" width="150" align="right">
  252. <template slot-scope="scope">
  253. {{ scope.row.totalQty || 0 }}
  254. </template>
  255. </el-table-column>
  256. <el-table-column prop="totalItems" label="明细数" width="160" align="center">
  257. <template slot-scope="scope">
  258. {{ scope.row.totalItems || 0 }}
  259. </template>
  260. </el-table-column>
  261. <el-table-column prop="shippingMode" label="运输方式" min-width="80"></el-table-column>
  262. </el-table>
  263. </div>
  264. <!-- Sheet错误信息展示 -->
  265. <div v-if="sheetErrors.length > 0" style="margin-bottom: 5px;">
  266. <span style="color: #E6A23C; ">
  267. <i class="el-icon-warning" style="margin-right: 8px;"></i>
  268. Sheet处理警告 ({{ sheetErrors.length }}个Sheet存在问题)
  269. </span>
  270. <el-table :data="sheetErrors" border style="width: 100%" max-height="400" class="delClass warning-table">
  271. <el-table-column prop="sheetName" label="Sheet名称" width="150" fixed="left" >
  272. <template slot-scope="scope">
  273. <span style="font-weight: bold;">{{ scope.row.sheetName }}</span>
  274. </template>
  275. </el-table-column>
  276. <el-table-column prop="errorMessage" label="原因" min-width="300">
  277. <template slot-scope="scope">
  278. <div>
  279. <el-tooltip
  280. v-if="scope.row.errorDetails && scope.row.errorDetails.length > 0"
  281. placement="top"
  282. effect="light">
  283. <div slot="content" style="max-width: 500px; line-height: 1.6;">
  284. <div style="font-weight: bold; margin-bottom: 8px; color: #E6A23C;">详细错误信息 ({{ scope.row.errorDetails.length }})</div>
  285. <div v-for="(detail, index) in scope.row.errorDetails" :key="index" style="margin-bottom: 6px;">
  286. <span style="color: #E6A23C; font-weight: bold;">{{ index + 1 }}.</span> {{ detail }}
  287. </div>
  288. </div>
  289. <div style="font-size: 12px; color: #909399; cursor: pointer; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;">
  290. <span v-for="(detail, index) in scope.row.errorDetails" :key="index">
  291. <span v-if="index > 0">; </span>
  292. <span style="color: #E6A23C; font-weight: bold;">{{ index + 1 }}.</span> {{ detail }}
  293. </span>
  294. </div>
  295. </el-tooltip>
  296. </div>
  297. </template>
  298. </el-table-column>
  299. </el-table>
  300. </div>
  301. </div>
  302. <span slot="footer" class="dialog-footer" style="margin-top: 10px">
  303. <el-button v-if="!showPreview" type="primary" @click="saveUploadFile" :loading="saveButtonLoading" :disabled="saveButtonLoading">保存</el-button>
  304. <el-button v-if="showPreview" type="primary" @click="saveFromPreview" :loading="confirmSaveButtonLoading" :disabled="confirmSaveButtonLoading">确认保存</el-button>
  305. <el-button v-if="showPreview" @click="cancelPreview" :disabled="confirmSaveButtonLoading">取消预览</el-button>
  306. <el-button v-if="!showPreview" type="primary" @click="closeDialog" :disabled="saveButtonLoading">关闭</el-button>
  307. </span>
  308. </el-dialog>
  309. <el-dialog :title="currentRow ? `为发票号 ${currentRow.cmcInvoice} 选择客户模板` : '客户模板'"
  310. @close="templateFlag = false; currentRow = null" :visible.sync="templateFlag" width="1200px" v-drag>
  311. <!-- 搜索表单 -->
  312. <el-form :inline="true" label-position="top" :model="templateSearchData" label-width="100px" >
  313. <el-form-item label="模板名称">
  314. <el-input
  315. v-model="templateSearchData.templateName"
  316. placeholder="请输入模板名称"
  317. style="width: 200px;"
  318. clearable>
  319. </el-input>
  320. </el-form-item>
  321. <el-form-item label="客户名称">
  322. <el-input
  323. v-model="templateSearchData.customerName"
  324. placeholder="请输入客户名称"
  325. style="width: 200px;"
  326. clearable>
  327. </el-input>
  328. </el-form-item>
  329. <el-form-item label="BU">
  330. <el-select
  331. v-model="templateSearchData.buNo"
  332. placeholder="请选择BU"
  333. style="width: 200px;"
  334. clearable>
  335. <el-option v-for="i in buList" :key="`template-${i.buNo}`" :label="i.buDesc" :value="i.buNo"></el-option>
  336. </el-select>
  337. </el-form-item>
  338. <el-form-item label=" ">
  339. <el-button type="primary" @click="searchTemplateList">查询</el-button>
  340. </el-form-item>
  341. <el-form-item label=" ">
  342. <el-button @click="resetTemplateSearch">重置</el-button>
  343. </el-form-item>
  344. </el-form>
  345. <el-table
  346. :height="400"
  347. :data="customerTemplateList"
  348. stripe
  349. highlight-current-row
  350. border class="delClass"
  351. @row-dblclick="rowDblclickTemplate"
  352. style="width: 100%;">
  353. <el-table-column
  354. prop="template_name"
  355. header-align="center"
  356. align="left"
  357. width="150"
  358. label="模板名称">
  359. </el-table-column>
  360. <el-table-column
  361. prop="ccusname"
  362. header-align="center"
  363. align="left"
  364. width="200"
  365. label="客户名称">
  366. </el-table-column>
  367. <el-table-column
  368. prop="localShipAddress"
  369. header-align="center"
  370. align="left"
  371. width="300"
  372. label="客户地址">
  373. </el-table-column>
  374. <el-table-column
  375. prop="overseasShipper"
  376. header-align="center"
  377. align="left"
  378. width="200"
  379. label="收货单位">
  380. </el-table-column>
  381. <el-table-column
  382. prop="overseasAddress"
  383. header-align="center"
  384. align="left"
  385. width="300"
  386. label="收货地址">
  387. </el-table-column>
  388. <el-table-column
  389. prop="salesArea"
  390. header-align="center"
  391. align="left"
  392. width="80"
  393. label="贸易国">
  394. </el-table-column>
  395. <el-table-column
  396. prop="cnative"
  397. header-align="center"
  398. align="left"
  399. width="80"
  400. label="运抵国">
  401. </el-table-column>
  402. </el-table>
  403. <el-footer style="height:40px;margin-top: 10px;text-align:center">
  404. <el-button @click="templateFlag = false; currentRow = null">关闭</el-button>
  405. </el-footer>
  406. </el-dialog>
  407. <el-dialog :title="currentRow ? `为发票号 ${currentRow.cmcInvoice} 选择客户` : '客户'" @close="closeCustomDialog" :visible.sync="customFlag" width="500px" v-drag>
  408. <el-form inline="inline" label-position="top" :model="customSearchData" style="margin-left: 7px;margin-top: -5px;">
  409. <el-form-item label="客户名称">
  410. <el-input v-model="customSearchData.ccusname" clearable style="width: 150px"></el-input>
  411. </el-form-item>
  412. <el-form-item label=" ">
  413. <el-button type="primary" style="padding: 3px 12px" @click="getCustomerList()">查询</el-button>
  414. </el-form-item>
  415. </el-form>
  416. <el-table
  417. :height="400"
  418. :data="customerList"
  419. stripe
  420. highlight-current-row
  421. border
  422. @row-dblclick="rowDblclick"
  423. style="width: 100%;">
  424. <el-table-column
  425. prop="ccusname"
  426. header-align="center"
  427. align="left"
  428. width="350"
  429. label="客户名称">
  430. </el-table-column>
  431. <el-table-column
  432. prop="country"
  433. header-align="center"
  434. align="left"
  435. label="贸易国">
  436. </el-table-column>
  437. </el-table>
  438. <el-footer style="height:40px;margin-top: 10px;text-align:center">
  439. <el-button @click="customFlag = false">关闭</el-button>
  440. </el-footer>
  441. </el-dialog>
  442. <el-dialog :title="currentRow ? `为发票号 ${currentRow.cmcInvoice} 选择客户地址` : '客户地址'" @close="localShipAddressFlag = false; currentRow = null" :visible.sync="localShipAddressFlag" width="500px" v-drag>
  443. <el-table
  444. :height="400"
  445. :data="customerAddrs"
  446. stripe
  447. highlight-current-row
  448. border
  449. @row-dblclick="rowDblclick2"
  450. style="width: 100%;">
  451. <el-table-column
  452. prop="cDeliverAdd"
  453. header-align="center"
  454. align="left"
  455. label="客户地址">
  456. </el-table-column>
  457. </el-table>
  458. <el-footer style="height:40px;margin-top: 10px;text-align:center">
  459. <el-button @click="localShipAddressFlag = false; currentRow = null">关闭</el-button>
  460. </el-footer>
  461. </el-dialog>
  462. <el-dialog :title="currentRow ? `为发票号 ${currentRow.cmcInvoice} 选择收货单位地址` : '收货单位地址'" @close="overseasAddressFlag = false; currentRow = null" :visible.sync="overseasAddressFlag" width="500px" v-drag>
  463. <el-table
  464. :height="400"
  465. :data="customerAddrs"
  466. stripe
  467. highlight-current-row
  468. border
  469. @row-dblclick="rowDblclick3"
  470. style="width: 100%;">
  471. <el-table-column
  472. prop="cDeliverAdd"
  473. header-align="center"
  474. align="left"
  475. label="收货单位地址">
  476. </el-table-column>
  477. </el-table>
  478. <el-footer style="height:40px;margin-top: 10px;text-align:center">
  479. <el-button @click="overseasAddressFlag = false; currentRow = null">关闭</el-button>
  480. </el-footer>
  481. </el-dialog>
  482. <el-dialog :title="currentRow ? `为发票号 ${currentRow.cmcInvoice} 选择收货单位` : '收货单位'" @close="overseasShipperFlag = false; currentRow = null" :visible.sync="overseasShipperFlag" width="500px" v-drag>
  483. <el-table
  484. :height="400"
  485. :data="customerAddrs"
  486. stripe
  487. highlight-current-row
  488. border
  489. @row-dblclick="rowDblclick4"
  490. style="width: 100%;">
  491. <el-table-column
  492. prop="cDeliverUnit"
  493. header-align="left"
  494. align="left"
  495. width="350"
  496. label="收货单位">
  497. </el-table-column>
  498. <el-table-column
  499. prop="deliverycountry"
  500. header-align="center"
  501. align="left"
  502. label="运抵国">
  503. </el-table-column>
  504. </el-table>
  505. <el-footer style="height:40px;margin-top: 10px;text-align:center">
  506. <el-button @click="overseasShipperFlag = false; currentRow = null">关闭</el-button>
  507. </el-footer>
  508. </el-dialog>
  509. <!-- 大输入框编辑弹窗 -->
  510. <el-dialog
  511. :title="editDialog.title"
  512. :visible.sync="editDialog.visible"
  513. width="600px"
  514. class="edit-dialog"
  515. @close="closeEditDialog">
  516. <div class="edit-dialog-tip">
  517. <i class="el-icon-info"></i> 提示您可以在此编辑较长的文本内容支持多行输入
  518. </div>
  519. <el-form label-position="top" style="margin-bottom: 120px">
  520. <el-form-item :label="editDialog.label">
  521. <el-input ref="editTextarea"
  522. v-model="editDialog.value"
  523. type="textarea"
  524. :rows="6"
  525. placeholder="请输入内容,支持多行文本..."
  526. maxlength="500"
  527. show-word-limit
  528. class="edit-textarea">
  529. </el-input>
  530. </el-form-item>
  531. </el-form>
  532. <span slot="footer" class="dialog-footer">
  533. <el-button @click="closeEditDialog">取消</el-button>
  534. <el-button type="primary" @click="confirmEdit">保存</el-button>
  535. </span>
  536. </el-dialog>
  537. <!-- 物料不存在详情对话框 -->
  538. <el-dialog
  539. :title="`发票号 ${invalidMaterialsDialog.invoice} - 不存在的物料详情`"
  540. :visible.sync="invalidMaterialsDialog.visible"
  541. width="320px"
  542. class="invalid-materials-dialog"
  543. @close="closeInvalidMaterialsDialog">
  544. <div class="invalid-materials-content">
  545. <el-table
  546. :data="invalidMaterialsDialog.materials"
  547. border
  548. style="width: 100%; margin-top: 15px;"
  549. max-height="300">
  550. <el-table-column
  551. type="index"
  552. label="序号"
  553. width="60"
  554. align="center">
  555. </el-table-column>
  556. <el-table-column
  557. prop="material"
  558. label="物料号"
  559. align="left">
  560. <template slot-scope="scope">
  561. <span style="color: #F56C6C; font-weight: bold;">{{ scope.row }}</span>
  562. </template>
  563. </el-table-column>
  564. </el-table>
  565. <div class="materials-summary" style="margin-top: 15px; padding: 10px; background-color: #FEF0F0; border-radius: 4px;">
  566. <span style="color: #F56C6C;">
  567. <i class="el-icon-info"></i>
  568. 共发现 <strong>{{ invalidMaterialsDialog.materials.length }}</strong> 个不存在的物料
  569. </span>
  570. </div>
  571. </div>
  572. <span slot="footer" class="dialog-footer">
  573. <el-button type="primary" @click="closeInvalidMaterialsDialog">确定</el-button>
  574. </span>
  575. </el-dialog>
  576. </div>
  577. </template>
  578. <script>
  579. import {queryFileId} from "@/api/qc/qc.js"
  580. import {previewExcelTX,saveEcssCoDelNotifyByExcelTX,getCustomerList,getCustomers,getCustomerAdd,getCustomerTemplateList,saveExcelImportTemplate} from '@/api/ecss/ecss.js'
  581. import {downLoadObjectFile} from '@/api/eam/eam_object_list.js'
  582. import {getBuList}from '@/api/factory/site.js'
  583. export default {
  584. name: 'delUploadExcelTx',
  585. data() {
  586. return {
  587. buList: [],
  588. titleCon: '天线/硬标导入',
  589. visible: false,
  590. fileList: [],
  591. pageData: {
  592. site: '',
  593. buNo: '',
  594. createBy: this.$store.state.user.name,
  595. customerName:'',
  596. localShipAddress:'',
  597. overseasShipper:'',
  598. overseasAddress:'',
  599. cnative:'',
  600. salesArea:'',
  601. },
  602. previewData: [], // 预览数据
  603. showPreview: false, // 是否显示预览
  604. selectedFile: null, // 选择的文件
  605. previewLoading: false, // 预览加载状态
  606. saveButtonLoading: false, // 保存按钮加载状态
  607. confirmSaveButtonLoading: false, // 确认保存按钮加载状态
  608. deletedInvoices: [], // 被删除的发票号列表
  609. sheetErrors: [], // Sheet错误信息列表
  610. customSearchData: {},
  611. customerList : [],//所有客户
  612. customerAddrs : [],//地址
  613. customerPersons : [],//联系人
  614. customerMap:new Map,
  615. customFlag:false,
  616. localShipAddressFlag:false,
  617. overseasShipperFlag:false,
  618. overseasAddressFlag:false,
  619. templateFlag:false,
  620. customerTemplateList: [],//客户模板列表
  621. templateSearchData: {
  622. templateName: '',
  623. customerName: '',
  624. buNo: ''
  625. },//模板搜索条件
  626. cacheKey: '', // 缓存键
  627. cacheTimer: null, // 缓存定时器
  628. currentRow: null, // 当前编辑的行
  629. cachedFileInfo: null, // 缓存的文件信息
  630. cachedFileList: [], // 缓存的文件列表
  631. // 大输入框编辑弹窗相关数据
  632. editDialog: {
  633. visible: false,
  634. title: '',
  635. label: '',
  636. value: '',
  637. fieldName: '', // 要编辑的字段名
  638. row: null // 当前编辑的行数据
  639. },
  640. // 物料不存在详情对话框相关数据
  641. invalidMaterialsDialog: {
  642. visible: false,
  643. invoice: '',
  644. materials: []
  645. },
  646. // 批量删除相关数据
  647. selectedRows: [] // 选中的行
  648. }
  649. },
  650. computed: {
  651. // 可导入的发票(不包含物料不存在的发票)
  652. validInvoices() {
  653. return this.previewData.filter(item => !item.hasInvalidMaterials)
  654. },
  655. // 物料不存在的发票
  656. invalidInvoices() {
  657. return this.previewData.filter(item => item.hasInvalidMaterials)
  658. }
  659. },
  660. watch: {
  661. // 深度监听pageData的变化,自动保存到缓存
  662. pageData: {
  663. handler: function(newVal, oldVal) {
  664. // 只有在组件已初始化且对话框可见时才保存缓存
  665. if (this.visible && this.cacheKey) {
  666. this.saveToCache();
  667. }
  668. },
  669. deep: true
  670. },
  671. // 深度监听previewData的变化,保存用户的编辑
  672. previewData: {
  673. handler: function(newVal, oldVal) {
  674. // 只有在组件已初始化且对话框可见时才保存缓存
  675. if (this.visible && this.cacheKey && newVal && newVal.length > 0) {
  676. this.saveToCache();
  677. }
  678. },
  679. deep: true
  680. }
  681. },
  682. beforeDestroy() {
  683. // 组件销毁前清理定时器
  684. if (this.cacheTimer) {
  685. clearTimeout(this.cacheTimer);
  686. }
  687. },
  688. methods: {
  689. // 生成缓存键
  690. generateCacheKey() {
  691. const userId = this.$store.state.user.id || this.$store.state.user.name;
  692. return `ecss_del_upload_cache_${userId}`;
  693. },
  694. // 保存数据到缓存(防抖处理)
  695. saveToCache() {
  696. // 清除之前的定时器
  697. if (this.cacheTimer) {
  698. clearTimeout(this.cacheTimer);
  699. }
  700. // 设置新的定时器,500ms后执行保存
  701. this.cacheTimer = setTimeout(() => {
  702. try {
  703. const cacheData = {
  704. pageData: {
  705. buNo: this.pageData.buNo,
  706. customerName: this.pageData.customerName,
  707. localShipAddress: this.pageData.localShipAddress,
  708. overseasShipper: this.pageData.overseasShipper,
  709. overseasAddress: this.pageData.overseasAddress,
  710. cnative: this.pageData.cnative,
  711. salesArea: this.pageData.salesArea,
  712. },
  713. // 保存文件和预览相关数据
  714. fileInfo: this.selectedFile ? {
  715. name: this.selectedFile.name,
  716. size: this.selectedFile.size,
  717. lastModified: this.selectedFile.lastModified
  718. } : null,
  719. showPreview: this.showPreview,
  720. previewData: this.previewData,
  721. deletedInvoices: this.deletedInvoices,
  722. fileList: this.fileList.map(file => ({
  723. name: file.name,
  724. size: file.size,
  725. lastModified: file.lastModified,
  726. uid: file.uid
  727. }))
  728. };
  729. localStorage.setItem(this.cacheKey, JSON.stringify(cacheData));
  730. } catch (error) {
  731. console.warn('保存缓存失败:', error);
  732. }
  733. }, 500);
  734. },
  735. // 从缓存加载数据
  736. loadFromCache() {
  737. try {
  738. const cachedData = localStorage.getItem(this.cacheKey);
  739. if (cachedData) {
  740. const parsedData = JSON.parse(cachedData);
  741. if (parsedData.pageData) {
  742. // 恢复基础表单数据
  743. Object.assign(this.pageData, parsedData.pageData);
  744. // 恢复预览数据和文件状态
  745. if (parsedData.previewData && parsedData.previewData.length > 0) {
  746. this.previewData = parsedData.previewData;
  747. this.showPreview = parsedData.showPreview || false;
  748. }
  749. // 恢复删除的发票号列表
  750. if (parsedData.deletedInvoices) {
  751. this.deletedInvoices = parsedData.deletedInvoices;
  752. }
  753. // 恢复文件列表信息(用于界面显示)
  754. if (parsedData.fileList && parsedData.fileList.length > 0) {
  755. // 记录缓存的文件信息,用于后续比对
  756. this.cachedFileInfo = parsedData.fileInfo;
  757. this.cachedFileList = parsedData.fileList;
  758. }
  759. return true;
  760. }
  761. }
  762. } catch (error) {
  763. console.warn('加载缓存失败:', error);
  764. }
  765. return false;
  766. },
  767. // 清除缓存
  768. clearCache() {
  769. try {
  770. localStorage.removeItem(this.cacheKey);
  771. } catch (error) {
  772. console.warn('清除缓存失败:', error);
  773. }
  774. },
  775. // 检查并恢复文件状态
  776. checkAndRestoreFileState() {
  777. // 检查上传组件中是否有文件
  778. const uploadFiles = this.$refs.uploadFile.uploadFiles;
  779. if (this.cachedFileInfo && this.cachedFileList.length > 0) {
  780. // 如果有缓存的文件信息,检查当前上传组件中的文件
  781. if (uploadFiles && uploadFiles.length > 0) {
  782. const currentFile = uploadFiles[0];
  783. const isSameFile = currentFile.name === this.cachedFileInfo.name &&
  784. currentFile.size === this.cachedFileInfo.size &&
  785. currentFile.lastModified === this.cachedFileInfo.lastModified;
  786. if (isSameFile) {
  787. // 是同一个文件,恢复文件相关状态
  788. this.selectedFile = currentFile;
  789. this.fileList = [currentFile];
  790. console.log('恢复文件状态:', currentFile.name);
  791. } else {
  792. // 文件不匹配,清除预览状态但保留表单数据
  793. this.showPreview = false;
  794. this.previewData = [];
  795. this.selectedFile = null;
  796. this.fileList = [];
  797. console.log('文件不匹配,清除预览状态');
  798. }
  799. } else {
  800. // 没有文件但有缓存,说明文件可能被清除了
  801. this.showPreview = false;
  802. this.previewData = [];
  803. this.selectedFile = null;
  804. this.fileList = [];
  805. console.log('没有找到文件,清除预览状态');
  806. }
  807. }
  808. // 保存当前状态
  809. this.saveToCache();
  810. },
  811. // 初始化组件的参数
  812. init () {
  813. // 初始化缓存键,但不清除任何现有数据
  814. this.cacheKey = this.generateCacheKey();
  815. this.previewLoading = false
  816. let tempData = {
  817. username: this.$store.state.user.name,
  818. }
  819. getBuList(tempData).then(({data}) => {
  820. if (data.code === 0) {
  821. this.buList = data.row2
  822. if(data.row2.length===1){
  823. this.pageData.buNo=data.row2[0].buNo
  824. }
  825. }
  826. // 在获取BU列表后尝试加载缓存
  827. this.loadFromCache();
  828. // 检查并恢复文件状态
  829. this.$nextTick(() => {
  830. this.checkAndRestoreFileState();
  831. });
  832. })
  833. getCustomerList({}).then(({data}) => {
  834. //区分请求成功和失败的状况
  835. if (data && data.code === 0) {
  836. this.customerList=data.rows
  837. }
  838. });
  839. // 只有在完全没有缓存数据时才初始化为空
  840. const hasCache = this.loadFromCache();
  841. if (!hasCache) {
  842. this.fileList = []
  843. this.previewData = []
  844. this.showPreview = false
  845. this.selectedFile = null
  846. this.deletedInvoices = []
  847. this.pageData.customerName=''
  848. this.pageData.cnative=''
  849. this.pageData.localShipAddress='',
  850. this.pageData.overseasShipper='',
  851. this.pageData.overseasAddress='',
  852. this.pageData.salesArea=''
  853. }
  854. this.customerPersons=[]
  855. this.customerAddrs=[]
  856. // 打开页面
  857. this.visible = true
  858. },
  859. getCustomerList(){
  860. getCustomerList(this.customSearchData).then(({data}) => {
  861. //区分请求成功和失败的状况
  862. if (data && data.code === 0) {
  863. this.customerList=data.rows
  864. }
  865. });
  866. },
  867. getCusPersons(){
  868. let cusData = {ccusname: this.pageData.customerName}
  869. getCustomers(cusData).then(({data}) => {
  870. //区分请求成功和失败的状况
  871. if (data && data.code === 0) {
  872. this.customerPersons=data.rows
  873. this.customerPersons.forEach(o => {
  874. if (!this.customerMap.has(o.ccontactname)) {
  875. this.customerMap.set(o.ccontactname, o.cnative);
  876. }
  877. });
  878. }
  879. });
  880. getCustomerAdd(cusData).then(({data}) => {
  881. //区分请求成功和失败的状况
  882. if (data && data.code === 0) {
  883. this.customerAddrs=data.rows
  884. }
  885. });
  886. },
  887. setCnative(){
  888. this.pageData.cnative=this.customerMap.get(this.pageData.overseasShipper)
  889. },
  890. closeCustomDialog () {
  891. this.customFlag = false
  892. this.currentRow = null
  893. },
  894. rowDblclickTemplate(row) {
  895. console.log(row)
  896. if (this.currentRow) {
  897. // 使用模板设置当前行的所有信息
  898. this.currentRow.templateNo = row.template_no
  899. this.currentRow.ccuscode = row.ccuscode
  900. this.currentRow.selectedTemplate = row.template_name
  901. this.currentRow.originalTemplateName = row.template_name // 保存原始模板名称,用于判断是否修改
  902. this.currentRow.selectedCustomer = row.ccusname || ''
  903. this.currentRow.selectedLocalAddress = row.localShipAddress || ''
  904. this.currentRow.selectedOverseasShipper = row.overseasShipper || ''
  905. this.currentRow.selectedOverseasAddress = row.overseasAddress || ''
  906. this.currentRow.selectedCnative = row.cnative || ''
  907. this.currentRow.selectedSalesArea = row.salesArea || ''
  908. // 如果模板中有客户信息,自动获取该客户的地址和收货单位信息
  909. if (row.ccusname) {
  910. this.getCusPersonsForRow(row.ccusname)
  911. }
  912. }
  913. this.templateFlag = false
  914. this.currentRow = null
  915. },
  916. rowDblclick (row) {
  917. if (this.currentRow) {
  918. // 预览模式下,为当前行设置客户信息
  919. this.currentRow.selectedCustomer = row.ccusname
  920. this.currentRow.selectedSalesArea = row.country
  921. this.currentRow.selectedLocalAddress = ''
  922. this.currentRow.selectedOverseasShipper = ''
  923. this.currentRow.selectedOverseasAddress = ''
  924. this.currentRow.selectedCnative = ''
  925. this.getCusPersonsForRow(row.ccusname)
  926. } else {
  927. // 普通模式下,设置全局信息
  928. this.pageData.customerName=row.ccusname
  929. this.pageData.cnative='',
  930. this.pageData.localShipAddress='',
  931. this.pageData.overseasShipper='',
  932. this.pageData.overseasAddress='',
  933. this.pageData.salesArea = row.country
  934. this.getCusPersons()
  935. }
  936. this.customFlag = false
  937. },
  938. rowDblclick2 (row) {
  939. if (this.currentRow) {
  940. this.currentRow.selectedLocalAddress = row.cDeliverAdd
  941. } else {
  942. this.pageData.localShipAddress = row.cDeliverAdd
  943. }
  944. this.localShipAddressFlag = false
  945. this.currentRow = null
  946. },
  947. rowDblclick3 (row) {
  948. if (this.currentRow) {
  949. this.currentRow.selectedOverseasAddress = row.cDeliverAdd
  950. } else {
  951. this.pageData.overseasAddress = row.cDeliverAdd
  952. }
  953. this.overseasAddressFlag = false
  954. this.currentRow = null
  955. },
  956. rowDblclick4 (row) {
  957. if (this.currentRow) {
  958. this.currentRow.selectedOverseasShipper = row.cDeliverUnit
  959. this.currentRow.selectedCnative = row.deliverycountry
  960. } else {
  961. this.pageData.overseasShipper = row.cDeliverUnit
  962. this.pageData.cnative = row.deliverycountry
  963. }
  964. this.overseasShipperFlag = false
  965. this.currentRow = null
  966. },
  967. // 上传之前
  968. beforeUploadHandle (file) {
  969. let extName = file[0].name.substring(file[0].name.lastIndexOf('.')).toLowerCase()
  970. if (!(extName === '.xlsx' || extName === '.xls')) {
  971. this.$message.error('数据导入失败,请选择正确的xlsx模板文件')
  972. return false
  973. }
  974. },
  975. // 选择上传文件时
  976. onChange (file) {
  977. this.fileList.push(file)
  978. this.selectedFile = file
  979. this.previewFile(file)
  980. // 保存文件信息到缓存
  981. this.saveToCache()
  982. },
  983. // 关闭modal
  984. closeDialog () {
  985. // 保存当前状态到缓存
  986. this.saveToCache()
  987. // 关闭当前的页面
  988. this.visible = false
  989. this.$emit('refreshTable')
  990. },
  991. deleteFile(){
  992. // 只有在明确需要清除数据时才调用此方法
  993. this.fileList = []
  994. this.previewData = []
  995. this.showPreview = false
  996. this.selectedFile = null
  997. this.deletedInvoices = []
  998. this.cachedFileInfo = null
  999. this.cachedFileList = []
  1000. // 清空文件上传记录
  1001. this.$refs.uploadFile.clearFiles()
  1002. // 清除缓存
  1003. this.clearCache()
  1004. // 刷新报工的页面
  1005. this.$emit('refreshTable')
  1006. },
  1007. // 保修当前的数据
  1008. saveUploadFile () {
  1009. if (null == this.pageData.buNo || this.pageData.buNo=='') {
  1010. this.$message.error("请先选择BU!")
  1011. return false
  1012. }
  1013. if (null == this.pageData.customerName || this.pageData.customerName=='') {
  1014. this.$message.error("请先选择客户!")
  1015. return false
  1016. }
  1017. if (null == this.pageData.localShipAddress || this.pageData.localShipAddress=='') {
  1018. this.$message.error("请先填写客户发货地址!")
  1019. return false
  1020. }
  1021. if (null == this.pageData.overseasShipper || this.pageData.overseasShipper=='') {
  1022. this.$message.error("请先填写收货单位!")
  1023. return false
  1024. }
  1025. if (null == this.pageData.overseasAddress || this.pageData.overseasAddress=='') {
  1026. this.$message.error("请先填写收货单位地址!")
  1027. return false
  1028. }
  1029. if (null == this.pageData.cnative || this.pageData.cnative=='') {
  1030. this.$message.error("请先填写收货单位运抵国!")
  1031. return false
  1032. }
  1033. // 判断文件是否上传
  1034. if (null == this.fileList || 0 === this.fileList.length) {
  1035. this.$message.error("请先上传文件!")
  1036. return false
  1037. }
  1038. this.saveButtonLoading = true // 开始加载
  1039. const formData = new FormData()
  1040. formData.append("buNo",this.pageData.buNo)
  1041. formData.append("username",this.$store.state.user.name)
  1042. formData.append("file", this.fileList[0].raw)
  1043. formData.append("customerName", this.pageData.customerName)
  1044. formData.append("localShipAddress", this.pageData.localShipAddress)
  1045. formData.append("overseasShipper", this.pageData.overseasShipper)
  1046. formData.append("overseasAddress", this.pageData.overseasAddress)
  1047. formData.append("cnative", this.pageData.cnative)
  1048. formData.append("salesArea", this.pageData.salesArea)
  1049. saveEcssCoDelNotifyByExcelTX(formData).then(({ data }) => {
  1050. if (data.code === 0) {
  1051. const { resultMap } = data;
  1052. const successList = resultMap.success || [];
  1053. const failList = resultMap.fail || [];
  1054. // 紧凑样式
  1055. let html = `
  1056. <div style="max-height:380px;overflow:auto;font-size:12px;line-height:1.4;">
  1057. `;
  1058. if (successList.length > 0) {
  1059. html += `<div style="margin-bottom:6px;">
  1060. <div style="color:green;font-weight:bold;margin-bottom:3px;">
  1061. 成功${successList.length}
  1062. </div>
  1063. <table border="1" cellspacing="0" cellpadding="2"
  1064. style="border-collapse:collapse;width:100%;">
  1065. `;
  1066. successList.forEach(item => {
  1067. html += `<tr><td style="color:green;padding:2px 4px;">${item}</td></tr>`;
  1068. });
  1069. html += `</table></div>`;
  1070. }
  1071. if (failList.length > 0) {
  1072. html += `<div>
  1073. <div style="color:red;font-weight:bold;margin-bottom:3px;">
  1074. 失败${failList.length}
  1075. </div>
  1076. <table border="1" cellspacing="0" cellpadding="2"
  1077. style="border-collapse:collapse;width:100%;">
  1078. `;
  1079. failList.forEach(item => {
  1080. html += `<tr><td style="color:red;padding:2px 4px;">${item}</td></tr>`;
  1081. });
  1082. html += `</table></div>`;
  1083. }
  1084. html += `</div>`;
  1085. this.$alert(html, '导入结果', {
  1086. confirmButtonText: '确定',
  1087. dangerouslyUseHTMLString: true,
  1088. callback: () => {
  1089. if (successList.length > 0){
  1090. this.clearCache();
  1091. this.clearPreviewData();
  1092. this.closeDialog();
  1093. }
  1094. }
  1095. });
  1096. } else {
  1097. this.$alert(data.msg, '错误', {
  1098. confirmButtonText: '确定'
  1099. });
  1100. }
  1101. }).catch(error => {
  1102. this.$message.error('保存失败:' + (error.message || '网络异常'))
  1103. }).finally(() => {
  1104. this.saveButtonLoading = false // 结束加载
  1105. });
  1106. },
  1107. // 预览文件
  1108. async previewFile(file) {
  1109. if (!file || !file.raw) {
  1110. return
  1111. }
  1112. if (!this.pageData.buNo) {
  1113. this.$message.error('请先选择BU!')
  1114. this.fileList = []
  1115. this.$refs.uploadFile.clearFiles()
  1116. return
  1117. }
  1118. this.previewLoading = true // 开始加载
  1119. const formData = new FormData()
  1120. formData.append("file", file.raw)
  1121. formData.append("buNo", this.pageData.buNo)
  1122. try {
  1123. const { data } = await previewExcelTX(formData)
  1124. if (data.code === 0) {
  1125. this.previewData = data.data || []
  1126. this.sheetErrors = data.sheetErrors || []
  1127. this.showPreview = true
  1128. // 清空删除列表,因为这是新的文件预览
  1129. this.deletedInvoices = []
  1130. // 如果有Sheet错误,显示警告信息
  1131. if (this.sheetErrors.length > 0) {
  1132. const skippedCount = this.sheetErrors.filter(e => e.skipped).length
  1133. const errorCount = this.sheetErrors.filter(e => !e.skipped).length
  1134. let message = `文件解析完成,但有 ${this.sheetErrors.length} 个Sheet存在问题`
  1135. if (skippedCount > 0) {
  1136. message += `${skippedCount}个已跳过`
  1137. }
  1138. if (errorCount > 0) {
  1139. message += `${skippedCount > 0 ? ',' : '('}${errorCount}个处理失败`
  1140. }
  1141. message += '),请查看详细信息'
  1142. this.$message.warning(message)
  1143. }
  1144. // 为每个发票号初始化客户信息
  1145. this.previewData.forEach(item => {
  1146. this.$set(item, 'templateNo', '')
  1147. this.$set(item, 'ccuscode', '')
  1148. this.$set(item, 'selectedTemplate', '')
  1149. this.$set(item, 'originalTemplateName', '')
  1150. this.$set(item, 'selectedCustomer', '')
  1151. this.$set(item, 'selectedLocalAddress', '')
  1152. this.$set(item, 'selectedOverseasShipper', '')
  1153. this.$set(item, 'selectedOverseasAddress', '')
  1154. this.$set(item, 'selectedCnative', '')
  1155. this.$set(item, 'selectedSalesArea','')
  1156. })
  1157. // 预览成功后立即保存缓存
  1158. this.saveToCache()
  1159. } else {
  1160. this.$message.error(data.msg || '文件预览失败')
  1161. }
  1162. } catch (error) {
  1163. this.$message.error('文件预览失败:' + error.message)
  1164. } finally {
  1165. this.previewLoading = false // 结束加载
  1166. }
  1167. },
  1168. // 从预览数据保存
  1169. saveFromPreview() {
  1170. // 检查是否有可导入的发票
  1171. if (this.validInvoices.length === 0) {
  1172. this.$message.warning('没有可导入的发票!')
  1173. return false
  1174. }
  1175. // 只验证可导入发票的必填信息
  1176. for (let item of this.validInvoices) {
  1177. if (!item.selectedCustomer) {
  1178. this.$message.error(`发票号 ${item.cmcInvoice} 请选择客户`)
  1179. return false
  1180. }
  1181. if (!item.selectedLocalAddress) {
  1182. this.$message.error(`发票号 ${item.cmcInvoice} 请填写客户地址`)
  1183. return false
  1184. }
  1185. if (!item.selectedOverseasShipper) {
  1186. this.$message.error(`发票号 ${item.cmcInvoice} 请填写收货单位`)
  1187. return false
  1188. }
  1189. if (!item.selectedOverseasAddress) {
  1190. this.$message.error(`发票号 ${item.cmcInvoice} 请填写收货单位地址`)
  1191. return false
  1192. }
  1193. if (!item.selectedCnative) {
  1194. this.$message.error(`发票号 ${item.cmcInvoice} 请填写运抵国`)
  1195. return false
  1196. }
  1197. }
  1198. this.confirmSaveButtonLoading = true // 开始加载
  1199. // 发送保存请求
  1200. const formData = new FormData()
  1201. formData.append("buNo", this.pageData.buNo)
  1202. formData.append("username", this.$store.state.user.name)
  1203. formData.append("file", this.fileList[0].raw)
  1204. // 添加被删除的发票号列表(包括用户手动删除的和物料不存在的)
  1205. const allDeletedInvoices = [...this.deletedInvoices]
  1206. // 将物料不存在的发票也添加到删除列表中
  1207. this.invalidInvoices.forEach(item => {
  1208. if (!allDeletedInvoices.includes(item.cmcInvoice)) {
  1209. allDeletedInvoices.push(item.cmcInvoice)
  1210. }
  1211. })
  1212. formData.append("deletedInvoices", JSON.stringify(allDeletedInvoices))
  1213. // 只为可导入的发票设置客户信息
  1214. this.validInvoices.forEach((item, index) => {
  1215. formData.append(`templateNo_${item.cmcInvoice}`, item.templateNo)
  1216. formData.append(`customerName_${item.cmcInvoice}`, item.selectedCustomer)
  1217. formData.append(`localShipAddress_${item.cmcInvoice}`, item.selectedLocalAddress)
  1218. formData.append(`overseasShipper_${item.cmcInvoice}`, item.selectedOverseasShipper)
  1219. formData.append(`overseasAddress_${item.cmcInvoice}`, item.selectedOverseasAddress)
  1220. formData.append(`cnative_${item.cmcInvoice}`, item.selectedCnative)
  1221. formData.append(`salesArea_${item.cmcInvoice}`, item.selectedSalesArea)
  1222. })
  1223. saveEcssCoDelNotifyByExcelTX(formData).then(({ data }) => {
  1224. if (data.code === 0) {
  1225. const { resultMap } = data;
  1226. const successList = resultMap.success || [];
  1227. const failList = resultMap.fail || [];
  1228. // 紧凑样式
  1229. let html = `
  1230. <div style="max-height:380px;overflow:auto;font-size:12px;line-height:1.4;">
  1231. `;
  1232. if (successList.length > 0) {
  1233. html += `<div style="margin-bottom:6px;">
  1234. <div style="color:green;font-weight:bold;margin-bottom:3px;">
  1235. 成功${successList.length}
  1236. </div>
  1237. <table border="1" cellspacing="0" cellpadding="2"
  1238. style="border-collapse:collapse;width:100%;">
  1239. `;
  1240. successList.forEach(item => {
  1241. html += `<tr><td style="color:green;padding:2px 4px;">${item}</td></tr>`;
  1242. });
  1243. html += `</table></div>`;
  1244. }
  1245. if (failList.length > 0) {
  1246. html += `<div>
  1247. <div style="color:red;font-weight:bold;margin-bottom:3px;">
  1248. 失败${failList.length}
  1249. </div>
  1250. <table border="1" cellspacing="0" cellpadding="2"
  1251. style="border-collapse:collapse;width:100%;">
  1252. `;
  1253. failList.forEach(item => {
  1254. html += `<tr><td style="color:red;padding:2px 4px;">${item}</td></tr>`;
  1255. });
  1256. html += `</table></div>`;
  1257. }
  1258. html += `</div>`;
  1259. this.$alert(html, '导入结果', {
  1260. confirmButtonText: '确定',
  1261. dangerouslyUseHTMLString: true,
  1262. callback: () => {
  1263. if (successList.length > 0){
  1264. this.clearCache();
  1265. this.clearPreviewData();
  1266. this.closeDialog();
  1267. }
  1268. }
  1269. });
  1270. } else {
  1271. this.$alert(data.msg, '错误', {
  1272. confirmButtonText: '确定'
  1273. });
  1274. }
  1275. }).catch(error => {
  1276. this.$message.error('保存失败:' + (error.message || '网络异常'))
  1277. }).finally(() => {
  1278. this.confirmSaveButtonLoading = false // 结束加载
  1279. });
  1280. },
  1281. // 取消预览
  1282. cancelPreview() {
  1283. this.showPreview = false
  1284. this.previewData = []
  1285. this.sheetErrors = []
  1286. this.fileList = []
  1287. this.selectedFile = null
  1288. this.deletedInvoices = []
  1289. this.cachedFileInfo = null
  1290. this.cachedFileList = []
  1291. this.$refs.uploadFile.clearFiles()
  1292. // 更新缓存
  1293. this.saveToCache()
  1294. },
  1295. // 清除预览数据
  1296. clearPreviewData() {
  1297. this.previewData = []
  1298. this.sheetErrors = []
  1299. this.showPreview = false
  1300. this.selectedFile = null
  1301. this.fileList = []
  1302. this.deletedInvoices = []
  1303. this.previewLoading = false
  1304. this.cachedFileInfo = null
  1305. this.cachedFileList = []
  1306. this.$refs.uploadFile.clearFiles()
  1307. // 更新缓存
  1308. this.saveToCache()
  1309. },
  1310. // 为行选择客户模板
  1311. selectTemplateForRow(row) {
  1312. this.currentRow = row
  1313. this.templateSearchData.buNo = this.pageData.buNo || ''
  1314. this.getCustomerTemplateList()
  1315. this.templateFlag = true
  1316. },
  1317. // 为行选择客户
  1318. selectCustomerForRow(row) {
  1319. this.currentRow = row
  1320. this.customFlag = true
  1321. },
  1322. // 为行选择客户地址
  1323. selectLocalAddressForRow(row) {
  1324. if (!row.selectedCustomer) {
  1325. this.$message.warning('请先选择客户')
  1326. return
  1327. }
  1328. this.currentRow = row
  1329. this.getCusPersonsForRow(row.selectedCustomer)
  1330. this.localShipAddressFlag = true
  1331. },
  1332. // 为行选择收货单位
  1333. selectOverseasShipperForRow(row) {
  1334. if (!row.selectedCustomer) {
  1335. this.$message.warning('请先选择客户')
  1336. return
  1337. }
  1338. this.currentRow = row
  1339. this.getCusPersonsForRow(row.selectedCustomer)
  1340. this.overseasShipperFlag = true
  1341. },
  1342. // 为行选择收货单位地址
  1343. selectOverseasAddressForRow(row) {
  1344. if (!row.selectedCustomer) {
  1345. this.$message.warning('请先选择客户')
  1346. return
  1347. }
  1348. this.currentRow = row
  1349. this.getCusPersonsForRow(row.selectedCustomer)
  1350. this.overseasAddressFlag = true
  1351. },
  1352. // 按BU映射模板的bu_no规则
  1353. getTemplateBuNoByBu(buNo) {
  1354. const sourceBu = (buNo || '').toString().trim()
  1355. if (!sourceBu) {
  1356. return ''
  1357. }
  1358. const upperBu = sourceBu.toUpperCase()
  1359. const buCodeMatch = upperBu.match(/\d{2}/)
  1360. const buCode = buCodeMatch ? buCodeMatch[0] : ''
  1361. if (['01', '03'].includes(buCode) || upperBu.includes('RFID') || upperBu.includes('LABEL') || upperBu.includes('软标')) {
  1362. return '03-RFID,01-Label'
  1363. }
  1364. if (['02', '05'].includes(buCode) || upperBu.includes('HARD') || upperBu.includes('ALPHA') || upperBu.includes('硬标')) {
  1365. return '02-Hardtag,05-Alpha'
  1366. }
  1367. if (buCode === '04' || upperBu.includes('MHM') || upperBu.includes('天线')) {
  1368. return '04-MHM'
  1369. }
  1370. return sourceBu
  1371. },
  1372. // 解析逗号分隔的bu_no
  1373. parseTemplateBuNoList(templateBuNo) {
  1374. return (templateBuNo || '')
  1375. .toString()
  1376. .split(',')
  1377. .map(item => item.trim())
  1378. .filter(item => item)
  1379. },
  1380. // 构造模板查询参数
  1381. buildTemplateSearchParams(searchParams = {}) {
  1382. const mergedBuNo = searchParams.buNo !== undefined
  1383. ? searchParams.buNo
  1384. : (this.templateSearchData.buNo || this.pageData.buNo || '')
  1385. const templateBuNo = this.getTemplateBuNoByBu(mergedBuNo)
  1386. const params = {
  1387. templateName: searchParams.templateName !== undefined ? searchParams.templateName : this.templateSearchData.templateName,
  1388. customerName: searchParams.customerName !== undefined ? searchParams.customerName : this.templateSearchData.customerName
  1389. }
  1390. if (mergedBuNo) {
  1391. params.buNo = mergedBuNo
  1392. }
  1393. if (templateBuNo) {
  1394. params.templateBuNo = templateBuNo
  1395. }
  1396. return params
  1397. },
  1398. // 前端兜底:只保留命中当前BU组的模板
  1399. filterTemplateListByBu(templateList, selectedBuNo) {
  1400. const expectedBuList = this.parseTemplateBuNoList(this.getTemplateBuNoByBu(selectedBuNo))
  1401. if (expectedBuList.length === 0) {
  1402. return templateList || []
  1403. }
  1404. return (templateList || []).filter(item => {
  1405. const itemBuList = this.parseTemplateBuNoList(item.bu_no || item.buNo)
  1406. return itemBuList.some(itemBu => expectedBuList.includes(itemBu))
  1407. })
  1408. },
  1409. // 获取客户模板列表
  1410. async getCustomerTemplateList(searchParams = {}) {
  1411. const requestParams = this.buildTemplateSearchParams(searchParams)
  1412. try {
  1413. const { data } = await getCustomerTemplateList(requestParams)
  1414. if (data && data.code === 0) {
  1415. this.customerTemplateList = this.filterTemplateListByBu(data.rows || [], requestParams.buNo)
  1416. } else {
  1417. this.customerTemplateList = []
  1418. }
  1419. } catch (error) {
  1420. console.error('获取客户模板列表失败:', error)
  1421. this.customerTemplateList = []
  1422. }
  1423. },
  1424. // 搜索客户模板
  1425. searchTemplateList() {
  1426. const searchParams = {
  1427. templateName: this.templateSearchData.templateName,
  1428. customerName: this.templateSearchData.customerName,
  1429. buNo: this.templateSearchData.buNo || this.pageData.buNo || ''
  1430. }
  1431. this.getCustomerTemplateList(searchParams)
  1432. },
  1433. // 重置模板搜索
  1434. resetTemplateSearch() {
  1435. this.templateSearchData = {
  1436. templateName: '',
  1437. customerName: '',
  1438. buNo: this.pageData.buNo || ''
  1439. }
  1440. this.getCustomerTemplateList()
  1441. },
  1442. // 获取特定客户的地址信息
  1443. getCusPersonsForRow(customerName) {
  1444. let cusData = {ccusname: customerName}
  1445. getCustomers(cusData).then(({data}) => {
  1446. if (data && data.code === 0) {
  1447. this.customerPersons = data.rows
  1448. this.customerPersons.forEach(o => {
  1449. if (!this.customerMap.has(o.ccontactname)) {
  1450. this.customerMap.set(o.ccontactname, o.cnative);
  1451. }
  1452. });
  1453. }
  1454. });
  1455. getCustomerAdd(cusData).then(({data}) => {
  1456. if (data && data.code === 0) {
  1457. this.customerAddrs = data.rows
  1458. }
  1459. });
  1460. },
  1461. // 打开大输入框编辑弹窗
  1462. openEditDialog(row, fieldName, label, title) {
  1463. this.editDialog.visible = true
  1464. this.editDialog.title = title
  1465. this.editDialog.label = label
  1466. this.editDialog.fieldName = fieldName
  1467. this.editDialog.row = row
  1468. this.editDialog.value = row[fieldName] || ''
  1469. this.$nextTick(() => this.$refs.editTextarea.focus());
  1470. },
  1471. // 关闭大输入框编辑弹窗
  1472. closeEditDialog() {
  1473. this.editDialog.visible = false
  1474. this.editDialog.title = ''
  1475. this.editDialog.label = ''
  1476. this.editDialog.fieldName = ''
  1477. this.editDialog.row = null
  1478. this.editDialog.value = ''
  1479. },
  1480. // 确认编辑
  1481. confirmEdit() {
  1482. if (this.editDialog.row && this.editDialog.fieldName) {
  1483. this.editDialog.row[this.editDialog.fieldName] = this.editDialog.value
  1484. }
  1485. this.closeEditDialog()
  1486. },
  1487. // 处理表格选择变化
  1488. handleSelectionChange(selection) {
  1489. this.selectedRows = selection
  1490. },
  1491. // 批量删除行
  1492. batchDeleteRows() {
  1493. if (this.selectedRows.length === 0) {
  1494. this.$message.warning('请先选择要删除的发票')
  1495. return
  1496. }
  1497. const invoiceNumbers = this.selectedRows.map(row => row.cmcInvoice).join('、')
  1498. this.$confirm(`确定要删除以下 ${this.selectedRows.length} 个发票吗?\n${invoiceNumbers}\n\n删除后将不会提交到后台。`, '批量删除确认', {
  1499. confirmButtonText: '确定删除',
  1500. cancelButtonText: '取消',
  1501. type: 'warning'
  1502. }).then(() => {
  1503. // 记录被删除的发票号并从预览数据中移除
  1504. this.selectedRows.forEach(row => {
  1505. // 记录被删除的发票号
  1506. if (!this.deletedInvoices.includes(row.cmcInvoice)) {
  1507. this.deletedInvoices.push(row.cmcInvoice)
  1508. }
  1509. // 从预览数据中移除该行
  1510. const previewIndex = this.previewData.findIndex(item => item.cmcInvoice === row.cmcInvoice)
  1511. if (previewIndex !== -1) {
  1512. this.previewData.splice(previewIndex, 1)
  1513. }
  1514. })
  1515. this.$message.success(`已成功删除 ${this.selectedRows.length} 个发票`)
  1516. // 清空选中状态
  1517. this.selectedRows = []
  1518. // 保存到缓存
  1519. this.saveToCache()
  1520. }).catch(() => {
  1521. // 用户取消删除
  1522. })
  1523. },
  1524. // 删除行
  1525. deleteRow(index, row) {
  1526. this.$confirm(`确定要删除发票号 "${row.cmcInvoice}" 吗?删除后将不会提交到后台。`, '删除确认', {
  1527. confirmButtonText: '确定删除',
  1528. cancelButtonText: '取消',
  1529. type: 'warning'
  1530. }).then(() => {
  1531. // 记录被删除的发票号
  1532. if (!this.deletedInvoices.includes(row.cmcInvoice)) {
  1533. this.deletedInvoices.push(row.cmcInvoice)
  1534. }
  1535. // 从预览数据中移除该行(根据发票号查找)
  1536. const previewIndex = this.previewData.findIndex(item => item.cmcInvoice === row.cmcInvoice)
  1537. if (previewIndex !== -1) {
  1538. this.previewData.splice(previewIndex, 1)
  1539. }
  1540. this.$message.success(`发票号 "${row.cmcInvoice}" 已删除`)
  1541. // 清空选中状态(如果删除的是选中的行)
  1542. this.selectedRows = this.selectedRows.filter(r => r.cmcInvoice !== row.cmcInvoice)
  1543. // 保存到缓存
  1544. this.saveToCache()
  1545. }).catch(() => {
  1546. // 用户取消删除
  1547. })
  1548. },
  1549. // 下载
  1550. async downloadFile () {
  1551. let file = {
  1552. id: 0,
  1553. fileName: ''
  1554. }
  1555. let tempData = {
  1556. orderRef1: 'ecss',
  1557. orderRef2: 'upLoadDel'
  1558. }
  1559. await queryFileId(tempData).then(({data}) => {
  1560. if (data && data.code === 0) {
  1561. file.id = data.data.id
  1562. file.fileName = data.data.fileName
  1563. } else {
  1564. this.$alert(data.msg, '错误', {
  1565. confirmButtonText: '确定'
  1566. })
  1567. }
  1568. })
  1569. await downLoadObjectFile(file).then(({data}) => {
  1570. // 不限制文件下载类型
  1571. const blob = new Blob([data], {type: "application/octet-stream"})
  1572. // 下载文件名称
  1573. const fileName = file.fileName
  1574. // a标签下载
  1575. const linkNode = document.createElement('a')
  1576. // a标签的download属性规定下载文件的名称
  1577. linkNode.download = fileName
  1578. linkNode.style.display = 'none'
  1579. // 生成一个Blob URL
  1580. linkNode.href = URL.createObjectURL(blob)
  1581. document.body.appendChild(linkNode)
  1582. // 模拟在按钮上的一次鼠标单击
  1583. linkNode.click()
  1584. // 释放URL 对象
  1585. URL.revokeObjectURL(linkNode.href)
  1586. document.body.removeChild(linkNode)
  1587. })
  1588. },
  1589. // 显示物料不存在详情
  1590. showInvalidMaterials(row) {
  1591. this.invalidMaterialsDialog.invoice = row.cmcInvoice
  1592. this.invalidMaterialsDialog.materials = row.invalidMaterials || []
  1593. this.invalidMaterialsDialog.visible = true
  1594. },
  1595. // 关闭物料不存在详情对话框
  1596. closeInvalidMaterialsDialog() {
  1597. this.invalidMaterialsDialog.visible = false
  1598. this.invalidMaterialsDialog.invoice = ''
  1599. this.invalidMaterialsDialog.materials = []
  1600. },
  1601. /**
  1602. * 检查行数据是否已准备好保存模板
  1603. * @param {Object} row - 行数据
  1604. * @return {boolean} 是否可以保存
  1605. */
  1606. isRowReadyForSave(row) {
  1607. return !!(row.selectedTemplate &&
  1608. row.selectedTemplate.trim() &&
  1609. row.selectedCustomer &&
  1610. row.selectedCustomer.trim())
  1611. },
  1612. /**
  1613. * 保存模板修改
  1614. * @param {Object} row - 行数据
  1615. */
  1616. async saveTemplateChanges(row) {
  1617. // 验证必填字段
  1618. if (!row.selectedTemplate || !row.selectedTemplate.trim()) {
  1619. this.$message.warning('请输入模板名称')
  1620. return
  1621. }
  1622. if (!row.selectedCustomer || !row.selectedCustomer.trim()) {
  1623. this.$message.warning('请填写客户信息')
  1624. return
  1625. }
  1626. const selectedBuNo = this.pageData.buNo || this.templateSearchData.buNo
  1627. const templateBuNo = this.getTemplateBuNoByBu(selectedBuNo)
  1628. if (!templateBuNo) {
  1629. this.$message.warning('请先选择BU')
  1630. return
  1631. }
  1632. // 判断操作类型,给用户明确提示
  1633. const isNewTemplate = !row.originalTemplateName || row.originalTemplateName === ''
  1634. const isNameChanged = row.originalTemplateName && row.selectedTemplate !== row.originalTemplateName
  1635. let confirmMessage = ''
  1636. if (isNewTemplate) {
  1637. // 手动输入的新模板名
  1638. confirmMessage = `确定要保存模板"${row.selectedTemplate}"吗?\n\n如果此模板名已存在,将会覆盖原有模板内容!`
  1639. } else if (isNameChanged) {
  1640. // 基于已选模板另存为新模板
  1641. confirmMessage = `确定要将模板"${row.originalTemplateName}"另存为"${row.selectedTemplate}"吗?\n\n如果"${row.selectedTemplate}"已存在,将会覆盖原有模板内容!`
  1642. } else {
  1643. // 更新原有模板
  1644. confirmMessage = `确定要更新模板"${row.selectedTemplate}"吗?\n\n此操作将覆盖原有模板内容!`
  1645. }
  1646. // 弹出确认对话框
  1647. try {
  1648. await this.$confirm(confirmMessage, '操作确认', {
  1649. confirmButtonText: '确定',
  1650. cancelButtonText: '取消',
  1651. type: 'warning',
  1652. distinguishCancelAndClose: true
  1653. })
  1654. } catch (error) {
  1655. // 用户取消操作
  1656. return
  1657. }
  1658. // 准备保存数据
  1659. const templateData = {
  1660. templateName: row.selectedTemplate.trim(),
  1661. // ✅ 修复Bug:保持空字符串不变,不要用 || 运算符替换
  1662. // 空字符串表示"新增或更新同名模板",非空表示"基于原模板修改"
  1663. originalTemplateName: row.originalTemplateName || '',
  1664. ccuscode: '', // 后端会根据实际情况自动处理
  1665. ccusname: row.selectedCustomer.trim(),
  1666. localShipAddress: row.selectedLocalAddress || '',
  1667. overseasShipper: row.selectedOverseasShipper || '',
  1668. overseasAddress: row.selectedOverseasAddress || '',
  1669. cnative: row.selectedCnative || '',
  1670. salesArea: row.selectedSalesArea || '',
  1671. buNo: selectedBuNo || '',
  1672. templateBuNo: templateBuNo
  1673. }
  1674. try {
  1675. const { data } = await saveExcelImportTemplate(templateData)
  1676. if (data && data.code === 0) {
  1677. // 判断是新增还是修改,给出不同的成功提示
  1678. if (isNewTemplate) {
  1679. this.$message.success(`模板"${row.selectedTemplate}"保存成功!`)
  1680. // 保存成功后更新 originalTemplateName,下次保存时就是修改模式
  1681. row.originalTemplateName = row.selectedTemplate
  1682. } else if (isNameChanged) {
  1683. this.$message.success(`新模板"${row.selectedTemplate}"另存成功!`)
  1684. // 另存为成功后更新 originalTemplateName
  1685. row.originalTemplateName = row.selectedTemplate
  1686. } else {
  1687. this.$message.success(`模板"${row.selectedTemplate}"更新成功!`)
  1688. }
  1689. // 保存成功后更新缓存
  1690. this.saveToCache()
  1691. } else {
  1692. this.$message.error(data.msg || '保存模板失败')
  1693. }
  1694. } catch (error) {
  1695. console.error('保存模板失败:', error)
  1696. this.$message.error('保存模板失败:' + (error.message || '网络异常'))
  1697. }
  1698. },
  1699. }
  1700. }
  1701. </script>
  1702. <style scoped>
  1703. /deep/ .delClass .cell {
  1704. line-height: 24px !important;
  1705. font-size: 12px !important;
  1706. height: 24px !important;
  1707. }
  1708. /deep/ .customer-upload .el-upload .el-upload-dragger {
  1709. width: 580px;
  1710. }
  1711. /* 输入框样式优化 */
  1712. .el-input.is-readonly {
  1713. cursor: pointer !important;
  1714. }
  1715. .el-input.is-readonly .el-input__inner {
  1716. cursor: pointer !important;
  1717. background-color: #f8f9fa;
  1718. }
  1719. .el-input.is-readonly .el-input__inner:hover {
  1720. background-color: #e9ecef;
  1721. border-color: #409EFF;
  1722. }
  1723. /* 编辑图标样式 */
  1724. .el-input__suffix .el-icon-edit {
  1725. color: #409EFF;
  1726. transition: all 0.3s;
  1727. font-size: 14px;
  1728. padding: 2px;
  1729. border-radius: 3px;
  1730. }
  1731. .el-input__suffix .el-icon-edit:hover {
  1732. color: #ffffff;
  1733. background-color: #409EFF;
  1734. transform: scale(1.1);
  1735. }
  1736. /* 编辑弹窗整体样式 */
  1737. .edit-dialog .el-dialog__body {
  1738. padding: 20px 20px 0;
  1739. }
  1740. .edit-dialog-tip {
  1741. margin-bottom: 15px;
  1742. color: #909399;
  1743. font-size: 12px;
  1744. background-color: #f4f4f5;
  1745. padding: 8px 12px;
  1746. border-radius: 4px;
  1747. border-left: 3px solid #409EFF;
  1748. }
  1749. .edit-dialog-tip .el-icon-info {
  1750. margin-right: 5px;
  1751. color: #409EFF;
  1752. }
  1753. /* 大输入框样式 */
  1754. .edit-textarea .el-textarea__inner {
  1755. resize: vertical !important;
  1756. min-height: 120px !important;
  1757. border: 1px solid #dcdfe6 !important;
  1758. border-radius: 4px !important;
  1759. padding: 8px 12px !important;
  1760. font-size: 14px !important;
  1761. line-height: 1.5 !important;
  1762. color: #606266 !important;
  1763. background-color: #fff !important;
  1764. transition: border-color 0.2s cubic-bezier(.645,.045,.355,1) !important;
  1765. box-sizing: border-box !important;
  1766. }
  1767. .edit-textarea .el-textarea__inner:focus {
  1768. outline: none !important;
  1769. border-color: #409EFF !important;
  1770. box-shadow: 0 0 0 2px rgba(64, 158, 255, 0.2) !important;
  1771. }
  1772. .edit-textarea .el-input__count {
  1773. color: #909399 !important;
  1774. background: #fff !important;
  1775. position: absolute !important;
  1776. font-size: 12px !important;
  1777. bottom: 5px !important;
  1778. right: 10px !important;
  1779. }
  1780. /* 修复弹窗中的表单项样式 */
  1781. .edit-dialog .el-form-item {
  1782. margin-bottom: 18px !important;
  1783. }
  1784. .edit-dialog .el-form-item__label {
  1785. color: #606266 !important;
  1786. font-weight: 500 !important;
  1787. line-height: 1.5 !important;
  1788. padding: 0 0 8px 0 !important;
  1789. box-sizing: border-box !important;
  1790. font-size: 14px !important;
  1791. }
  1792. /* 编辑弹窗按钮样式 */
  1793. .edit-dialog .dialog-footer {
  1794. text-align: right !important;
  1795. padding: 15px 20px 20px !important;
  1796. }
  1797. .edit-dialog .dialog-footer .el-button {
  1798. margin-left: 10px !important;
  1799. }
  1800. /* 确保弹窗内容不会溢出 */
  1801. .edit-dialog .el-dialog__wrapper {
  1802. overflow: hidden;
  1803. }
  1804. .edit-dialog .el-dialog {
  1805. margin-top: 5vh !important;
  1806. margin-bottom: 50px !important;
  1807. }
  1808. /* 表格输入框提示文字 */
  1809. .el-table .el-input__inner::placeholder {
  1810. font-size: 12px;
  1811. color: #c0c4cc;
  1812. }
  1813. /* 可点击发票号样式 */
  1814. .clickable-invoice {
  1815. cursor: pointer !important;
  1816. text-decoration: underline;
  1817. transition: all 0.3s;
  1818. }
  1819. .clickable-invoice:hover {
  1820. color: #409EFF !important;
  1821. text-shadow: 0 0 3px rgba(64, 158, 255, 0.3);
  1822. }
  1823. /* 表格样式区分 */
  1824. .valid-table .el-table__header {
  1825. background-color: #F0F9FF !important;
  1826. }
  1827. .valid-table .el-table th {
  1828. background-color: #F0F9FF !important;
  1829. color: #67C23A !important;
  1830. }
  1831. .invalid-table .el-table__header {
  1832. background-color: #FEF0F0 !important;
  1833. }
  1834. .invalid-table .el-table th {
  1835. background-color: #FEF0F0 !important;
  1836. color: #F56C6C !important;
  1837. }
  1838. .invalid-table .el-table .el-table__row:hover > td {
  1839. background-color: #FDF2F2 !important;
  1840. }
  1841. /* 物料不存在详情对话框样式 */
  1842. .invalid-materials-dialog .el-dialog__body {
  1843. padding: 20px;
  1844. }
  1845. .invalid-materials-content .warning-tip {
  1846. padding: 12px 16px;
  1847. background-color: #FEF0F0;
  1848. border: 1px solid #FBC4C4;
  1849. border-radius: 4px;
  1850. margin-bottom: 15px;
  1851. }
  1852. .invalid-materials-content .materials-summary {
  1853. text-align: center;
  1854. font-size: 14px;
  1855. }
  1856. .invalid-materials-dialog .el-table th {
  1857. background-color: #FEF0F0 !important;
  1858. }
  1859. .invalid-materials-dialog .el-table .el-table__row:hover > td {
  1860. background-color: #FDF2F2 !important;
  1861. }
  1862. /* Sheet错误表格样式 */
  1863. .warning-table .el-table__header {
  1864. background-color: #FDF6EC !important;
  1865. }
  1866. .warning-table .el-table th {
  1867. background-color: #FDF6EC !important;
  1868. color: #E6A23C !important;
  1869. }
  1870. .warning-table .el-table .el-table__row:hover > td {
  1871. background-color: #FEF5E7 !important;
  1872. }
  1873. </style>