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.

3274 lines
110 KiB

4 weeks ago
4 weeks ago
1 month ago
4 weeks ago
1 month ago
1 month ago
4 months ago
2 months ago
4 months ago
4 months ago
4 weeks ago
2 months ago
4 months ago
1 month ago
1 month ago
4 weeks ago
4 months ago
4 months ago
4 months ago
2 months ago
3 weeks ago
2 months ago
3 weeks ago
2 months ago
3 weeks ago
2 months ago
3 weeks ago
2 months ago
1 month ago
1 month ago
4 months ago
4 months ago
1 month ago
4 months ago
1 month ago
4 months ago
4 months ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
4 months ago
1 month ago
4 months ago
3 weeks ago
4 months ago
3 months ago
4 months ago
3 months ago
4 months ago
3 months ago
1 month ago
4 weeks ago
4 weeks ago
4 weeks ago
1 month ago
2 months ago
1 month ago
4 weeks ago
1 month ago
4 weeks ago
1 month ago
4 weeks ago
1 month ago
3 weeks ago
1 month ago
3 weeks ago
3 weeks ago
1 month ago
4 weeks ago
3 weeks ago
1 month ago
2 months ago
4 weeks ago
2 months ago
4 weeks ago
2 months ago
3 weeks ago
3 weeks ago
2 months ago
1 month ago
2 months ago
1 month ago
1 month ago
4 weeks ago
4 months ago
3 weeks ago
1 month ago
1 month ago
2 months ago
4 weeks ago
3 weeks ago
4 weeks ago
2 weeks ago
4 weeks ago
1 month ago
4 weeks ago
4 months ago
4 months ago
4 months ago
1 month ago
1 month ago
4 weeks ago
4 months ago
4 months ago
4 weeks ago
1 month ago
4 weeks ago
1 month ago
1 month ago
1 month ago
3 weeks ago
3 weeks ago
1 month ago
4 months ago
2 months ago
4 months ago
1 month ago
3 weeks ago
4 months ago
1 month ago
1 month ago
1 month ago
2 months ago
4 weeks ago
2 months ago
1 month ago
1 month ago
1 month ago
4 months ago
4 months ago
3 months ago
4 months ago
4 months ago
4 months ago
1 month ago
4 months ago
4 weeks ago
4 months ago
4 months ago
4 months ago
4 weeks ago
1 month ago
4 months ago
4 months ago
4 months ago
1 month ago
4 months ago
1 month ago
4 months ago
4 months ago
4 months ago
4 months ago
4 months ago
4 months ago
4 months ago
4 months ago
4 months ago
4 months ago
4 months ago
4 months ago
4 months ago
2 months ago
4 months ago
4 months ago
4 months ago
4 months ago
4 months ago
4 months ago
4 months ago
4 months ago
3 weeks ago
4 months ago
4 months ago
4 months ago
4 months ago
4 months ago
4 months ago
4 months ago
4 months ago
4 months ago
4 months ago
4 months ago
4 months ago
4 months ago
4 months ago
4 months ago
4 weeks ago
1 month ago
4 weeks ago
2 weeks ago
4 weeks ago
2 weeks ago
4 weeks ago
4 weeks ago
1 month ago
1 month ago
4 weeks ago
3 weeks ago
3 weeks ago
3 weeks ago
2 months ago
1 month ago
4 weeks ago
4 weeks ago
4 weeks ago
1 month ago
4 weeks ago
1 month ago
1 month ago
3 weeks ago
1 month ago
3 weeks ago
1 month ago
4 weeks ago
3 weeks ago
4 weeks ago
2 weeks ago
4 weeks ago
3 weeks ago
4 weeks ago
2 months ago
3 weeks ago
3 weeks ago
2 months ago
4 months ago
4 months ago
4 months ago
3 weeks ago
3 months ago
3 weeks ago
2 months ago
4 months ago
2 months ago
3 weeks ago
4 weeks ago
3 weeks ago
3 weeks ago
4 weeks ago
3 weeks ago
4 weeks ago
3 weeks ago
4 weeks ago
3 weeks ago
4 weeks ago
3 weeks ago
4 weeks ago
2 months ago
4 weeks ago
2 months ago
1 month ago
3 weeks ago
1 month ago
3 weeks ago
1 month ago
2 months ago
4 weeks ago
2 months ago
4 months ago
4 weeks ago
4 months ago
2 months ago
4 months ago
3 months ago
4 months ago
4 weeks ago
4 months ago
4 weeks ago
1 month ago
4 months ago
1 month ago
4 months ago
3 months ago
4 months ago
3 months ago
4 months ago
3 months ago
4 months ago
3 months ago
4 months ago
4 weeks ago
4 months ago
1 month ago
3 months ago
3 months ago
3 months ago
4 months ago
3 months ago
4 months ago
3 months ago
4 months ago
3 months ago
1 month ago
1 month ago
3 weeks ago
1 month ago
3 weeks ago
1 month ago
4 months ago
4 weeks ago
3 months ago
1 month ago
3 months ago
4 months ago
3 months ago
4 months ago
3 months ago
4 months ago
3 months ago
4 months ago
3 months ago
4 months ago
3 months ago
3 months ago
3 months ago
3 months ago
4 months ago
4 months ago
1 month ago
1 month ago
4 weeks ago
1 month ago
4 weeks ago
1 month ago
1 month ago
1 month ago
2 weeks ago
1 month ago
4 weeks ago
1 month ago
4 months ago
1 month ago
1 month ago
1 month ago
3 months ago
4 months ago
3 months ago
4 months ago
4 weeks ago
4 weeks ago
4 weeks ago
1 month ago
4 weeks ago
4 weeks ago
4 weeks ago
1 month ago
4 weeks ago
4 weeks ago
1 month ago
1 month ago
3 weeks ago
1 month ago
3 weeks ago
1 month ago
3 weeks ago
4 weeks ago
1 month ago
4 weeks ago
1 month ago
3 weeks ago
1 month ago
4 weeks ago
1 month ago
3 weeks ago
1 month ago
3 weeks ago
1 month ago
4 weeks ago
3 weeks ago
4 weeks ago
3 weeks ago
3 weeks ago
4 weeks ago
1 month ago
4 weeks ago
1 month ago
1 month ago
3 weeks ago
1 month ago
4 weeks ago
3 weeks ago
1 month ago
3 weeks ago
1 month ago
4 weeks ago
1 month ago
3 weeks ago
1 month ago
2 weeks ago
1 month ago
4 weeks ago
1 month ago
1 month ago
1 month ago
3 weeks ago
1 month ago
3 weeks ago
1 month ago
3 weeks ago
1 month ago
1 month ago
1 month ago
4 weeks ago
1 month ago
1 month ago
1 month ago
1 month ago
4 weeks ago
1 month ago
4 weeks ago
1 month ago
3 weeks ago
1 month ago
3 weeks ago
1 month ago
3 weeks ago
1 month ago
1 month ago
3 weeks ago
3 months ago
1 month ago
2 weeks ago
4 weeks ago
2 weeks ago
1 month ago
  1. <template>
  2. <div ref="pageRoot" class="mod-config">
  3. <com-po-order-customer-picker
  4. :site="searchData.site"
  5. v-model="searchData.customer"
  6. @change="onSessionCustomerChange" />
  7. <el-form :inline="true" label-position="top" :model="searchData">
  8. <el-form-item label="PO No">
  9. <el-input v-model="searchData.poNo" clearable style="width: 140px" @keyup.enter.native="handleSearch"></el-input>
  10. </el-form-item>
  11. <el-form-item label="订单类型">
  12. <el-select v-model="searchData.orderType" placeholder="请选择" style="width: 120px" clearable>
  13. <el-option
  14. v-for="item in poOrderTypeSearchOptions"
  15. :key="item.value"
  16. :label="item.label"
  17. :value="item.value" />
  18. </el-select>
  19. </el-form-item>
  20. <el-form-item>
  21. <span style="cursor: pointer" slot="label" @click="openSearchBaseList(2017)"><a href="javascript:void(0)">Part No</a></span>
  22. <el-input v-model="searchData.partNo" clearable style="width: 120px" @keyup.enter.native="handleSearch"></el-input>
  23. </el-form-item>
  24. <el-form-item>
  25. <span style="cursor: pointer" slot="label" @click="openSearchBaseList(520)"><a href="javascript:void(0)">供应商编码</a></span>
  26. <el-input v-model="searchData.supplierNo" clearable style="width: 120px" @keyup.enter.native="handleSearch"></el-input>
  27. </el-form-item>
  28. <el-form-item label="SKU">
  29. <el-input v-model="searchData.sku" clearable style="width: 120px" @keyup.enter.native="handleSearch"></el-input>
  30. </el-form-item>
  31. <el-form-item label="Status">
  32. <el-select v-model="searchData.status" placeholder="请选择" style="width:100px" clearable>
  33. <el-option label="全部" value=""></el-option>
  34. <el-option
  35. v-for="item in poOrderStatusOptions"
  36. :key="item.value"
  37. :label="item.label"
  38. :value="item.value" />
  39. </el-select>
  40. </el-form-item>
  41. </el-form>
  42. <el-form :inline="true" label-position="top" style="margin-top:10px ">
  43. <el-form-item>
  44. <el-button type="primary" @click="handleSearch()" v-if="!editMode" :disabled="!searchData.customer">查询</el-button>
  45. <el-button type="primary" style="margin-left: 2px" @click="exportExcel" :disabled="editMode || !searchData.customer">导出</el-button>
  46. <el-button type="warning" plain @click="advancedQueryVisible = true" v-if="!editMode" style="margin-left: 2px">高级查询</el-button>
  47. <el-button type="primary" style="margin-left: 2px" @click="toggleEditMode">
  48. {{ editMode ? '确定' : '编辑' }}
  49. </el-button>
  50. <el-button v-if="editMode" style="margin-left: 2px" @click="cancelEditMode">取消</el-button>
  51. <el-button type="primary" style="margin-left: 2px" @click="openAddDialog" v-if="!editMode">新增</el-button>
  52. <!-- <el-button type="primary" style="margin-left: 2px" @click="exportModal">导入</el-button>-->
  53. </el-form-item>
  54. </el-form>
  55. <el-table
  56. ref="poTable"
  57. :height="height"
  58. :data="masterRows"
  59. border
  60. highlight-current-row
  61. style="width: 100%;"
  62. @current-change="onTableCurrentChange">
  63. <el-table-column
  64. v-if="!editMode"
  65. fixed="left"
  66. label="操作"
  67. header-align="center"
  68. align="center"
  69. width="90">
  70. <template slot-scope="scope">
  71. <el-link
  72. v-if="canIssuePoOrder(scope.row.status)"
  73. type="primary"
  74. @click.stop="handleIssuePoOrder(scope.row)">下达</el-link>
  75. <el-link
  76. v-else-if="canShipPoOrder(scope.row.status)"
  77. type="primary"
  78. @click.stop="handleShipPoOrder(scope.row)">shipped</el-link>
  79. <el-link
  80. v-else-if="canClosePoOrder(scope.row.status)"
  81. type="primary"
  82. @click.stop="handleClosePoOrder(scope.row)">关闭</el-link>
  83. <el-link
  84. v-else-if="canOpenPoOrder(scope.row.status)"
  85. type="primary"
  86. @click.stop="handleOpenPoOrder(scope.row)">打开</el-link>
  87. </template>
  88. </el-table-column>
  89. <el-table-column
  90. v-for="(item, index) in visibleColumns"
  91. :key="item.serialNumber || index"
  92. :sortable="item.columnSortable"
  93. :prop="item.columnProp"
  94. :header-align="item.headerAlign"
  95. :show-overflow-tooltip="item.showOverflowTooltip && (!editMode || (!item.editAble && !isChooserEditColumn(item.columnProp)))"
  96. :align="item.align"
  97. :fixed="item.fixed === '' ? false : item.fixed"
  98. :min-width="item.columnWidth"
  99. :label="item.columnLabel">
  100. <template slot-scope="scope">
  101. <template v-if="editMode && item.columnProp==='supplierName' && canEditCell(scope.row, item)">
  102. <el-input
  103. v-model="scope.row.supplierName"
  104. size="mini"
  105. style="width: 100%; cursor: pointer"
  106. readonly
  107. placeholder="请选择供应商"
  108. @click.native="openSupplierSelect(scope.row)">
  109. <i slot="suffix" class="el-icon-search" style="cursor: pointer" @click.stop="openSupplierSelect(scope.row)"></i>
  110. </el-input>
  111. </template>
  112. <template v-else-if="editMode && item.columnProp==='partNo' && canEditCell(scope.row, item)">
  113. <el-input
  114. v-model="scope.row.partNo"
  115. size="mini"
  116. style="width: 100%; cursor: pointer"
  117. readonly
  118. placeholder="请选择物料"
  119. @click.native="openPartNoSelect(scope.row)">
  120. <i slot="suffix" class="el-icon-search" style="cursor: pointer" @click.stop="openPartNoSelect(scope.row)"></i>
  121. </el-input>
  122. </template>
  123. <template v-else-if="editMode && item.columnProp==='departure' && canEditCell(scope.row, item)">
  124. <el-input
  125. v-model="scope.row.departure"
  126. size="mini"
  127. style="width: 100%; cursor: pointer"
  128. readonly
  129. placeholder="请选择始发港"
  130. @click.native="openDepartureSelect(scope.row)">
  131. <i slot="suffix" class="el-icon-search" style="cursor: pointer" @click.stop="openDepartureSelect(scope.row)"></i>
  132. </el-input>
  133. </template>
  134. <template v-else-if="editMode && item.columnProp==='destination' && canEditCell(scope.row, item)">
  135. <el-input
  136. v-model="scope.row.destination"
  137. size="mini"
  138. style="width: 100%; cursor: pointer"
  139. readonly
  140. placeholder="请选择目的港"
  141. @click.native="openDestinationSelect(scope.row)">
  142. <i slot="suffix" class="el-icon-search" style="cursor: pointer" @click.stop="openDestinationSelect(scope.row)"></i>
  143. </el-input>
  144. </template>
  145. <template v-else-if="editMode && item.columnProp==='shipVia' && canEditCell(scope.row, item)">
  146. <el-input
  147. v-model="scope.row.shipVia"
  148. size="mini"
  149. style="width: 100%; cursor: pointer"
  150. readonly
  151. placeholder="请选择运输方式"
  152. @click.native="openShipViaSelect(scope.row)">
  153. <i slot="suffix" class="el-icon-search" style="cursor: pointer" @click.stop="openShipViaSelect(scope.row)"></i>
  154. </el-input>
  155. </template>
  156. <template v-else-if="editMode && canEditCell(scope.row, item)">
  157. <!-- 对于 confirmed wantReceiveDate 字段仅在新增行时可编辑 -->
  158. <template v-if="(item.columnProp === 'confirmed' || item.columnProp === 'wantReceiveDate') && !isNewRow(scope.row)">
  159. <span>{{ scope.row[item.columnProp] }}</span>
  160. </template>
  161. <!-- 对于 inspection realCrd 字段仅在修改时非新增行可编辑 -->
  162. <template v-else-if="(item.columnProp === 'inspection' || item.columnProp === 'realCrd') && isNewRow(scope.row)">
  163. <span>{{ scope.row[item.columnProp] }}</span>
  164. </template>
  165. <template v-else>
  166. <!-- 下拉框 -->
  167. <el-select
  168. v-if="item.editType === 'select' || item.editType === 'dict-select'"
  169. v-model="scope.row[item.columnProp]"
  170. size="mini"
  171. style="width: 100%"
  172. clearable
  173. @change="onCellChange(scope.row)">
  174. <el-option
  175. v-for="opt in getSelectOptionsForColumn(item)"
  176. :key="String(opt.value)"
  177. :label="opt.label"
  178. :value="opt.value">
  179. </el-option>
  180. </el-select>
  181. <!-- 数字输入框 -->
  182. <el-input
  183. v-else-if="item.editType === 'num'"
  184. v-model="scope.row[item.columnProp]"
  185. type="number"
  186. size="mini"
  187. @change="onCellChange(scope.row)">
  188. </el-input>
  189. <!-- 时间控件 -->
  190. <el-date-picker
  191. v-else-if="item.editType === 'date'"
  192. v-model="scope.row[item.columnProp]"
  193. type="date"
  194. size="mini"
  195. style="width: 100%"
  196. value-format="yyyy-MM-dd"
  197. placeholder="选择日期"
  198. @change="onCellChange(scope.row)">
  199. </el-date-picker>
  200. <el-date-picker
  201. v-else-if="item.editType === 'datetime'"
  202. v-model="scope.row[item.columnProp]"
  203. type="datetime"
  204. size="mini"
  205. style="width: 100%"
  206. value-format="yyyy-MM-dd HH:mm:ss"
  207. placeholder="选择日期时间"
  208. @change="onCellChange(scope.row)">
  209. </el-date-picker>
  210. <!-- 普通文本输入框 -->
  211. <el-input
  212. v-else
  213. v-model="scope.row[item.columnProp]"
  214. size="mini"
  215. @change="onCellChange(scope.row)">
  216. </el-input>
  217. </template>
  218. </template>
  219. <span v-else>{{ formatColumnCell(scope.row, item) }}</span>
  220. </template>
  221. </el-table-column>
  222. </el-table>
  223. <el-pagination
  224. ref="mainPager"
  225. @size-change="sizeChangeHandle"
  226. @current-change="currentChangeHandle"
  227. :current-page="pageIndex"
  228. :page-sizes="[20, 50, 100, 200, 500]"
  229. :page-size="pageSize"
  230. :total="totalPage"
  231. layout="total, sizes, prev, pager, next, jumper">
  232. </el-pagination>
  233. <!-- 导入弹窗 -->
  234. <el-dialog title="PO订单数据导入" :visible.sync="uploadDialogVisible" :height="height" width="800px">
  235. <!-- 选择文件 -->
  236. <div style="margin-bottom:15px;display:flex;align-items:center">
  237. <span style="margin-right:10px">请选择文件</span>
  238. <el-input v-model="uploadFileName" style="width:400px;margin-right:10px" readonly></el-input>
  239. <el-upload ref="upload" action="/api/pODetail/upload"
  240. :show-file-list="false" :on-change="handleFileChange"
  241. :auto-upload="false">
  242. <el-button type="primary">选择文件</el-button>
  243. </el-upload>
  244. <el-button type="success" style="margin-left:10px" @click="previewUpload">上传</el-button>
  245. <el-button type="primary" @click="downloadTemplate" style="margin-left:10px">
  246. <i class="el-icon-download"></i> 下载模板
  247. </el-button>
  248. </div>
  249. <!-- 跳过列提示 -->
  250. <el-alert
  251. v-if="uploadSkippedColumns.length"
  252. type="warning"
  253. :closable="false"
  254. show-icon
  255. style="margin-bottom:10px"
  256. :title="'已跳过列:' + uploadSkippedColumns.join('、')"
  257. />
  258. <div v-if="uploadColumnMappingEntries.length" style="margin-bottom:10px;font-size:12px;color:#606266">
  259. 列映射
  260. <span v-for="item in uploadColumnMappingEntries" :key="item.header" style="margin-right:12px">
  261. {{ item.header }} {{ item.fieldCode }}
  262. </span>
  263. </div>
  264. <!-- 预览表格 -->
  265. <el-table
  266. :data="uploadPreviewList"
  267. border
  268. height="250"
  269. style="width:100%;margin-top:10px"
  270. >
  271. <el-table-column
  272. v-for="col in uploadPreviewColumns"
  273. :key="col.prop"
  274. :prop="col.prop"
  275. :label="col.label"
  276. align="center"
  277. min-width="100"
  278. />
  279. </el-table>
  280. <!-- 按钮 -->
  281. <div style="margin-top:20px;text-align:center">
  282. <el-button type="primary" @click="confirmUpload">保存</el-button>
  283. <el-button @click="uploadDialogVisible=false" style="margin-right:30px">关闭</el-button>
  284. </div>
  285. </el-dialog>
  286. <ChooselistEam ref="eamList" @getBaseData="getEamData" />
  287. <po-order-advanced-query
  288. :visible.sync="advancedQueryVisible"
  289. :advanced-query-data="advancedQueryData"
  290. @query="handleSearch" />
  291. <!-- 新增 PO 订单 -->
  292. <el-dialog title="新增 PO 订单" :visible.sync="addDialogVisible" width="1000px" top="4vh"
  293. :close-on-click-modal="false" append-to-body>
  294. <div class="po-add-form-wrap">
  295. <el-form ref="addFormRef" :model="addForm" label-position="top" size="small">
  296. <el-row :gutter="15">
  297. <el-col v-for="field in addBaseFields" :key="field.fieldCode" :span="getAddFieldSpan(field)">
  298. <el-form-item :label="field.fieldLabel" :required="field.requiredFlag === 'Y'">
  299. <template v-if="isAddChooserField(field)">
  300. <el-input
  301. v-model="addForm[getAddFieldProp(field)]"
  302. readonly
  303. :placeholder="getAddChooserPlaceholder(field)"
  304. @click.native="openAddChooserByField(field)">
  305. <i slot="suffix" class="el-icon-search" style="cursor:pointer" @click.stop="openAddChooserByField(field)"></i>
  306. </el-input>
  307. </template>
  308. <template v-else-if="isAddSelectField(field)">
  309. <el-select
  310. v-model="addForm[getAddFieldProp(field)]"
  311. :filterable="isAddFilterableSelectField(field)"
  312. clearable
  313. style="width:100%"
  314. :disabled="isAddFieldDisabled(field)">
  315. <el-option
  316. v-for="opt in getAddFieldSelectOptions(field)"
  317. :key="opt.value"
  318. :label="opt.label"
  319. :value="opt.value" />
  320. </el-select>
  321. </template>
  322. <template v-else-if="isAddDateField(field)">
  323. <el-date-picker
  324. v-model="addForm[getAddFieldProp(field)]"
  325. type="date"
  326. value-format="yyyy-MM-dd"
  327. style="width:100%"
  328. :disabled="isAddFieldDisabled(field)" />
  329. </template>
  330. <template v-else-if="isAddTextareaField(field)">
  331. <el-input
  332. v-model="addForm[getAddFieldProp(field)]"
  333. type="textarea"
  334. :rows="2"
  335. :disabled="isAddFieldDisabled(field)" />
  336. </template>
  337. <template v-else>
  338. <el-input
  339. v-model="addForm[getAddFieldProp(field)]"
  340. :type="isAddNumberField(field) ? 'number' : 'text'"
  341. :disabled="isAddFieldDisabled(field)"
  342. @input="onAddFieldInput(field)" />
  343. </template>
  344. </el-form-item>
  345. </el-col>
  346. </el-row>
  347. <el-row v-if="addExtFields.length" :gutter="24">
  348. <el-col v-for="field in addExtFields" :key="field.fieldCode" :span="6">
  349. <el-form-item :label="field.fieldLabel" :required="field.requiredFlag === 'Y'">
  350. <com-po-order-dynamic-field-renderer
  351. :field="field"
  352. :site="searchData.site"
  353. :value="getAddExtValue(field.fieldCode)"
  354. @input="val => setAddExtValue(field.fieldCode, val)"
  355. />
  356. </el-form-item>
  357. </el-col>
  358. </el-row>
  359. </el-form>
  360. </div>
  361. <div slot="footer" class="dialog-footer">
  362. <el-button type="primary" :loading="addFormSaving" @click="saveAddPoOrder">保存</el-button>
  363. <el-button @click="addDialogVisible = false">取消</el-button>
  364. </div>
  365. </el-dialog>
  366. <el-dialog
  367. title="选择供应商可供物料"
  368. :visible.sync="supplierPartDialogVisible"
  369. width="820px"
  370. top="6vh"
  371. append-to-body
  372. :close-on-click-modal="false"
  373. @closed="resetSupplierPartDialog">
  374. <div style="margin-bottom: 10px; color: #606266;">
  375. <span>供应商{{ supplierPartDialogSupplierNo }}</span>
  376. </div>
  377. <el-table
  378. :data="supplierPartDialogRows"
  379. :height="430"
  380. border
  381. stripe
  382. v-loading="supplierPartDialogLoading"
  383. empty-text="该供应商未维护供应商可供物料"
  384. @row-dblclick="handleSupplierPartRowDblClick">
  385. <el-table-column prop="partNo" label="物料编码" min-width="160" header-align="center" align="center" />
  386. <el-table-column prop="partDesc" label="物料描述" min-width="220" header-align="center" align="left" show-overflow-tooltip />
  387. <el-table-column prop="item" label="Item" min-width="120" header-align="center" align="center" show-overflow-tooltip />
  388. <el-table-column prop="sku" label="SKU" min-width="120" header-align="center" align="center" show-overflow-tooltip />
  389. </el-table>
  390. <div slot="footer" class="dialog-footer">
  391. <el-button @click="supplierPartDialogVisible = false">关闭</el-button>
  392. </div>
  393. </el-dialog>
  394. </div>
  395. </template>
  396. <script>
  397. import {
  398. searchPoDetailPage,
  399. searchPoDetailAdvancedPage,
  400. batchUpdatePoDetail,
  401. closePoDetail,
  402. openPoDetail,
  403. issuePoDetail,
  404. shipPoDetail,
  405. createPoOrder,
  406. getPoCustomerOptions,
  407. getPoBuyerOptions,
  408. getPoFieldSchema,
  409. listPoSupplierPartOptions,
  410. listPoCurrentTierPrice
  411. } from '@/api/order/poOrder.js'
  412. import {
  413. createAdvancedQueryData,
  414. createAdvancedQueryDataFromSchema,
  415. buildPoOrderQueryParams
  416. } from './poOrderAdvancedQueryHelper.js'
  417. import {
  418. applyFieldSchemaToColumns,
  419. getAdvancedQueryFieldsFromSchema,
  420. getEditableExtFieldsFromSchema,
  421. buildImportPreviewColumns,
  422. normalizeSchemaRowValues,
  423. buildExtValuesFromRow
  424. } from './poOrderFieldSchemaHelper.js'
  425. import {
  426. PO_ORDER_STATUS_OPTIONS,
  427. canIssuePoOrder,
  428. canShipPoOrder,
  429. canClosePoOrder,
  430. canOpenPoOrder,
  431. canEditPoColumnByStatus,
  432. resolvePoOrderStatusByInspectQty,
  433. buildPoDetailActionParams
  434. } from './poOrderStatusOptions.js'
  435. import { PO_ORDER_TYPE_OPTIONS, PO_ORDER_TYPE_FILTER_OPTIONS, formatPoOrderTypeLabel } from './poOrderTypeOptions.js'
  436. import { getPartList, searchPartInfo } from '@/api/part/partInfo.js'
  437. import excel from '@/utils/excel-util.js'
  438. import { checkSrmSupplierList } from '@/api/srm/srmSupplier.js'
  439. import { selectDictDataList } from '@/api/dict'
  440. import {
  441. SUPPLIER_CHOOSELIST_TAG,
  442. parseSupplierChooselistRow,
  443. fetchSupplierDetail,
  444. resolveSupplierShortFieldsFromDetail
  445. } from '@/utils/supplierChooselistHelper.js'
  446. import { searchTransportOptions } from '@/api/port/portTransit.js'
  447. import ChooselistEam from '@/views/modules/common/Chooselist_eam.vue'
  448. import PoOrderAdvancedQuery from './com_poOrderAdvancedQuery.vue'
  449. import ComPoOrderCustomerPicker from './com_poOrder_CustomerPicker.vue'
  450. import ComPoOrderDynamicFieldRenderer from './com_poOrder_DynamicFieldRenderer.vue'
  451. const ADD_CHOOSER_FIELD_CODES = new Set(['supplier_name', 'part_no', 'departure', 'destination', 'ship_via'])
  452. const ADD_DISPLAY_ONLY_FIELD_CODES = new Set(['short_office', 'short_npc', 'item', 'category_name', 'sku', 'value', 'status', 'crd_ori'])
  453. const ADD_TEXTAREA_FIELD_CODES = new Set(['remark'])
  454. const ADD_FULL_ROW_FIELD_CODES = new Set(['remark'])
  455. const ADD_NUMBER_FIELD_CODES = new Set(['price', 'qty', 'ship_qty', 'sum_price'])
  456. const ADD_FILTERABLE_SELECT_FIELD_CODES = new Set(['customer', 'buyer'])
  457. const ADD_SELECT_OPTIONS_FIELD_CODE_MAP = {
  458. order_type: 'poOrderTypeOptions',
  459. customer: 'poCustomerOptions',
  460. buyer: 'poBuyerOptions',
  461. status: 'poOrderStatusOptions',
  462. doc_sent: 'yesNoOptions',
  463. telex_release: 'yesNoOptions',
  464. advance_paid: 'yesNoOptions'
  465. }
  466. export default {
  467. name: 'PoOrder',
  468. components: {
  469. ChooselistEam,
  470. PoOrderAdvancedQuery,
  471. ComPoOrderCustomerPicker,
  472. ComPoOrderDynamicFieldRenderer
  473. },
  474. data () {
  475. return {
  476. loading: false,
  477. masterRows: [],
  478. /**
  479. * 需要单独写编辑 UI columnProp 填在这里才会走模板里自定义分支不在此数组的仍用默认 select/num/text - rqrq
  480. * 示例['mPlanner', 'comments']
  481. */
  482. rowDeparture: {}, // 存储每行选中的始发港
  483. rowDestination: {}, // 存储每行选中的目的港
  484. rowShipVia: {}, // 存储每行选中的运输方式
  485. transportOptions: [], // 运输方式选项
  486. rowPartNo: {}, //存储每行选中的物料编号
  487. currentSelectRow: null, // 当前正在选择供应商的行
  488. currentPartNoRow: null, // 当前正在选择物料的行
  489. currentDepartureRow: null, // 当前正在选择始发港的行
  490. currentDestinationRow: null, // 当前正在选择目的港的行
  491. currentShipViaRow: null, // 当前正在选择运输方式的行
  492. rowSupplierNo: {}, //存储每行选中的供应商编号
  493. poPartNoOptions: [],
  494. supplierOptions: [],
  495. poDepartureOptions: [],
  496. poDestinationOptions: [],
  497. poCustomerOptions: [],
  498. poBuyerOptions: [],
  499. /** Chooselist 弹窗选择列(editAble 可为 false,如供应商/物料) */
  500. chooserEditColumnProps: ['supplierName', 'partNo', 'departure', 'destination', 'shipVia'],
  501. /** 联表展示、不写入 PO 的列 */
  502. displayOnlyColumnProps: ['shortOffice', 'shortNpc', 'item', 'categoryName', 'sku'],
  503. customEditColumnProps: [],
  504. // 上传相关
  505. uploadDialogVisible: false,
  506. uploadFileName: '',
  507. uploadFile: null,
  508. uploadPreviewList: [],
  509. uploadSkippedColumns: [],
  510. uploadColumnMapping: {},
  511. uploadPreviewColumns: [],
  512. addDialogVisible: false,
  513. addFormSaving: false,
  514. addFormSchemaFields: [],
  515. pickContext: '',
  516. eamTagNo: '',
  517. eamPickField: '',
  518. addForm: {},
  519. supplierPartDialogVisible: false,
  520. supplierPartDialogLoading: false,
  521. supplierPartDialogRows: [],
  522. supplierPartDialogContext: '',
  523. supplierPartDialogTargetRow: null,
  524. supplierPartDialogSupplierNo: '',
  525. supplierPartDialogSite: '',
  526. addPriceLookupTimer: null,
  527. addPriceLookupSeq: 0,
  528. selectedCustomerScope: null,
  529. currentRow: null,
  530. // 各列下拉:select 列通过 selectOptionsKey 指向此处;也可在列定义里写 selectOptions 数组 - rqrq
  531. columnSelectOptions: {
  532. poStatusOptions: PO_ORDER_STATUS_OPTIONS,
  533. poPartNoOptions: [],
  534. poDepartureOptions: [],
  535. poCustomerOptions: [],
  536. poBuyerOptions: [],
  537. transportOptions: [
  538. { label: '海运 SEA', value: 'SEA' },
  539. { label: '空运 AIR', value: 'AIR' },
  540. { label: '陆运 ROAD', value: 'ROAD' }
  541. ],
  542. yesNoOptions: [
  543. { label: 'Y', value: 'Y' },
  544. { label: 'N', value: 'N' }
  545. ]
  546. },
  547. dictSelectOptionsMap: {},
  548. searchData: {
  549. site: this.$store.state.user.site,
  550. customer: '',
  551. buyer: '',
  552. poNo: '',
  553. orderType: '',
  554. partNo: '',
  555. supplierNo: '',
  556. sku: '',
  557. status: '',
  558. supplierName: ''
  559. },
  560. poOrderTypeSearchOptions: [{ label: '全部', value: '' }, ...PO_ORDER_TYPE_OPTIONS],
  561. advancedQueryVisible: false,
  562. /** 字段 schema(list 场景) */
  563. fieldSchemaFields: [],
  564. baseColumnList: null,
  565. /** 高级查询条件对象(查询均读取;仅弹窗内「重置」可清空) */
  566. advancedQueryData: createAdvancedQueryData(),
  567. poOrderStatusOptions: PO_ORDER_STATUS_OPTIONS,
  568. poOrderTypeOptions: PO_ORDER_TYPE_FILTER_OPTIONS,
  569. height: 400,
  570. pageIndex: 1,
  571. pageSize: 20,
  572. totalPage: 0,
  573. dataList: [],
  574. editMode: false,
  575. columnList: [
  576. {
  577. userId: this.$store.state.user.name,
  578. functionId: 812003,
  579. serialNumber: '812003Table1Customer',
  580. tableId: '812003Table1',
  581. tableName: 'PO Order',
  582. columnProp: 'customer',
  583. headerAlign: 'center',
  584. align: 'center',
  585. columnLabel: 'Customer',
  586. columnHidden: false,
  587. columnImage: false,
  588. columnSortable: false,
  589. sortLv: 0,
  590. status: true,
  591. fixed: '',
  592. columnWidth: 180,
  593. showOverflowTooltip: true,
  594. editAble: true,
  595. editType: 'select',
  596. selectOptionsKey: 'poCustomerOptions',
  597. selectOptions: null
  598. },
  599. {
  600. userId: this.$store.state.user.name,
  601. functionId: 812003,
  602. serialNumber: '812003Table1Buyer',
  603. tableId: '812003Table1',
  604. tableName: 'PO Order',
  605. columnProp: 'buyer',
  606. headerAlign: 'center',
  607. align: 'center',
  608. columnLabel: 'Buyer',
  609. columnHidden: false,
  610. columnImage: false,
  611. columnSortable: false,
  612. sortLv: 0,
  613. status: true,
  614. fixed: '',
  615. columnWidth: 90,
  616. showOverflowTooltip: true,
  617. editAble: true,
  618. editType: 'select',
  619. selectOptionsKey: 'poBuyerOptions',
  620. selectOptions: null
  621. },
  622. {
  623. userId: this.$store.state.user.name,
  624. functionId: 812003,
  625. serialNumber: '812003Table1VendorName',
  626. tableId: '812003Table1',
  627. tableName: 'PO Order',
  628. columnProp: 'supplierName',
  629. headerAlign: 'center',
  630. align: 'center',
  631. columnLabel: 'Vendor Name',
  632. columnHidden: false,
  633. columnImage: false,
  634. columnSortable: false,
  635. sortLv: 0,
  636. status: true,
  637. fixed: '',
  638. columnWidth: 180,
  639. showOverflowTooltip: true,
  640. editAble: false,
  641. editType: 'select',
  642. selectOptionsKey: 'supplierOptions',
  643. selectOptions: null
  644. },
  645. {
  646. userId: this.$store.state.user.name,
  647. functionId: 812003,
  648. serialNumber: '812003Table1VShortOffice',
  649. tableId: '812003Table1',
  650. tableName: 'PO Order',
  651. columnProp: 'shortOffice',
  652. headerAlign: 'center',
  653. align: 'center',
  654. columnLabel: 'V_Short_Office',
  655. columnHidden: false,
  656. columnImage: false,
  657. columnSortable: false,
  658. sortLv: 0,
  659. status: true,
  660. fixed: '',
  661. columnWidth: 110,
  662. showOverflowTooltip: true,
  663. editAble: false,
  664. editType: 'text',
  665. selectOptionsKey: '',
  666. selectOptions: null
  667. },
  668. {
  669. userId: this.$store.state.user.name,
  670. functionId: 812003,
  671. serialNumber: '812003Table1VShortNpc',
  672. tableId: '812003Table1',
  673. tableName: 'PO Order',
  674. columnProp: 'shortNpc',
  675. headerAlign: 'center',
  676. align: 'center',
  677. columnLabel: 'V_Short_NPC',
  678. columnHidden: false,
  679. columnImage: false,
  680. columnSortable: false,
  681. sortLv: 0,
  682. status: true,
  683. fixed: '',
  684. columnWidth: 100,
  685. showOverflowTooltip: true,
  686. editAble: false,
  687. editType: 'text',
  688. selectOptionsKey: '',
  689. selectOptions: null
  690. },
  691. {
  692. userId: this.$store.state.user.name,
  693. functionId: 812003,
  694. serialNumber: '812003Table1PoNo',
  695. tableId: '812003Table1',
  696. tableName: 'PO Order',
  697. columnProp: 'poNo',
  698. headerAlign: 'center',
  699. align: 'center',
  700. columnLabel: 'PO_No',
  701. columnHidden: false,
  702. columnImage: false,
  703. columnSortable: false,
  704. sortLv: 0,
  705. status: true,
  706. fixed: '',
  707. columnWidth: 120,
  708. showOverflowTooltip: true,
  709. editAble: true,
  710. editType: 'text',
  711. selectOptionsKey: '',
  712. selectOptions: null
  713. },
  714. {
  715. userId: this.$store.state.user.name,
  716. functionId: 812003,
  717. serialNumber: '812003Table1OrderType',
  718. tableId: '812003Table1',
  719. tableName: 'PO Order',
  720. columnProp: 'orderType',
  721. headerAlign: 'center',
  722. align: 'center',
  723. columnLabel: '订单类型',
  724. columnHidden: false,
  725. columnImage: false,
  726. columnSortable: false,
  727. sortLv: 0,
  728. status: true,
  729. fixed: '',
  730. columnWidth: 100,
  731. showOverflowTooltip: true,
  732. editAble: false,
  733. editType: 'text',
  734. selectOptionsKey: '',
  735. selectOptions: null
  736. },
  737. {
  738. userId: this.$store.state.user.name,
  739. functionId: 812003,
  740. serialNumber: '812003Table1PartNo',
  741. tableId: '812003Table1',
  742. tableName: 'PO Order',
  743. columnProp: 'partNo',
  744. headerAlign: 'center',
  745. align: 'center',
  746. columnLabel: 'Part No',
  747. columnHidden: false,
  748. columnImage: false,
  749. columnSortable: false,
  750. sortLv: 0,
  751. status: true,
  752. fixed: '',
  753. columnWidth: 120,
  754. showOverflowTooltip: true,
  755. editAble: false,
  756. editType: 'select',
  757. selectOptionsKey: 'poPartNoOptions',
  758. selectOptions: null
  759. },
  760. {
  761. userId: this.$store.state.user.name,
  762. functionId: 812003,
  763. serialNumber: '812003Table1Item',
  764. tableId: '812003Table1',
  765. tableName: 'PO Order',
  766. columnProp: 'item',
  767. headerAlign: 'center',
  768. align: 'center',
  769. columnLabel: 'Item',
  770. columnHidden: false,
  771. columnImage: false,
  772. columnSortable: false,
  773. sortLv: 0,
  774. status: true,
  775. fixed: '',
  776. columnWidth: 120,
  777. showOverflowTooltip: true,
  778. editAble: false,
  779. editType: 'text',
  780. selectOptionsKey: '',
  781. selectOptions: null
  782. },
  783. {
  784. userId: this.$store.state.user.name,
  785. functionId: 812003,
  786. serialNumber: '812003Table1Category',
  787. tableId: '812003Table1',
  788. tableName: 'PO Order',
  789. columnProp: 'categoryName',
  790. headerAlign: 'center',
  791. align: 'center',
  792. columnLabel: 'Category',
  793. columnHidden: false,
  794. columnImage: false,
  795. columnSortable: false,
  796. sortLv: 0,
  797. status: true,
  798. fixed: '',
  799. columnWidth: 90,
  800. showOverflowTooltip: true,
  801. editAble: false,
  802. editType: 'text',
  803. selectOptionsKey: '',
  804. selectOptions: null
  805. },
  806. {
  807. userId: this.$store.state.user.name,
  808. functionId: 812003,
  809. serialNumber: '812003Table1Sku',
  810. tableId: '812003Table1',
  811. tableName: 'PO Order',
  812. columnProp: 'sku',
  813. headerAlign: 'center',
  814. align: 'center',
  815. columnLabel: 'SKU',
  816. columnHidden: false,
  817. columnImage: false,
  818. columnSortable: false,
  819. sortLv: 0,
  820. status: true,
  821. fixed: '',
  822. columnWidth: 100,
  823. showOverflowTooltip: true,
  824. editAble: false,
  825. editType: 'text',
  826. selectOptionsKey: '',
  827. selectOptions: null
  828. },
  829. {
  830. userId: this.$store.state.user.name,
  831. functionId: 812003,
  832. serialNumber: '812003Table1UnitPrice',
  833. tableId: '812003Table1',
  834. tableName: 'PO Order',
  835. columnProp: 'price',
  836. headerAlign: 'center',
  837. align: 'center',
  838. columnLabel: 'Unit Price',
  839. columnHidden: false,
  840. columnImage: false,
  841. columnSortable: false,
  842. sortLv: 0,
  843. status: true,
  844. fixed: '',
  845. columnWidth: 90,
  846. showOverflowTooltip: true,
  847. editAble: true,
  848. editType: 'num',
  849. selectOptionsKey: '',
  850. selectOptions: null
  851. },
  852. {
  853. userId: this.$store.state.user.name,
  854. functionId: 812003,
  855. serialNumber: '812003Table1PQty',
  856. tableId: '812003Table1',
  857. tableName: 'PO Order',
  858. columnProp: 'qty',
  859. headerAlign: 'center',
  860. align: 'center',
  861. columnLabel: 'PO Qty',
  862. columnHidden: false,
  863. columnImage: false,
  864. columnSortable: false,
  865. sortLv: 0,
  866. status: true,
  867. fixed: '',
  868. columnWidth: 80,
  869. showOverflowTooltip: true,
  870. editAble: true,
  871. editType: 'num',
  872. selectOptionsKey: '',
  873. selectOptions: null
  874. },
  875. {
  876. userId: this.$store.state.user.name,
  877. functionId: 812003,
  878. serialNumber: '812003Table1PValue',
  879. tableId: '812003Table1',
  880. tableName: 'PO Order',
  881. columnProp: 'value',
  882. headerAlign: 'center',
  883. align: 'center',
  884. columnLabel: 'PO Value',
  885. columnHidden: false,
  886. columnImage: false,
  887. columnSortable: false,
  888. sortLv: 0,
  889. status: true,
  890. fixed: '',
  891. columnWidth: 90,
  892. showOverflowTooltip: true,
  893. editAble: false,
  894. editType: 'num',
  895. selectOptionsKey: '',
  896. selectOptions: null
  897. },
  898. {
  899. userId: this.$store.state.user.name,
  900. functionId: 812003,
  901. serialNumber: '812003Table1AQty',
  902. tableId: '812003Table1',
  903. tableName: 'PO Order',
  904. columnProp: 'shipQty',
  905. headerAlign: 'center',
  906. align: 'center',
  907. columnLabel: 'A-Qty',
  908. columnHidden: false,
  909. columnImage: false,
  910. columnSortable: false,
  911. sortLv: 0,
  912. status: true,
  913. fixed: '',
  914. columnWidth: 80,
  915. showOverflowTooltip: true,
  916. editAble: true,
  917. editType: 'text',
  918. selectOptionsKey: '',
  919. selectOptions: null
  920. },
  921. {
  922. userId: this.$store.state.user.name,
  923. functionId: 812003,
  924. serialNumber: '812003Table1AValue',
  925. tableId: '812003Table1',
  926. tableName: 'PO Order',
  927. columnProp: 'sumPrice',
  928. headerAlign: 'center',
  929. align: 'center',
  930. columnLabel: 'A-Value',
  931. columnHidden: false,
  932. columnImage: false,
  933. columnSortable: false,
  934. sortLv: 0,
  935. status: true,
  936. fixed: '',
  937. columnWidth: 90,
  938. showOverflowTooltip: true,
  939. editAble: true,
  940. editType: 'text',
  941. selectOptionsKey: '',
  942. selectOptions: null
  943. },
  944. {
  945. userId: this.$store.state.user.name,
  946. functionId: 812003,
  947. serialNumber: '812003Table1PDeparture',
  948. tableId: '812003Table1',
  949. tableName: 'PO Order',
  950. columnProp: 'departure',
  951. headerAlign: 'center',
  952. align: 'center',
  953. columnLabel: 'Departure Port',
  954. columnHidden: false,
  955. columnImage: false,
  956. columnSortable: false,
  957. sortLv: 0,
  958. status: true,
  959. fixed: '',
  960. columnWidth: 100,
  961. showOverflowTooltip: true,
  962. editAble: true,
  963. editType: 'select',
  964. selectOptionsKey: 'departureOptions',
  965. selectOptions: null
  966. },
  967. {
  968. userId: this.$store.state.user.name,
  969. functionId: 812003,
  970. serialNumber: '812003Table1PDestination',
  971. tableId: '812003Table1',
  972. tableName: 'PO Order',
  973. columnProp: 'destination',
  974. headerAlign: 'center',
  975. align: 'center',
  976. columnLabel: 'Destination Port',
  977. columnHidden: false,
  978. columnImage: false,
  979. columnSortable: false,
  980. sortLv: 0,
  981. status: true,
  982. fixed: '',
  983. columnWidth: 110,
  984. showOverflowTooltip: true,
  985. editAble: true,
  986. editType: 'select',
  987. selectOptionsKey: 'destinationOptions',
  988. selectOptions: null
  989. },
  990. {
  991. userId: this.$store.state.user.name,
  992. functionId: 812003,
  993. serialNumber: '812003Table1SMethod',
  994. tableId: '812003Table1',
  995. tableName: 'PO Order',
  996. columnProp: 'shipVia',
  997. headerAlign: 'center',
  998. align: 'center',
  999. columnLabel: 'Method',
  1000. columnHidden: false,
  1001. columnImage: false,
  1002. columnSortable: false,
  1003. sortLv: 0,
  1004. status: true,
  1005. fixed: '',
  1006. columnWidth: 90,
  1007. showOverflowTooltip: true,
  1008. editAble: true,
  1009. editType: 'select',
  1010. selectOptionsKey: 'transportOptions',
  1011. selectOptions: null
  1012. },
  1013. {
  1014. userId: this.$store.state.user.name,
  1015. functionId: 812003,
  1016. serialNumber: '812003Table1DIssue',
  1017. tableId: '812003Table1',
  1018. tableName: 'PO Order',
  1019. columnProp: 'orderDate',
  1020. headerAlign: 'center',
  1021. align: 'center',
  1022. columnLabel: 'Buyer Release Date',
  1023. columnHidden: false,
  1024. columnImage: false,
  1025. columnSortable: false,
  1026. sortLv: 0,
  1027. status: true,
  1028. fixed: '',
  1029. columnWidth: 130,
  1030. showOverflowTooltip: true,
  1031. editAble: false,
  1032. editType: 'date',
  1033. selectOptionsKey: '',
  1034. selectOptions: null
  1035. },
  1036. {
  1037. userId: this.$store.state.user.name,
  1038. functionId: 812003,
  1039. serialNumber: '812003Table1DEnquiry',
  1040. tableId: '812003Table1',
  1041. tableName: 'PO Order',
  1042. columnProp: 'enquiry',
  1043. headerAlign: 'center',
  1044. align: 'center',
  1045. columnLabel: 'Planner Release Date',
  1046. columnHidden: false,
  1047. columnImage: false,
  1048. columnSortable: false,
  1049. sortLv: 0,
  1050. status: true,
  1051. fixed: '',
  1052. columnWidth: 140,
  1053. showOverflowTooltip: true,
  1054. editAble: false,
  1055. editType: 'date',
  1056. selectOptionsKey: '',
  1057. selectOptions: null
  1058. },
  1059. {
  1060. userId: this.$store.state.user.name,
  1061. functionId: 812003,
  1062. serialNumber: '812003Table1Status',
  1063. tableId: '812003Table1',
  1064. tableName: 'PO Order',
  1065. columnProp: 'status',
  1066. headerAlign: 'center',
  1067. align: 'center',
  1068. columnLabel: 'Status',
  1069. columnHidden: false,
  1070. columnImage: false,
  1071. columnSortable: false,
  1072. sortLv: 0,
  1073. status: true,
  1074. fixed: '',
  1075. columnWidth: 80,
  1076. showOverflowTooltip: true,
  1077. editAble: false,
  1078. editType: 'select',
  1079. selectOptionsKey: 'poStatusOptions',
  1080. selectOptions: null
  1081. },
  1082. {
  1083. userId: this.$store.state.user.name,
  1084. functionId: 812003,
  1085. serialNumber: '812003Table1DConfirmed',
  1086. tableId: '812003Table1',
  1087. tableName: 'PO Order',
  1088. columnProp: 'confirmed',
  1089. headerAlign: 'center',
  1090. align: 'center',
  1091. columnLabel: 'PI Confirmed Date',
  1092. columnHidden: false,
  1093. columnImage: false,
  1094. columnSortable: false,
  1095. sortLv: 0,
  1096. status: true,
  1097. fixed: '',
  1098. columnWidth: 120,
  1099. showOverflowTooltip: true,
  1100. editAble: true,
  1101. editType: 'date',
  1102. selectOptionsKey: '',
  1103. selectOptions: null
  1104. },
  1105. {
  1106. userId: this.$store.state.user.name,
  1107. functionId: 812003,
  1108. serialNumber: '812003Table1DNeed',
  1109. tableId: '812003Table1',
  1110. tableName: 'PO Order',
  1111. columnProp: 'wantReceiveDate',
  1112. headerAlign: 'center',
  1113. align: 'center',
  1114. columnLabel: 'Original Arrival Date',
  1115. columnHidden: false,
  1116. columnImage: false,
  1117. columnSortable: false,
  1118. sortLv: 0,
  1119. status: true,
  1120. fixed: '',
  1121. columnWidth: 130,
  1122. showOverflowTooltip: true,
  1123. editAble: true,
  1124. editType: 'date',
  1125. selectOptionsKey: '',
  1126. selectOptions: null
  1127. },
  1128. {
  1129. userId: this.$store.state.user.name,
  1130. functionId: 812003,
  1131. serialNumber: '812003Table1DNarrival',
  1132. tableId: '812003Table1',
  1133. tableName: 'PO Order',
  1134. columnProp: 'narrival',
  1135. headerAlign: 'center',
  1136. align: 'center',
  1137. columnLabel: 'Final Confirmed Arrival Date',
  1138. columnHidden: false,
  1139. columnImage: false,
  1140. columnSortable: false,
  1141. sortLv: 0,
  1142. status: true,
  1143. fixed: '',
  1144. columnWidth: 110,
  1145. showOverflowTooltip: true,
  1146. editAble: true,
  1147. editType: 'date',
  1148. selectOptionsKey: '',
  1149. selectOptions: null
  1150. },
  1151. {
  1152. userId: this.$store.state.user.name,
  1153. functionId: 812003,
  1154. serialNumber: '812003Table1DCrd',
  1155. tableId: '812003Table1',
  1156. tableName: 'PO Order',
  1157. columnProp: 'crd',
  1158. headerAlign: 'center',
  1159. align: 'center',
  1160. columnLabel: 'PI Confirmed CRD',
  1161. columnHidden: false,
  1162. columnImage: false,
  1163. columnSortable: false,
  1164. sortLv: 0,
  1165. status: true,
  1166. fixed: '',
  1167. columnWidth: 120,
  1168. showOverflowTooltip: true,
  1169. editAble: true,
  1170. editType: 'date',
  1171. selectOptionsKey: '',
  1172. selectOptions: null
  1173. },
  1174. {
  1175. userId: this.$store.state.user.name,
  1176. functionId: 812003,
  1177. serialNumber: '812003Table1DCrdOri',
  1178. tableId: '812003Table1',
  1179. tableName: 'PO Order',
  1180. columnProp: 'crdOri',
  1181. headerAlign: 'center',
  1182. align: 'center',
  1183. columnLabel: 'Original CRD',
  1184. columnHidden: false,
  1185. columnImage: false,
  1186. columnSortable: false,
  1187. sortLv: 0,
  1188. status: true,
  1189. fixed: '',
  1190. columnWidth: 120,
  1191. showOverflowTooltip: true,
  1192. editAble: false,
  1193. editType: 'date',
  1194. selectOptionsKey: '',
  1195. selectOptions: null
  1196. },
  1197. {
  1198. userId: this.$store.state.user.name,
  1199. functionId: 812003,
  1200. serialNumber: '812003Table1DInspection',
  1201. tableId: '812003Table1',
  1202. tableName: 'PO Order',
  1203. columnProp: 'inspection',
  1204. headerAlign: 'center',
  1205. align: 'center',
  1206. columnLabel: 'Inspection Date',
  1207. columnHidden: false,
  1208. columnImage: false,
  1209. columnSortable: false,
  1210. sortLv: 0,
  1211. status: true,
  1212. fixed: '',
  1213. columnWidth: 100,
  1214. showOverflowTooltip: true,
  1215. editAble: true,
  1216. editType: 'date',
  1217. selectOptionsKey: '',
  1218. selectOptions: null
  1219. },
  1220. {
  1221. userId: this.$store.state.user.name,
  1222. functionId: 812003,
  1223. serialNumber: '812003Table1ACrd',
  1224. tableId: '812003Table1',
  1225. tableName: 'PO Order',
  1226. columnProp: 'realCrd',
  1227. headerAlign: 'center',
  1228. align: 'center',
  1229. columnLabel: 'Actual Completion Date',
  1230. columnHidden: false,
  1231. columnImage: false,
  1232. columnSortable: false,
  1233. sortLv: 0,
  1234. status: true,
  1235. fixed: '',
  1236. columnWidth: 150,
  1237. showOverflowTooltip: true,
  1238. editAble: true,
  1239. editType: 'date',
  1240. selectOptionsKey: '',
  1241. selectOptions: null
  1242. },
  1243. {
  1244. userId: this.$store.state.user.name,
  1245. functionId: 812003,
  1246. serialNumber: '812003Table1Eta',
  1247. tableId: '812003Table1',
  1248. tableName: 'PO Order',
  1249. columnProp: 'eta',
  1250. headerAlign: 'center',
  1251. align: 'center',
  1252. columnLabel: 'ETA',
  1253. columnHidden: false,
  1254. columnImage: false,
  1255. columnSortable: false,
  1256. sortLv: 0,
  1257. status: true,
  1258. fixed: '',
  1259. columnWidth: 100,
  1260. showOverflowTooltip: true,
  1261. editAble: false,
  1262. editType: 'date',
  1263. selectOptionsKey: '',
  1264. selectOptions: null
  1265. },
  1266. {
  1267. userId: this.$store.state.user.name,
  1268. functionId: 812003,
  1269. serialNumber: '812003Table1Flexid',
  1270. tableId: '812003Table1',
  1271. tableName: 'PO Order',
  1272. columnProp: 'flexid',
  1273. headerAlign: 'center',
  1274. align: 'center',
  1275. columnLabel: 'Flexport Id',
  1276. columnHidden: false,
  1277. columnImage: false,
  1278. columnSortable: false,
  1279. sortLv: 0,
  1280. status: true,
  1281. fixed: '',
  1282. columnWidth: 90,
  1283. showOverflowTooltip: true,
  1284. editAble: true,
  1285. editType: 'text',
  1286. selectOptionsKey: '',
  1287. selectOptions: null
  1288. },
  1289. {
  1290. userId: this.$store.state.user.name,
  1291. functionId: 812003,
  1292. serialNumber: '812003Table1AObd',
  1293. tableId: '812003Table1',
  1294. tableName: 'PO Order',
  1295. columnProp: 'obd',
  1296. headerAlign: 'center',
  1297. align: 'center',
  1298. columnLabel: 'On Board Date',
  1299. columnHidden: false,
  1300. columnImage: false,
  1301. columnSortable: false,
  1302. sortLv: 0,
  1303. status: true,
  1304. fixed: '',
  1305. columnWidth: 100,
  1306. showOverflowTooltip: true,
  1307. editAble: true,
  1308. editType: 'date',
  1309. selectOptionsKey: '',
  1310. selectOptions: null
  1311. },
  1312. {
  1313. userId: this.$store.state.user.name,
  1314. functionId: 812003,
  1315. serialNumber: '812003Table1DocSent',
  1316. tableId: '812003Table1',
  1317. tableName: 'PO Order',
  1318. columnProp: 'docSent',
  1319. headerAlign: 'center',
  1320. align: 'center',
  1321. columnLabel: 'Doc Sent',
  1322. columnHidden: false,
  1323. columnImage: false,
  1324. columnSortable: false,
  1325. sortLv: 0,
  1326. status: true,
  1327. fixed: '',
  1328. columnWidth: 90,
  1329. showOverflowTooltip: true,
  1330. editAble: true,
  1331. editType: 'select',
  1332. selectOptionsKey: 'yesNoOptions',
  1333. selectOptions: null
  1334. },
  1335. {
  1336. userId: this.$store.state.user.name,
  1337. functionId: 812003,
  1338. serialNumber: '812003Table1TelexRelease',
  1339. tableId: '812003Table1',
  1340. tableName: 'PO Order',
  1341. columnProp: 'telexRelease',
  1342. headerAlign: 'center',
  1343. align: 'center',
  1344. columnLabel: 'Telex Release',
  1345. columnHidden: false,
  1346. columnImage: false,
  1347. columnSortable: false,
  1348. sortLv: 0,
  1349. status: true,
  1350. fixed: '',
  1351. columnWidth: 100,
  1352. showOverflowTooltip: true,
  1353. editAble: true,
  1354. editType: 'select',
  1355. selectOptionsKey: 'yesNoOptions',
  1356. selectOptions: null
  1357. },
  1358. {
  1359. userId: this.$store.state.user.name,
  1360. functionId: 812003,
  1361. serialNumber: '812003Table1AdvancePayment',
  1362. tableId: '812003Table1',
  1363. tableName: 'PO Order',
  1364. columnProp: 'advancePayment',
  1365. headerAlign: 'center',
  1366. align: 'center',
  1367. columnLabel: 'Advance Payment',
  1368. columnHidden: false,
  1369. columnImage: false,
  1370. columnSortable: false,
  1371. sortLv: 0,
  1372. status: true,
  1373. fixed: '',
  1374. columnWidth: 120,
  1375. showOverflowTooltip: true,
  1376. editAble: true,
  1377. editType: 'text',
  1378. selectOptionsKey: '',
  1379. selectOptions: null
  1380. },
  1381. {
  1382. userId: this.$store.state.user.name,
  1383. functionId: 812003,
  1384. serialNumber: '812003Table1AdvancePaid',
  1385. tableId: '812003Table1',
  1386. tableName: 'PO Order',
  1387. columnProp: 'advancePaid',
  1388. headerAlign: 'center',
  1389. align: 'center',
  1390. columnLabel: 'Advanc Paid',
  1391. columnHidden: false,
  1392. columnImage: false,
  1393. columnSortable: false,
  1394. sortLv: 0,
  1395. status: true,
  1396. fixed: '',
  1397. columnWidth: 100,
  1398. showOverflowTooltip: true,
  1399. editAble: true,
  1400. editType: 'select',
  1401. selectOptionsKey: 'yesNoOptions',
  1402. selectOptions: null
  1403. },
  1404. {
  1405. userId: this.$store.state.user.name,
  1406. functionId: 812003,
  1407. serialNumber: '812003Table1DCreate',
  1408. tableId: '812003Table1',
  1409. tableName: 'PO Order',
  1410. columnProp: 'createTime',
  1411. headerAlign: 'center',
  1412. align: 'center',
  1413. columnLabel: 'Create Date',
  1414. columnHidden: false,
  1415. columnImage: false,
  1416. columnSortable: false,
  1417. sortLv: 0,
  1418. status: true,
  1419. fixed: '',
  1420. columnWidth: 100,
  1421. showOverflowTooltip: true,
  1422. editAble: false,
  1423. editType: 'date',
  1424. selectOptionsKey: '',
  1425. selectOptions: null
  1426. },
  1427. {
  1428. userId: this.$store.state.user.name,
  1429. functionId: 812003,
  1430. serialNumber: '812003Table1MPlanner',
  1431. tableId: '812003Table1',
  1432. tableName: 'PO Order',
  1433. columnProp: 'planner',
  1434. headerAlign: 'center',
  1435. align: 'center',
  1436. columnLabel: 'M-Planner',
  1437. columnHidden: false,
  1438. columnImage: false,
  1439. columnSortable: false,
  1440. sortLv: 0,
  1441. status: true,
  1442. fixed: '',
  1443. columnWidth: 100,
  1444. showOverflowTooltip: true,
  1445. editAble: true,
  1446. editType: 'text',
  1447. selectOptionsKey: '',
  1448. selectOptions: null
  1449. },
  1450. {
  1451. userId: this.$store.state.user.name,
  1452. functionId: 812003,
  1453. serialNumber: '812003Table1DEdit',
  1454. tableId: '812003Table1',
  1455. tableName: 'PO Order',
  1456. columnProp: 'edit',
  1457. headerAlign: 'center',
  1458. align: 'center',
  1459. columnLabel: 'Edit Date',
  1460. columnHidden: false,
  1461. columnImage: false,
  1462. columnSortable: false,
  1463. sortLv: 0,
  1464. status: true,
  1465. fixed: '',
  1466. columnWidth: 100,
  1467. showOverflowTooltip: true,
  1468. editAble: false,
  1469. editType: 'date',
  1470. selectOptionsKey: '',
  1471. selectOptions: null
  1472. },
  1473. {
  1474. userId: this.$store.state.user.name,
  1475. functionId: 812003,
  1476. serialNumber: '812003Table1EPlanner',
  1477. tableId: '812003Table1',
  1478. tableName: 'PO Order',
  1479. columnProp: 'endPlanner',
  1480. headerAlign: 'center',
  1481. align: 'center',
  1482. columnLabel: 'Last Editor',
  1483. columnHidden: false,
  1484. columnImage: false,
  1485. columnSortable: false,
  1486. sortLv: 0,
  1487. status: true,
  1488. fixed: '',
  1489. columnWidth: 100,
  1490. showOverflowTooltip: true,
  1491. editAble: false,
  1492. editType: 'text',
  1493. selectOptionsKey: '',
  1494. selectOptions: null
  1495. },
  1496. {
  1497. userId: this.$store.state.user.name,
  1498. functionId: 812003,
  1499. serialNumber: '812003Table1RemarkDelay',
  1500. tableId: '812003Table1',
  1501. tableName: 'PO Order',
  1502. columnProp: 'remarkDelay',
  1503. headerAlign: 'center',
  1504. align: 'center',
  1505. columnLabel: 'Remark Delay',
  1506. columnHidden: false,
  1507. columnImage: false,
  1508. columnSortable: false,
  1509. sortLv: 0,
  1510. status: true,
  1511. fixed: '',
  1512. columnWidth: 110,
  1513. showOverflowTooltip: true,
  1514. editAble: true,
  1515. editType: 'text',
  1516. selectOptionsKey: '',
  1517. selectOptions: null
  1518. },
  1519. {
  1520. userId: this.$store.state.user.name,
  1521. functionId: 812003,
  1522. serialNumber: '812003Table1Comments',
  1523. tableId: '812003Table1',
  1524. tableName: 'PO Order',
  1525. columnProp: 'remark',
  1526. headerAlign: 'center',
  1527. align: 'center',
  1528. columnLabel: 'Comments',
  1529. columnHidden: false,
  1530. columnImage: false,
  1531. columnSortable: false,
  1532. sortLv: 0,
  1533. status: true,
  1534. fixed: '',
  1535. columnWidth: 180,
  1536. showOverflowTooltip: true,
  1537. editAble: true,
  1538. editType: 'text',
  1539. selectOptionsKey: '',
  1540. selectOptions: null
  1541. },
  1542. {
  1543. userId: this.$store.state.user.name,
  1544. functionId: 812003,
  1545. serialNumber: '812003Table1InspectionCompletedQty',
  1546. tableId: '812003Table1',
  1547. tableName: 'PO Order',
  1548. columnProp: 'inspectionCompletedQty',
  1549. headerAlign: 'center',
  1550. align: 'center',
  1551. columnLabel: 'Inspection Completed Qty',
  1552. columnHidden: false,
  1553. columnImage: false,
  1554. columnSortable: false,
  1555. sortLv: 0,
  1556. status: true,
  1557. fixed: '',
  1558. columnWidth: 140,
  1559. showOverflowTooltip: true,
  1560. editAble: false,
  1561. editType: 'text',
  1562. selectOptionsKey: '',
  1563. selectOptions: null
  1564. }
  1565. ]
  1566. }
  1567. },
  1568. computed: {
  1569. visibleColumns () {
  1570. const source = this.baseColumnList || this.columnList
  1571. const applied = applyFieldSchemaToColumns(source, this.fieldSchemaFields)
  1572. const cols = applied.filter(c => !c.columnHidden)
  1573. const leadProps = ['poNo', 'orderType']
  1574. const leading = leadProps.map(p => cols.find(c => c.columnProp === p)).filter(Boolean)
  1575. const rest = cols.filter(c => !leadProps.includes(c.columnProp))
  1576. return [...leading, ...rest]
  1577. },
  1578. addExtFields () {
  1579. return getEditableExtFieldsFromSchema(this.addFormSchemaFields)
  1580. },
  1581. addBaseFields () {
  1582. if (!Array.isArray(this.addFormSchemaFields)) {
  1583. return []
  1584. }
  1585. const sortedFields = this.addFormSchemaFields
  1586. .filter(f => f && f.visibleFlag === 'Y' && !this.isExtSchemaField(f))
  1587. .slice()
  1588. .sort((a, b) => {
  1589. const sa = Number(a && a.sortNo)
  1590. const sb = Number(b && b.sortNo)
  1591. const left = Number.isFinite(sa) ? sa : Number.MAX_SAFE_INTEGER
  1592. const right = Number.isFinite(sb) ? sb : Number.MAX_SAFE_INTEGER
  1593. return left - right
  1594. })
  1595. const tailFields = []
  1596. const normalFields = []
  1597. sortedFields.forEach(field => {
  1598. if (ADD_FULL_ROW_FIELD_CODES.has(this.getAddFieldCode(field))) {
  1599. tailFields.push(field)
  1600. return
  1601. }
  1602. normalFields.push(field)
  1603. })
  1604. return [...normalFields, ...tailFields]
  1605. },
  1606. uploadColumnMappingEntries () {
  1607. if (!this.uploadColumnMapping || typeof this.uploadColumnMapping !== 'object') {
  1608. return []
  1609. }
  1610. return Object.keys(this.uploadColumnMapping).map(header => ({
  1611. header,
  1612. fieldCode: this.uploadColumnMapping[header]
  1613. }))
  1614. }
  1615. },
  1616. created () {
  1617. this.baseColumnList = JSON.parse(JSON.stringify(this.columnList))
  1618. this.getPartNoOptions()
  1619. this.getSupplierOptions()
  1620. this.getCustomerOptions()
  1621. this.getBuyerOptions()
  1622. },
  1623. mounted () {
  1624. this.updateTableHeight()
  1625. window.addEventListener('resize', this.onWindowResize)
  1626. },
  1627. activated () {
  1628. this.updateTableHeight()
  1629. this.refreshTableLayout()
  1630. },
  1631. deactivated () {
  1632. this.refreshTableLayout()
  1633. },
  1634. beforeDestroy () {
  1635. window.removeEventListener('resize', this.onWindowResize)
  1636. if (this.addPriceLookupTimer) {
  1637. clearTimeout(this.addPriceLookupTimer)
  1638. this.addPriceLookupTimer = null
  1639. }
  1640. },
  1641. methods: {
  1642. canIssuePoOrder,
  1643. canShipPoOrder,
  1644. canClosePoOrder,
  1645. canOpenPoOrder,
  1646. canEditPoColumnByStatus,
  1647. onWindowResize () {
  1648. this.updateTableHeight()
  1649. },
  1650. updateTableHeight () {
  1651. // 主表按可视区动态高度计算,扣除分页与底部预留,避免超出或留白 - rqrq
  1652. this.$nextTick(() => {
  1653. const pageRootEl = this.$refs.pageRoot || this.$el
  1654. const tableVm = this.$refs.poTable
  1655. const tableEl = tableVm && tableVm.$el
  1656. if (!pageRootEl || !tableEl) {
  1657. return
  1658. }
  1659. const pagerVm = this.$refs.mainPager
  1660. const pagerEl = (pagerVm && pagerVm.$el) || pageRootEl.querySelector('.el-pagination')
  1661. let pagerOuterHeight = 0
  1662. if (pagerEl) {
  1663. const pagerRect = pagerEl.getBoundingClientRect()
  1664. const pagerStyle = window.getComputedStyle(pagerEl)
  1665. pagerOuterHeight = pagerRect.height +
  1666. (parseFloat(pagerStyle.marginTop) || 0) +
  1667. (parseFloat(pagerStyle.marginBottom) || 0)
  1668. }
  1669. const rootStyle = window.getComputedStyle(pageRootEl)
  1670. const rootPaddingBottom = parseFloat(rootStyle.paddingBottom) || 0
  1671. const tableTop = tableEl.getBoundingClientRect().top
  1672. const viewportBottomGap = 16
  1673. const availableHeight = window.innerHeight - tableTop - pagerOuterHeight - rootPaddingBottom - viewportBottomGap
  1674. const nextHeight = Number.isFinite(availableHeight) ? Math.floor(availableHeight) : 240
  1675. this.height = nextHeight > 240 ? nextHeight : 240
  1676. this.refreshTableLayout()
  1677. })
  1678. },
  1679. refreshTableLayout () {
  1680. this.$nextTick(() => {
  1681. if (this.$refs.poTable && this.$refs.poTable.doLayout) {
  1682. this.$refs.poTable.doLayout()
  1683. }
  1684. })
  1685. },
  1686. formatColumnCell (row, item) {
  1687. if (item.columnProp === 'orderType') {
  1688. return formatPoOrderTypeLabel(row.orderType)
  1689. }
  1690. const prop = item && item.columnProp
  1691. if (!prop || !row) {
  1692. return ''
  1693. }
  1694. if (row[prop] !== undefined && row[prop] !== null) {
  1695. return row[prop]
  1696. }
  1697. if (row.extValues && typeof row.extValues === 'object' &&
  1698. Object.prototype.hasOwnProperty.call(row.extValues, prop)) {
  1699. return row.extValues[prop]
  1700. }
  1701. return ''
  1702. },
  1703. /** Chooselist 选择列 */
  1704. isChooserEditColumn (columnProp) {
  1705. return this.chooserEditColumnProps.includes(columnProp)
  1706. },
  1707. /**
  1708. * 当前行该列是否可编辑列配置 editAble + 状态限制Part NoVendor NameCustomerBuyerPO_No 草稿/已下达
  1709. */
  1710. canEditCell (row, item) {
  1711. if (!this.editMode || !item) return false
  1712. const prop = item.columnProp
  1713. if (prop === 'customer') return false
  1714. if (this.displayOnlyColumnProps.includes(prop)) return false
  1715. if (this.isChooserEditColumn(prop)) {
  1716. return canEditPoColumnByStatus(row.status, prop)
  1717. }
  1718. if (!item.editAble) return false
  1719. return canEditPoColumnByStatus(row.status, prop)
  1720. },
  1721. getAddFieldCode (field) {
  1722. if (!field) return ''
  1723. if (field.fieldCode) {
  1724. return String(field.fieldCode).trim().toLowerCase()
  1725. }
  1726. return this.camelToSnake(this.getAddFieldProp(field))
  1727. },
  1728. getAddFieldProp (field) {
  1729. if (!field) return ''
  1730. if (field.fieldProp) {
  1731. return String(field.fieldProp).trim()
  1732. }
  1733. if (field.fieldCode) {
  1734. return this.snakeToCamel(field.fieldCode)
  1735. }
  1736. return ''
  1737. },
  1738. isExtSchemaField (field) {
  1739. const code = this.getAddFieldCode(field)
  1740. return code.indexOf('ext_') === 0
  1741. },
  1742. snakeToCamel (text) {
  1743. return String(text || '').replace(/_([a-z0-9])/g, (_, c) => c.toUpperCase())
  1744. },
  1745. camelToSnake (text) {
  1746. return String(text || '').replace(/([A-Z])/g, '_$1').toLowerCase().replace(/^_/, '')
  1747. },
  1748. isAddChooserField (field) {
  1749. return ADD_CHOOSER_FIELD_CODES.has(this.getAddFieldCode(field))
  1750. },
  1751. openAddChooserByField (field) {
  1752. const code = this.getAddFieldCode(field)
  1753. if (code === 'supplier_name') {
  1754. this.openAddSupplierSelect()
  1755. } else if (code === 'part_no') {
  1756. this.openAddPartNoSelect()
  1757. } else if (code === 'departure') {
  1758. this.openAddDepartureSelect()
  1759. } else if (code === 'destination') {
  1760. this.openAddDestinationSelect()
  1761. } else if (code === 'ship_via') {
  1762. this.openAddShipViaSelect()
  1763. }
  1764. },
  1765. getAddChooserPlaceholder (field) {
  1766. const code = this.getAddFieldCode(field)
  1767. if (code === 'supplier_name') return '请选择供应商'
  1768. if (code === 'part_no') return '请选择物料'
  1769. if (code === 'departure') return '请选择始发港'
  1770. if (code === 'destination') return '请选择目的港'
  1771. if (code === 'ship_via') return '请选择运输方式'
  1772. return ''
  1773. },
  1774. getAddFieldSelectOptions (field) {
  1775. const code = this.getAddFieldCode(field)
  1776. const optionsKey = ADD_SELECT_OPTIONS_FIELD_CODE_MAP[code]
  1777. if (!optionsKey) {
  1778. return []
  1779. }
  1780. if (Array.isArray(this[optionsKey])) {
  1781. return this[optionsKey]
  1782. }
  1783. if (this.columnSelectOptions && Array.isArray(this.columnSelectOptions[optionsKey])) {
  1784. return this.columnSelectOptions[optionsKey]
  1785. }
  1786. return []
  1787. },
  1788. isAddSelectField (field) {
  1789. return this.getAddFieldSelectOptions(field).length > 0
  1790. },
  1791. isAddFilterableSelectField (field) {
  1792. return ADD_FILTERABLE_SELECT_FIELD_CODES.has(this.getAddFieldCode(field))
  1793. },
  1794. isAddDateField (field) {
  1795. const editorType = String((field && field.editorType) || '').trim().toLowerCase()
  1796. const dataType = String((field && field.dataType) || '').trim().toLowerCase()
  1797. return editorType === 'date' || editorType === 'datetime' || dataType === 'date' || dataType === 'datetime'
  1798. },
  1799. isAddTextareaField (field) {
  1800. return ADD_TEXTAREA_FIELD_CODES.has(this.getAddFieldCode(field))
  1801. },
  1802. isAddNumberField (field) {
  1803. const code = this.getAddFieldCode(field)
  1804. if (ADD_NUMBER_FIELD_CODES.has(code)) {
  1805. return true
  1806. }
  1807. const dataType = String((field && field.dataType) || '').trim().toLowerCase()
  1808. return dataType === 'number' || dataType === 'num' || dataType === 'decimal' || dataType === 'int'
  1809. },
  1810. isAddFieldDisabled (field) {
  1811. const code = this.getAddFieldCode(field)
  1812. if (code === 'customer') {
  1813. return true
  1814. }
  1815. if (ADD_DISPLAY_ONLY_FIELD_CODES.has(code)) {
  1816. return true
  1817. }
  1818. const editorType = String((field && field.editorType) || '').trim().toLowerCase()
  1819. return editorType === 'readonly'
  1820. },
  1821. getAddFieldSpan (field) {
  1822. if (ADD_FULL_ROW_FIELD_CODES.has(this.getAddFieldCode(field))) {
  1823. return 24
  1824. }
  1825. return this.isAddTextareaField(field) ? 12 : 6
  1826. },
  1827. onAddFieldInput (field) {
  1828. const code = this.getAddFieldCode(field)
  1829. if (code === 'price' || code === 'qty') {
  1830. this.recalcAddFormValue()
  1831. }
  1832. if (code === 'qty') {
  1833. this.scheduleAutoFillAddPriceByTierPrice()
  1834. }
  1835. },
  1836. scheduleAutoFillAddPriceByTierPrice () {
  1837. if (this.addPriceLookupTimer) {
  1838. clearTimeout(this.addPriceLookupTimer)
  1839. this.addPriceLookupTimer = null
  1840. }
  1841. this.addPriceLookupTimer = setTimeout(() => {
  1842. this.addPriceLookupTimer = null
  1843. this.autoFillAddPriceByTierPrice()
  1844. }, 250)
  1845. },
  1846. autoFillAddPriceByTierPrice () {
  1847. if (!this.addDialogVisible) {
  1848. return Promise.resolve()
  1849. }
  1850. const site = (this.searchData.site || this.$store.state.user.site || '').trim()
  1851. const supplierCode = String(this.addForm.supplierNo || '').trim()
  1852. const partNo = String(this.addForm.partNo || '').trim()
  1853. const qtyVal = this.addForm.qty
  1854. if (!site || !supplierCode || !partNo || qtyVal === '' || qtyVal === null || qtyVal === undefined) {
  1855. return Promise.resolve()
  1856. }
  1857. const qty = Number(qtyVal)
  1858. if (Number.isNaN(qty) || qty < 0) {
  1859. return Promise.resolve()
  1860. }
  1861. const seq = ++this.addPriceLookupSeq
  1862. return listPoCurrentTierPrice({
  1863. site,
  1864. supplierCode,
  1865. partNo
  1866. }).then(({ data }) => {
  1867. if (seq !== this.addPriceLookupSeq) {
  1868. return
  1869. }
  1870. if (!(data && data.code === 0)) {
  1871. return
  1872. }
  1873. const matchedRow = this.findCurrentTierPriceByQty(data.rows || [], qty)
  1874. if (!matchedRow) {
  1875. return
  1876. }
  1877. const normalizedPrice = this.normalizeAddNumericValue(matchedRow.unitPrice)
  1878. if (normalizedPrice === '') {
  1879. return
  1880. }
  1881. this.$set(this.addForm, 'price', normalizedPrice)
  1882. this.recalcAddFormValue()
  1883. }).catch(() => {})
  1884. },
  1885. findCurrentTierPriceByQty (rows, qty) {
  1886. if (!Array.isArray(rows) || rows.length === 0) {
  1887. return null
  1888. }
  1889. const qtyNum = Number(qty)
  1890. if (Number.isNaN(qtyNum)) {
  1891. return null
  1892. }
  1893. for (const row of rows) {
  1894. const start = Number(row.qtyStart)
  1895. const endRaw = row.qtyEnd
  1896. const end = (endRaw === '' || endRaw === null || endRaw === undefined)
  1897. ? Number.POSITIVE_INFINITY
  1898. : Number(endRaw)
  1899. if (Number.isNaN(start) || Number.isNaN(end)) {
  1900. continue
  1901. }
  1902. if (qtyNum >= start && qtyNum <= end) {
  1903. return row
  1904. }
  1905. }
  1906. return null
  1907. },
  1908. normalizeAddNumericValue (value) {
  1909. if (value === '' || value === null || value === undefined) {
  1910. return ''
  1911. }
  1912. const num = Number(value)
  1913. if (Number.isNaN(num)) {
  1914. return ''
  1915. }
  1916. if (Number.isInteger(num)) {
  1917. return String(num)
  1918. }
  1919. return String(Number(num.toFixed(4)))
  1920. },
  1921. handleClosePoOrder (row) {
  1922. const params = buildPoDetailActionParams(row, this.$store.state.user.site)
  1923. if (!params.id && !(params.orderNo && params.site && params.itemNo != null)) {
  1924. this.$message.error('无法识别订单行,请刷新后重试')
  1925. return
  1926. }
  1927. const poLabel = row.poNo ? `PO ${row.poNo}` : '该订单'
  1928. const itemLabel = row.itemNo != null ? `${row.itemNo}` : ''
  1929. this.$confirm(`确定关闭${poLabel}${itemLabel}`, '提示', { type: 'warning' }).then(() => {
  1930. closePoDetail(params).then(({ data }) => {
  1931. if (data && data.code === 0) {
  1932. this.$message.success('关闭成功')
  1933. this.getDataList()
  1934. } else {
  1935. this.$message.error((data && data.msg) || '关闭失败')
  1936. }
  1937. }).catch(err => {
  1938. this.$message.error((err && err.message) || '关闭失败')
  1939. })
  1940. }).catch(() => {})
  1941. },
  1942. handleIssuePoOrder (row) {
  1943. const params = buildPoDetailActionParams(row, this.$store.state.user.site)
  1944. if (!params.id && !(params.orderNo && params.site && params.itemNo != null)) {
  1945. this.$message.error('无法识别订单行,请刷新后重试')
  1946. return
  1947. }
  1948. const poLabel = row.poNo ? `PO ${row.poNo}` : '该订单'
  1949. const itemLabel = row.itemNo != null ? `${row.itemNo}` : ''
  1950. this.$confirm(`确定下达${poLabel}${itemLabel}`, '提示', { type: 'warning' }).then(() => {
  1951. issuePoDetail(params).then(({ data }) => {
  1952. if (data && data.code === 0) {
  1953. this.$message.success('下达成功')
  1954. this.getDataList()
  1955. } else {
  1956. this.$message.error((data && data.msg) || '下达失败')
  1957. }
  1958. }).catch(err => {
  1959. this.$message.error((err && err.message) || '下达失败')
  1960. })
  1961. }).catch(() => {})
  1962. },
  1963. handleShipPoOrder (row) {
  1964. const params = buildPoDetailActionParams(row, this.$store.state.user.site)
  1965. if (!params.id && !(params.orderNo && params.site && params.itemNo != null)) {
  1966. this.$message.error('无法识别订单行,请刷新后重试')
  1967. return
  1968. }
  1969. const poLabel = row.poNo ? `PO ${row.poNo}` : '该订单'
  1970. const itemLabel = row.itemNo != null ? `${row.itemNo}` : ''
  1971. this.$confirm(`确定将${poLabel}${itemLabel}标记为已发货?`, '提示', { type: 'warning' }).then(() => {
  1972. shipPoDetail(params).then(({ data }) => {
  1973. if (data && data.code === 0) {
  1974. this.$message.success('发货成功')
  1975. this.getDataList()
  1976. } else {
  1977. this.$message.error((data && data.msg) || '发货失败')
  1978. }
  1979. }).catch(err => {
  1980. this.$message.error((err && err.message) || '发货失败')
  1981. })
  1982. }).catch(() => {})
  1983. },
  1984. handleOpenPoOrder (row) {
  1985. const params = buildPoDetailActionParams(row, this.$store.state.user.site)
  1986. if (!params.id && !(params.orderNo && params.site && params.itemNo != null)) {
  1987. this.$message.error('无法识别订单行,请刷新后重试')
  1988. return
  1989. }
  1990. const poLabel = row.poNo ? `PO ${row.poNo}` : '该订单'
  1991. const itemLabel = row.itemNo != null ? `${row.itemNo}` : ''
  1992. const targetStatus = resolvePoOrderStatusByInspectQty(row)
  1993. this.$confirm(`确定打开${poLabel}${itemLabel}?恢复状态为:${targetStatus}`, '提示', { type: 'warning' }).then(() => {
  1994. openPoDetail(params).then(({ data }) => {
  1995. if (data && data.code === 0) {
  1996. this.$message.success('打开成功')
  1997. this.getDataList()
  1998. } else {
  1999. this.$message.error((data && data.msg) || '打开失败')
  2000. }
  2001. }).catch(err => {
  2002. this.$message.error((err && err.message) || '打开失败')
  2003. })
  2004. }).catch(() => {})
  2005. },
  2006. /**
  2007. * 表格当前行变化将选中行深拷贝到 currentRow取消选中时为 null - rqrq
  2008. */
  2009. onTableCurrentChange (row) {
  2010. if (!row) {
  2011. this.currentRow = null
  2012. return
  2013. }
  2014. this.currentRow = row
  2015. },
  2016. /**
  2017. * 解析列对应的下拉选项优先列上 selectOptions其次 columnSelectOptions[selectOptionsKey]
  2018. */
  2019. getSelectOptionsForColumn (item) {
  2020. if (item && item.editType === 'dict-select') {
  2021. const dictType = this.getSchemaDictType(item)
  2022. if (!dictType) {
  2023. return []
  2024. }
  2025. return this.dictSelectOptionsMap[dictType] || []
  2026. }
  2027. if (item.selectOptions && item.selectOptions.length) {
  2028. return item.selectOptions
  2029. }
  2030. const key = item.selectOptionsKey
  2031. if (key && this.columnSelectOptions[key]) {
  2032. return this.columnSelectOptions[key]
  2033. }
  2034. return []
  2035. },
  2036. getSchemaDictType (item) {
  2037. if (!item) {
  2038. return ''
  2039. }
  2040. if (item.dictType) {
  2041. return String(item.dictType).trim()
  2042. }
  2043. const prop = item.columnProp
  2044. if (!prop) {
  2045. return ''
  2046. }
  2047. const field = (this.fieldSchemaFields || []).find(f => {
  2048. const code = String((f && f.fieldCode) || '').trim()
  2049. const fieldProp = String((f && f.fieldProp) || '').trim()
  2050. return fieldProp === prop || this.snakeToCamel(code) === prop
  2051. })
  2052. return field && field.dictType ? String(field.dictType).trim() : ''
  2053. },
  2054. preloadDictSelectOptions (schemaFields) {
  2055. const site = this.searchData.site || this.$store.state.user.site
  2056. if (!site || !Array.isArray(schemaFields) || schemaFields.length === 0) {
  2057. this.dictSelectOptionsMap = {}
  2058. return Promise.resolve()
  2059. }
  2060. const dictTypeSet = new Set()
  2061. schemaFields.forEach(field => {
  2062. const editorType = String((field && field.editorType) || '').trim().toLowerCase()
  2063. if (editorType !== 'dict-select' && editorType !== 'dict_select') {
  2064. return
  2065. }
  2066. const dictType = String((field && field.dictType) || '').trim()
  2067. if (dictType) {
  2068. dictTypeSet.add(dictType)
  2069. }
  2070. })
  2071. const dictTypes = Array.from(dictTypeSet)
  2072. if (dictTypes.length === 0) {
  2073. this.dictSelectOptionsMap = {}
  2074. return Promise.resolve()
  2075. }
  2076. const nextMap = {}
  2077. const loaders = dictTypes.map(dictType => {
  2078. return selectDictDataList({
  2079. site,
  2080. dictType,
  2081. dictTypeList: [],
  2082. status: 'Y'
  2083. }).then(({ data }) => {
  2084. if (data && data.code === 0) {
  2085. nextMap[dictType] = (data.rows || []).map(item => ({
  2086. label: item.dictLabel || item.dictValue,
  2087. value: item.dictValue
  2088. }))
  2089. } else {
  2090. nextMap[dictType] = []
  2091. this.$message.error((data && data.msg) || `字典加载失败: ${dictType}`)
  2092. }
  2093. }).catch(() => {
  2094. nextMap[dictType] = []
  2095. this.$message.error(`字典加载失败: ${dictType}`)
  2096. })
  2097. })
  2098. return Promise.all(loaders).then(() => {
  2099. this.dictSelectOptionsMap = nextMap
  2100. })
  2101. },
  2102. buildQueryRequest() {
  2103. return buildPoOrderQueryParams({
  2104. searchData: this.searchData,
  2105. advancedQueryData: this.advancedQueryData,
  2106. page: this.pageIndex,
  2107. limit: this.pageSize
  2108. })
  2109. },
  2110. onSessionCustomerChange (customer, customerOption) {
  2111. this.searchData.customer = customer
  2112. this.selectedCustomerScope = customerOption || null
  2113. this.dictSelectOptionsMap = {}
  2114. this.getBuyerOptions(customer)
  2115. this.pageIndex = 1
  2116. this.masterRows = []
  2117. this.dataList = []
  2118. this.totalPage = 0
  2119. if (!customer) {
  2120. this.selectedCustomerScope = null
  2121. this.fieldSchemaFields = []
  2122. this.poBuyerOptions = []
  2123. this.columnSelectOptions.poBuyerOptions = []
  2124. this.refreshTableLayout()
  2125. return
  2126. }
  2127. this.loadFieldSchema(customer).then(() => {
  2128. this.getDataList()
  2129. })
  2130. },
  2131. loadFieldSchema (customer) {
  2132. return getPoFieldSchema({
  2133. site: this.searchData.site,
  2134. customer,
  2135. scene: 'list'
  2136. }).then(({ data }) => {
  2137. if (data && data.code === 0 && data.data) {
  2138. this.fieldSchemaFields = data.data.fields || []
  2139. const queryFields = getAdvancedQueryFieldsFromSchema(this.fieldSchemaFields)
  2140. const nextAdvanced = createAdvancedQueryDataFromSchema(queryFields)
  2141. this.advancedQueryData.rows = nextAdvanced.rows
  2142. return this.preloadDictSelectOptions(this.fieldSchemaFields)
  2143. } else {
  2144. this.fieldSchemaFields = []
  2145. this.$message.error((data && data.msg) || '加载字段权限失败')
  2146. }
  2147. }).then(() => {
  2148. this.refreshTableLayout()
  2149. }).catch(() => {
  2150. this.fieldSchemaFields = []
  2151. this.$message.error('加载字段权限失败')
  2152. this.refreshTableLayout()
  2153. })
  2154. },
  2155. handleSearch() {
  2156. if (!this.searchData.customer) {
  2157. this.$message.warning('请先选择 Customer')
  2158. return
  2159. }
  2160. this.pageIndex = 1
  2161. this.getDataList()
  2162. },
  2163. openEamList (tagNo, strVal = '', conSql = '', context = 'row', pickField = '') {
  2164. this.eamTagNo = tagNo
  2165. this.pickContext = context
  2166. this.eamPickField = pickField
  2167. this.$nextTick(() => {
  2168. this.$refs.eamList.init(tagNo, strVal, conSql)
  2169. })
  2170. },
  2171. resetEamPick () {
  2172. this.pickContext = ''
  2173. this.eamTagNo = ''
  2174. this.eamPickField = ''
  2175. this.currentSelectRow = null
  2176. this.currentPartNoRow = null
  2177. this.currentDepartureRow = null
  2178. this.currentDestinationRow = null
  2179. this.currentShipViaRow = null
  2180. },
  2181. openSearchBaseList (val) {
  2182. let strVal = ''
  2183. let conSql = ''
  2184. if (val === 520) {
  2185. strVal = this.searchData.supplierNo || ''
  2186. conSql = " and supplier_no <> '' "
  2187. } else if (val === 2017) {
  2188. strVal = this.searchData.partNo || ''
  2189. conSql = " and part_no <> '' "
  2190. }
  2191. this.openEamList(val, strVal, conSql, 'search')
  2192. },
  2193. getEamData (data) {
  2194. if (!data) {
  2195. return
  2196. }
  2197. const tag = this.eamTagNo
  2198. const ctx = this.pickContext
  2199. if (ctx === 'search') {
  2200. if (tag === 520) {
  2201. this.searchData.supplierNo = data.supplier_no || data.code || ''
  2202. this.searchData.supplierName = data.supplier_name || data.name || ''
  2203. } else if (tag === 2017) {
  2204. this.searchData.partNo = data.part_no || data.code || ''
  2205. }
  2206. this.resetEamPick()
  2207. return
  2208. }
  2209. if (tag === SUPPLIER_CHOOSELIST_TAG || tag === 520) {
  2210. const { supplierNo, supplierName } = parseSupplierChooselistRow(data)
  2211. if (ctx === 'add') {
  2212. this.fillSupplierShortFields(this.addForm, supplierNo, supplierName, false).then(() => {
  2213. this.scheduleAutoFillAddPriceByTierPrice()
  2214. })
  2215. } else if (this.currentSelectRow) {
  2216. const row = this.currentSelectRow
  2217. this.fillSupplierShortFields(row, supplierNo, supplierName, true)
  2218. }
  2219. this.resetEamPick()
  2220. return
  2221. }
  2222. if (tag === 507 || tag === 2017) {
  2223. const partNo = data.part_no || data.partNo || data.code || ''
  2224. if (ctx === 'add') {
  2225. this.$set(this.addForm, 'partNo', partNo)
  2226. this.fillPartCategorySku(partNo, this.addForm)
  2227. this.scheduleAutoFillAddPriceByTierPrice()
  2228. } else if (this.currentPartNoRow) {
  2229. this.$set(this.currentPartNoRow, 'partNo', partNo)
  2230. this.fillPartCategorySku(partNo, this.currentPartNoRow)
  2231. this.$set(this.currentPartNoRow, 'changeFlag', 1)
  2232. }
  2233. this.resetEamPick()
  2234. return
  2235. }
  2236. if (tag === 2018) {
  2237. const code = this.eamPickField === 'destination'
  2238. ? (data.port_code || data.portCode || data.destination || '')
  2239. : (data.port_code || data.portCode || data.departure || '')
  2240. const portName = data.port_name || data.portName || ''
  2241. if (ctx === 'add') {
  2242. if (this.eamPickField === 'departure') {
  2243. this.addForm.departure = code
  2244. } else if (this.eamPickField === 'destination') {
  2245. this.addForm.destination = code
  2246. }
  2247. } else if (this.eamPickField === 'departure' && this.currentDepartureRow) {
  2248. this.$set(this.currentDepartureRow, 'departure', code)
  2249. this.$set(this.currentDepartureRow, 'departureName', portName)
  2250. this.$set(this.currentDepartureRow, 'changeFlag', 1)
  2251. } else if (this.eamPickField === 'destination' && this.currentDestinationRow) {
  2252. this.$set(this.currentDestinationRow, 'destination', code)
  2253. this.$set(this.currentDestinationRow, 'destinationName', portName)
  2254. this.$set(this.currentDestinationRow, 'changeFlag', 1)
  2255. }
  2256. this.resetEamPick()
  2257. return
  2258. }
  2259. if (tag === 2019) {
  2260. const via = data.method_desc || data.methodDesc || data.shipVia || ''
  2261. if (ctx === 'add') {
  2262. this.addForm.shipVia = via
  2263. } else if (this.currentShipViaRow) {
  2264. this.$set(this.currentShipViaRow, 'shipVia', via)
  2265. this.$set(this.currentShipViaRow, 'shipViaCode', data.method_no || data.methodNo || '')
  2266. this.$set(this.currentShipViaRow, 'changeFlag', 1)
  2267. }
  2268. this.resetEamPick()
  2269. }
  2270. },
  2271. getDataList() {
  2272. if (!this.searchData.customer) {
  2273. this.loading = false
  2274. this.dataList = []
  2275. this.masterRows = []
  2276. this.totalPage = 0
  2277. this.refreshTableLayout()
  2278. return
  2279. }
  2280. this.loading = true
  2281. const { params, useAdvanced } = this.buildQueryRequest()
  2282. const request = useAdvanced ? searchPoDetailAdvancedPage(params) : searchPoDetailPage(params)
  2283. request.then(({ data }) => {
  2284. if (data.code === 0) {
  2285. const list = (data.page && data.page.list ? data.page.list : []).map(row => normalizeSchemaRowValues(row))
  2286. this.dataList = list
  2287. this.masterRows = list.map(row => ({
  2288. ...row,
  2289. changeFlag: 0
  2290. }))
  2291. this.pageIndex = data.page.currPage
  2292. this.pageSize = data.page.pageSize
  2293. this.totalPage = data.page.totalCount
  2294. } else {
  2295. this.$message.error((data && data.msg) || '获取列表失败')
  2296. }
  2297. this.loading = false
  2298. this.refreshTableLayout()
  2299. }).catch(() => {
  2300. this.loading = false
  2301. this.$message.error('请求失败')
  2302. this.refreshTableLayout()
  2303. })
  2304. },
  2305. sizeChangeHandle (val) {
  2306. this.pageSize = val
  2307. this.pageIndex = 1
  2308. this.getDataList()
  2309. },
  2310. currentChangeHandle (val) {
  2311. this.pageIndex = val
  2312. this.getDataList()
  2313. },
  2314. onCellChange (row) {
  2315. if (row.price !== undefined || row.qty !== undefined) {
  2316. this.$set(row, 'value', this.calcPoValue(row.price, row.qty))
  2317. }
  2318. this.$set(row, 'changeFlag', 1)
  2319. },
  2320. calcPoValue (price, qty) {
  2321. if (price === '' || price == null || qty === '' || qty == null) {
  2322. return ''
  2323. }
  2324. const p = Number(price)
  2325. const q = Number(qty)
  2326. if (isNaN(p) || isNaN(q)) {
  2327. return ''
  2328. }
  2329. const total = p * q
  2330. return Number.isInteger(total) ? String(total) : String(Number(total.toFixed(4)))
  2331. },
  2332. recalcAddFormValue () {
  2333. this.addForm.value = this.calcPoValue(this.addForm.price, this.addForm.qty)
  2334. },
  2335. validatePriceAndQty (price, qty, label) {
  2336. if (price === '' || price == null) {
  2337. this.$message.warning((label ? label + ':' : '') + '请填写 Unit Price')
  2338. return false
  2339. }
  2340. if (qty === '' || qty == null) {
  2341. this.$message.warning((label ? label + ':' : '') + '请填写 PO Qty')
  2342. return false
  2343. }
  2344. return true
  2345. },
  2346. handleSupplierChange(row, supplierNo) {
  2347. console.log('供应商变更:', supplierNo, '行ID:', row.id)
  2348. const selectedOption = this.supplierOptions.find(opt => opt.value === supplierNo)
  2349. if (selectedOption) {
  2350. this.$set(row, 'supplierName', selectedOption.label)
  2351. this.$set(row, 'supplierNo', selectedOption.value)
  2352. this.$set(row, 'shortOffice', selectedOption.shortOffice || '')
  2353. this.$set(row, 'shortNpc', selectedOption.shortNpc || '')
  2354. this.$set(row, 'changeFlag', 1)
  2355. }
  2356. },
  2357. handlePartNoChange(row, partNo) {
  2358. console.log('物料变更:', partNo, '行ID:', row.id)
  2359. // 根据 partNo 找到对应的物料信息
  2360. const selectedOption = this.poPartNoOptions.find(opt => opt.value === partNo)
  2361. if (selectedOption) {
  2362. // 更新物料相关信息
  2363. this.$set(row, 'partNo', selectedOption.value)
  2364. this.$set(row, 'item', selectedOption.item || '')
  2365. //同时更新 category 和 sku
  2366. this.$set(row, 'category', selectedOption.category || '')
  2367. this.$set(row, 'categoryName', selectedOption.categoryName || '')
  2368. this.$set(row, 'sku', selectedOption.sku || '')
  2369. this.$set(row, 'changeFlag', 1)
  2370. }
  2371. },
  2372. handlePortChange(row, field, value) {
  2373. console.log(`${field}变更:`, value, '行ID:', row.id)
  2374. this.$set(row, field, value) // 直接设置字段值
  2375. this.$set(row, 'changeFlag', 1)
  2376. // 注意:这里还需要同步更新对应的 rowDeparture/rowDestination/rowShipVia
  2377. if (field === 'departure') {
  2378. this.$set(this.rowDeparture, row.id, value)
  2379. } else if (field === 'destination') {
  2380. this.$set(this.rowDestination, row.id, value)
  2381. } else if (field === 'shipVia') {
  2382. this.$set(this.rowShipVia, row.id, value)
  2383. }
  2384. // 如果三个字段都填写了,获取运输方式选项
  2385. if (row.departure && row.destination && row.shipVia) {
  2386. this.getTransportOptions(row.departure, row.destination, row.shipVia)
  2387. }
  2388. },
  2389. getTransportOptions(departure, destination, shipVia) {
  2390. console.log('获取运输方式选项:', departure, destination, shipVia)
  2391. //调用接口获取运输方式选项
  2392. searchTransportOptions({ departure, destination, shipVia }).then(({ data }) => {
  2393. if (data && data.code === 0) {
  2394. this.transportOptions = (data.rows || []).map(item => ({
  2395. label: item.shipVia,
  2396. value: item.shipVia,
  2397. eta: item.eta
  2398. }))
  2399. } else {
  2400. this.$message.error(data.msg || '获取运输方式选项失败')
  2401. }
  2402. }).catch(error => {
  2403. this.$message.error('获取运输方式选项失败: ' + error.message)
  2404. })
  2405. },
  2406. toggleEditMode () {
  2407. if (!this.editMode) {
  2408. this.editMode = true
  2409. return
  2410. }
  2411. const changed = this.masterRows.filter(r => r.changeFlag === 1)
  2412. this.batchUpdatePoOrder(changed)
  2413. },
  2414. cancelEditMode () {
  2415. this.editMode = false
  2416. this.resetEamPick()
  2417. this.getDataList()
  2418. },
  2419. formatCodeOptionLabel (code, name) {
  2420. if (!name) {
  2421. return code || ''
  2422. }
  2423. if (!code) {
  2424. return name
  2425. }
  2426. return `${code} - ${name}`
  2427. },
  2428. getCustomerOptions () {
  2429. return getPoCustomerOptions({
  2430. site: this.$store.state.user.site
  2431. }).then(({ data }) => {
  2432. if (data && data.code === 0) {
  2433. this.poCustomerOptions = (data.rows || []).map(item => ({
  2434. label: this.formatCodeOptionLabel(item.code, item.name),
  2435. value: item.code
  2436. }))
  2437. this.columnSelectOptions.poCustomerOptions = this.poCustomerOptions
  2438. } else {
  2439. this.$message.error(data.msg || '操作失败')
  2440. }
  2441. }).catch(error => {
  2442. this.$message.error('操作失败: ' + error.message)
  2443. })
  2444. },
  2445. getBuyerOptions (customer = this.searchData.customer) {
  2446. const customerCode = (customer || '').trim()
  2447. if (!customerCode) {
  2448. this.poBuyerOptions = []
  2449. this.columnSelectOptions.poBuyerOptions = []
  2450. return Promise.resolve([])
  2451. }
  2452. this.poBuyerOptions = []
  2453. this.columnSelectOptions.poBuyerOptions = []
  2454. return getPoBuyerOptions({
  2455. site: this.$store.state.user.site,
  2456. customer: customerCode
  2457. }).then(({ data }) => {
  2458. if (data && data.code === 0) {
  2459. this.poBuyerOptions = (data.rows || []).map(item => ({
  2460. label: this.formatCodeOptionLabel(item.code, item.name),
  2461. value: item.code
  2462. }))
  2463. this.columnSelectOptions.poBuyerOptions = this.poBuyerOptions
  2464. } else {
  2465. this.$message.error(data.msg || '操作失败')
  2466. }
  2467. }).catch(error => {
  2468. this.$message.error('操作失败: ' + error.message)
  2469. })
  2470. },
  2471. getPartNoOptions() {
  2472. console.log('获取分类选项')
  2473. getPartList(
  2474. {
  2475. site: this.$store.state.user.site
  2476. }
  2477. ).then(({data}) => {
  2478. if (data && data.code === 0) {
  2479. console.log('接口返回的rows:', data.rows) // 查看返回数据
  2480. this.poPartNoOptions = (data.rows || []).map(item => ({
  2481. label: item.partNo,
  2482. value: item.partNo,
  2483. item: item.item,
  2484. category: item.category,
  2485. categoryName: item.categoryName,
  2486. sku: item.sku
  2487. }))
  2488. } else {
  2489. this.$message.error(data.msg || '操作失败')
  2490. }
  2491. }).catch(error => {
  2492. this.$message.error('操作失败: ' + error.message)
  2493. })
  2494. },
  2495. getSupplierOptions(){
  2496. console.log('获取供应商选项')
  2497. checkSrmSupplierList(
  2498. {
  2499. site: this.$store.state.user.site
  2500. }
  2501. ).then(({data}) => {
  2502. if (data && data.code === 0) {
  2503. console.log('接口返回的rows:', data.rows) // 查看返回数据
  2504. this.supplierOptions = (data.rows || []).map(item => ({
  2505. label: item.supplierName,
  2506. value: item.supplierNo,
  2507. shortOffice: item.cshortOffice,
  2508. shortNpc: item.cshortNpc
  2509. }))
  2510. } else {
  2511. this.$message.error(data.msg || '操作失败')
  2512. }
  2513. }).catch(error => {
  2514. this.$message.error('操作失败: ' + error.message)
  2515. })
  2516. },
  2517. getPortOptions(){
  2518. console.log('获取港口选项')
  2519. searchTransportOptions(
  2520. {
  2521. site: this.$store.state.user.site
  2522. }
  2523. ).then(({data}) => {
  2524. if (data && data.code === 0) {
  2525. console.log('接口返回的rows:', data.rows) // 查看返回数据
  2526. this.transportOptions = (data.rows || []).map(item => ({
  2527. label: item.supplierName,
  2528. value: item.supplierNo,
  2529. destination: item.destination,
  2530. departure: item.departure,
  2531. shipVia: item.shipVia,
  2532. etc: item.eta
  2533. }))
  2534. } else {
  2535. this.$message.error(data.msg || '操作失败')
  2536. }
  2537. }).catch(error => {
  2538. this.$message.error('操作失败: ' + error.message)
  2539. })
  2540. },
  2541. // 保存订单信息
  2542. buildBatchUpdateRow (row) {
  2543. const value = this.calcPoValue(row.price, row.qty)
  2544. const extValues = buildExtValuesFromRow(row, this.fieldSchemaFields)
  2545. return {
  2546. orderNo: row.orderNo,
  2547. site: row.site,
  2548. itemNo: row.itemNo,
  2549. supplierNo: row.supplierNo,
  2550. supplierName: row.supplierName,
  2551. buyer: row.buyer,
  2552. customer: row.customer,
  2553. poNo: row.poNo,
  2554. departure: row.departure,
  2555. destination: row.destination,
  2556. shipVia: row.shipVia,
  2557. orderDate: row.orderDate,
  2558. enquiry: row.enquiry,
  2559. confirmed: row.confirmed,
  2560. partNo: row.partNo,
  2561. item: row.item,
  2562. status: row.status,
  2563. qty: row.qty === '' ? null : Number(row.qty),
  2564. price: row.price === '' ? null : Number(row.price),
  2565. value: value === '' ? null : Number(value),
  2566. shipQty: row.shipQty,
  2567. sumPrice: row.sumPrice,
  2568. wantReceiveDate: row.wantReceiveDate,
  2569. narrival: row.narrival,
  2570. crd: row.crd,
  2571. inspection: row.inspection,
  2572. realCrd: row.realCrd,
  2573. poPlaceDate: row.poPlaceDate,
  2574. poPromiseReadyDate: row.poPromiseReadyDate,
  2575. poActualReadyDate: row.poActualReadyDate,
  2576. chinaOfficeInspectionDate: row.chinaOfficeInspectionDate,
  2577. shipToNpcDate: row.shipToNpcDate,
  2578. inspectionResult: row.inspectionResult,
  2579. flexid: row.flexid,
  2580. obd: row.obd,
  2581. docSent: row.docSent,
  2582. telexRelease: row.telexRelease,
  2583. advancePayment: row.advancePayment,
  2584. advancePaid: row.advancePaid,
  2585. planner: row.planner,
  2586. remarkDelay: row.remarkDelay,
  2587. remark: row.remark,
  2588. extValues
  2589. }
  2590. },
  2591. batchUpdatePoOrder(changed) {
  2592. for (const row of changed) {
  2593. const label = row.orderNo ? `订单 ${row.orderNo}` : '订单'
  2594. if (!this.validatePriceAndQty(row.price, row.qty, label)) {
  2595. return
  2596. }
  2597. this.$set(row, 'value', this.calcPoValue(row.price, row.qty))
  2598. }
  2599. const updateData = changed.map(row => this.buildBatchUpdateRow(row))
  2600. // 调用批量修改接口
  2601. batchUpdatePoDetail(updateData)
  2602. .then(({ data }) => {
  2603. if (data && data.code === 0) {
  2604. this.$message({
  2605. message: `已提交 ${updateData.length} 行变更`,
  2606. type: 'success',
  2607. duration: 2000
  2608. })
  2609. changed.forEach(r => {
  2610. this.$set(r, 'changeFlag', 0)
  2611. })
  2612. this.editMode = false
  2613. this.getDataList()
  2614. } else {
  2615. this.$message.error(data.msg || '操作失败')
  2616. }
  2617. })
  2618. .catch(error => {
  2619. this.$message.error('操作失败: ' + error.message)
  2620. })
  2621. },
  2622. // ========== 上传功能 ==========
  2623. // 打开上传弹窗
  2624. exportModal() {
  2625. if (!this.searchData.customer) {
  2626. this.$message.warning('请先选择 Customer')
  2627. return
  2628. }
  2629. this.uploadDialogVisible = true
  2630. this.uploadFileName = ''
  2631. this.uploadFile = null
  2632. this.uploadPreviewList = []
  2633. this.uploadSkippedColumns = []
  2634. this.uploadColumnMapping = {}
  2635. this.uploadPreviewColumns = []
  2636. },
  2637. // 文件选择变化
  2638. handleFileChange(file) {
  2639. this.uploadFile = file.raw
  2640. this.uploadFileName = file.name
  2641. },
  2642. // 预览上传数据
  2643. previewUpload() {
  2644. if (!this.uploadFile) {
  2645. this.$message.warning('请先选择文件')
  2646. return
  2647. }
  2648. if (!this.searchData.customer) {
  2649. this.$message.warning('请先选择 Customer')
  2650. return
  2651. }
  2652. const formData = new FormData()
  2653. formData.append('file', this.uploadFile)
  2654. formData.append('site', this.searchData.site || this.$store.state.user.site)
  2655. formData.append('customer', this.searchData.customer)
  2656. this.$http({
  2657. url: this.$http.adornUrl('/pODetail/previewUpload'),
  2658. method: 'post',
  2659. data: formData
  2660. }).then(({ data }) => {
  2661. if (data && data.code === 0) {
  2662. const preview = data.data || {}
  2663. this.uploadPreviewList = preview.rows || []
  2664. this.uploadSkippedColumns = preview.skippedColumns || []
  2665. this.uploadColumnMapping = preview.columnMapping || {}
  2666. this.refreshUploadPreviewColumns()
  2667. this.$message.success('文件解析成功,请确认数据后点击保存')
  2668. } else {
  2669. this.$message.error(data.msg || '文件解析失败')
  2670. }
  2671. }).catch((error) => {
  2672. console.error('文件解析失败:', error)
  2673. const errorMsg = (error.response && error.response.data && error.response.data.msg) || error.message || '未知错误'
  2674. this.$message.error('文件解析失败: ' + errorMsg)
  2675. })
  2676. },
  2677. refreshUploadPreviewColumns () {
  2678. this.uploadPreviewColumns = buildImportPreviewColumns(
  2679. this.uploadPreviewList,
  2680. this.fieldSchemaFields,
  2681. this.uploadColumnMapping
  2682. )
  2683. },
  2684. exportExcel () {
  2685. if (this.editMode) {
  2686. this.$message.warning('快速编辑模式下不允许导出,请先点击取消或确定')
  2687. return
  2688. }
  2689. if (!this.searchData.customer) {
  2690. this.$message.warning('请先选择 Customer')
  2691. return
  2692. }
  2693. const now = new Date()
  2694. const year = now.getFullYear()
  2695. const month = String(now.getMonth() + 1).padStart(2, '0')
  2696. const day = String(now.getDate()).padStart(2, '0')
  2697. const hour = String(now.getHours()).padStart(2, '0')
  2698. const minute = String(now.getMinutes()).padStart(2, '0')
  2699. const second = String(now.getSeconds()).padStart(2, '0')
  2700. const exportName = `PO订单列表${year}${month}${day}${hour}${minute}${second}`
  2701. const { params, useAdvanced } = buildPoOrderQueryParams({
  2702. searchData: this.searchData,
  2703. advancedQueryData: this.advancedQueryData,
  2704. page: 1,
  2705. limit: 99999
  2706. })
  2707. try {
  2708. excel.exportTable({
  2709. url: useAdvanced ? 'pODetail/advancedPage' : 'pODetail/page',
  2710. columnMapping: this.visibleColumns,
  2711. mergeSetting: [],
  2712. params,
  2713. fileName: exportName + '.xlsx',
  2714. rowFetcher: res => {
  2715. const page = res.data && res.data.page
  2716. const rows = ((page && page.list) || []).map(row => normalizeSchemaRowValues(row))
  2717. return { rows }
  2718. },
  2719. columnFormatter: [],
  2720. dropColumns: []
  2721. })
  2722. } catch (error) {
  2723. this.$message.error('导出失败: ' + error.message)
  2724. }
  2725. },
  2726. // 确认上传
  2727. confirmUpload() {
  2728. if (this.uploadPreviewList.length === 0) {
  2729. this.$message.warning('没有可保存的数据')
  2730. return
  2731. }
  2732. this.$confirm(`确认保存 ${this.uploadPreviewList.length} 条数据吗?`, '提示', {
  2733. confirmButtonText: '确定',
  2734. cancelButtonText: '取消',
  2735. type: 'warning'
  2736. }).then(() => {
  2737. const formData = new FormData()
  2738. formData.append('file', this.uploadFile)
  2739. formData.append('site', this.searchData.site || this.$store.state.user.site)
  2740. formData.append('customer', this.searchData.customer)
  2741. this.$http({
  2742. url: this.$http.adornUrl('/pODetail/batchSave'),
  2743. method: 'post',
  2744. data: formData
  2745. }).then(({ data }) => {
  2746. if (data && data.code === 0) {
  2747. const result = data.data || {}
  2748. const successCount = result.successCount || 0
  2749. const failCount = result.failCount || 0
  2750. let msg = `导入完成:成功 ${successCount} 条,失败 ${failCount}`
  2751. if (result.rowErrors && result.rowErrors.length) {
  2752. msg += ';' + result.rowErrors.slice(0, 3).map(e => `${e.rowNo}${e.message}`).join(';')
  2753. }
  2754. if (failCount > 0) {
  2755. this.$message.warning(msg)
  2756. } else {
  2757. this.$message.success(msg)
  2758. }
  2759. this.uploadDialogVisible = false
  2760. this.getDataList()
  2761. } else {
  2762. this.$message.error(data.msg || '数据保存失败')
  2763. }
  2764. }).catch((error) => {
  2765. console.error('数据保存失败:', error)
  2766. const errorMsg = (error.response && error.response.data && error.response.data.msg) || error.message || '未知错误'
  2767. this.$message.error('数据保存失败: ' + errorMsg)
  2768. })
  2769. }).catch(() => {})
  2770. },
  2771. // 下载模板
  2772. downloadTemplate() {
  2773. const loading = this.$loading({
  2774. lock: true,
  2775. text: '正在下载模板...',
  2776. spinner: 'el-icon-loading',
  2777. background: 'rgba(0, 0, 0, 0.7)'
  2778. })
  2779. this.$http({
  2780. url: this.$http.adornUrl('/pODetail/downloadTemplate'),
  2781. method: 'get',
  2782. responseType: 'blob'
  2783. }).then(response => {
  2784. loading.close()
  2785. // 创建下载文件
  2786. const blob = new Blob([response.data], {
  2787. type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
  2788. })
  2789. const url = window.URL.createObjectURL(blob)
  2790. const link = document.createElement('a')
  2791. link.href = url
  2792. link.download = 'PO订单导入模板.xlsx'
  2793. document.body.appendChild(link)
  2794. link.click()
  2795. document.body.removeChild(link)
  2796. window.URL.revokeObjectURL(url)
  2797. this.$message.success('模板下载成功')
  2798. }).catch(error => {
  2799. loading.close()
  2800. console.error('模板下载失败:', error)
  2801. this.$message.error('模板下载失败,请联系管理员')
  2802. })
  2803. },
  2804. // 打开供应商选择弹窗
  2805. openSupplierSelect(row) {
  2806. this.currentSelectRow = row
  2807. const conSql = " and site = '" + this.$store.state.user.site + "'"
  2808. this.openEamList(SUPPLIER_CHOOSELIST_TAG, '', conSql, 'row', 'supplier')
  2809. },
  2810. applySupplierSelection (target, supplierNo, supplierName, shortOffice, shortNpc, markChanged) {
  2811. if (!target) return
  2812. this.$set(target, 'supplierName', supplierName)
  2813. this.$set(target, 'supplierNo', supplierNo)
  2814. this.$set(target, 'shortOffice', shortOffice)
  2815. this.$set(target, 'shortNpc', shortNpc)
  2816. if (markChanged) {
  2817. this.$set(target, 'changeFlag', 1)
  2818. }
  2819. },
  2820. fillSupplierShortFields (target, supplierNo, supplierName, markChanged) {
  2821. if (!target || !supplierNo) {
  2822. return Promise.resolve()
  2823. }
  2824. this.applySupplierSelection(target, supplierNo, supplierName, target.shortOffice || '', target.shortNpc || '', markChanged)
  2825. return fetchSupplierDetail(supplierNo, this.$store.state.user.site).then(detail => {
  2826. const { shortOffice, shortNpc } = resolveSupplierShortFieldsFromDetail(detail)
  2827. this.applySupplierSelection(target, supplierNo, supplierName, shortOffice, shortNpc, markChanged)
  2828. }).catch(() => {})
  2829. },
  2830. fillPartCategorySku (partNo, target) {
  2831. if (!partNo || !target) return
  2832. const targetSite = String(target.site || this.$store.state.user.site || '').trim()
  2833. const apply = (item, category, categoryName, sku) => {
  2834. this.$set(target, 'item', item)
  2835. this.$set(target, 'category', category)
  2836. this.$set(target, 'categoryName', categoryName)
  2837. this.$set(target, 'sku', sku)
  2838. }
  2839. const fromList = this.poPartNoOptions.find(opt => opt.value === partNo)
  2840. if (fromList) {
  2841. apply(fromList.item || '', fromList.category || '', fromList.categoryName || '', fromList.sku || '')
  2842. return
  2843. }
  2844. searchPartInfo({ site: targetSite, partNo }).then(({ data }) => {
  2845. if (data && data.code === 0 && data.data) {
  2846. apply(data.data.item || '', data.data.category || '', data.data.categoryName || '', data.data.sku || '')
  2847. }
  2848. }).catch(() => {})
  2849. },
  2850. applySelectedPartToTarget (target, partRow, markChanged) {
  2851. if (!target || !partRow) {
  2852. return
  2853. }
  2854. const partNo = partRow.partNo || partRow.part_no || ''
  2855. if (!partNo) {
  2856. return
  2857. }
  2858. this.$set(target, 'partNo', partNo)
  2859. this.$set(target, 'partDesc', partRow.partDesc || '')
  2860. this.$set(target, 'item', partRow.item || '')
  2861. this.$set(target, 'sku', partRow.sku || '')
  2862. this.fillPartCategorySku(partNo, target)
  2863. if (markChanged) {
  2864. this.$set(target, 'changeFlag', 1)
  2865. }
  2866. },
  2867. openSupplierPartDialog (context, row = null) {
  2868. const site = String((context === 'row' ? (row && row.site) : this.searchData.site) || this.$store.state.user.site || '').trim()
  2869. const supplierNo = String((context === 'row'
  2870. ? (row && (row.supplierNo || row.supplier_no || row.supplierCode || row.supplier_code))
  2871. : this.addForm.supplierNo) || '').trim()
  2872. if (!site) {
  2873. this.$message.warning('请先选择site')
  2874. return
  2875. }
  2876. if (!supplierNo) {
  2877. this.$message.warning('请先选择供应商')
  2878. return
  2879. }
  2880. this.supplierPartDialogVisible = true
  2881. this.supplierPartDialogLoading = true
  2882. this.supplierPartDialogRows = []
  2883. this.supplierPartDialogContext = context
  2884. this.supplierPartDialogTargetRow = context === 'row' ? row : null
  2885. this.supplierPartDialogSupplierNo = supplierNo
  2886. this.supplierPartDialogSite = site
  2887. listPoSupplierPartOptions({
  2888. site,
  2889. supplierCode: supplierNo,
  2890. active: 'Y'
  2891. }).then(({ data }) => {
  2892. if (data && data.code === 0) {
  2893. this.supplierPartDialogRows = (data.rows || []).map(item => ({
  2894. partNo: item.partNo || '',
  2895. partDesc: item.partDesc || '',
  2896. item: item.item || '',
  2897. sku: item.sku || ''
  2898. }))
  2899. if (this.supplierPartDialogRows.length === 0) {
  2900. this.$message.warning('该供应商未维护供应商可供物料')
  2901. }
  2902. return
  2903. }
  2904. this.supplierPartDialogRows = []
  2905. this.$message.error((data && data.msg) || '获取供应商可供物料失败')
  2906. }).catch(() => {
  2907. this.supplierPartDialogRows = []
  2908. this.$message.error('获取供应商可供物料失败')
  2909. }).finally(() => {
  2910. this.supplierPartDialogLoading = false
  2911. })
  2912. },
  2913. handleSupplierPartRowDblClick (row) {
  2914. if (!row) {
  2915. return
  2916. }
  2917. if (this.supplierPartDialogContext === 'add') {
  2918. this.applySelectedPartToTarget(this.addForm, row, false)
  2919. this.scheduleAutoFillAddPriceByTierPrice()
  2920. } else if (this.supplierPartDialogContext === 'row' && this.supplierPartDialogTargetRow) {
  2921. this.applySelectedPartToTarget(this.supplierPartDialogTargetRow, row, true)
  2922. }
  2923. this.supplierPartDialogVisible = false
  2924. },
  2925. resetSupplierPartDialog () {
  2926. this.supplierPartDialogLoading = false
  2927. this.supplierPartDialogRows = []
  2928. this.supplierPartDialogContext = ''
  2929. this.supplierPartDialogTargetRow = null
  2930. this.supplierPartDialogSupplierNo = ''
  2931. this.supplierPartDialogSite = ''
  2932. },
  2933. resolveAddOrderTypeByCustomer () {
  2934. const customerOrderType = this.selectedCustomerScope && this.selectedCustomerScope.orderType
  2935. ? this.selectedCustomerScope.orderType
  2936. : 'PO'
  2937. return formatPoOrderTypeLabel(customerOrderType) || '采购订单'
  2938. },
  2939. openAddDialog () {
  2940. if (!this.searchData.customer) {
  2941. this.$message.warning('请选择customer')
  2942. return
  2943. }
  2944. if (this.addPriceLookupTimer) {
  2945. clearTimeout(this.addPriceLookupTimer)
  2946. this.addPriceLookupTimer = null
  2947. }
  2948. this.addPriceLookupSeq += 1
  2949. this.addForm = this.createEmptyAddForm(this.resolveAddOrderTypeByCustomer())
  2950. this.addForm.customer = this.searchData.customer
  2951. this.addDialogVisible = true
  2952. this.loadAddFieldSchema(this.searchData.customer)
  2953. if (!this.poPartNoOptions.length) {
  2954. this.getPartNoOptions()
  2955. }
  2956. if (!this.poCustomerOptions.length) {
  2957. this.getCustomerOptions()
  2958. }
  2959. this.getBuyerOptions(this.searchData.customer)
  2960. },
  2961. loadAddFieldSchema (customer) {
  2962. return getPoFieldSchema({
  2963. site: this.searchData.site,
  2964. customer,
  2965. scene: 'add'
  2966. }).then(({ data }) => {
  2967. if (data && data.code === 0 && data.data) {
  2968. this.addFormSchemaFields = data.data.fields || []
  2969. } else {
  2970. this.addFormSchemaFields = []
  2971. }
  2972. }).catch(() => {
  2973. this.addFormSchemaFields = []
  2974. })
  2975. },
  2976. getAddExtValue (fieldCode) {
  2977. if (!this.addForm.extValues) {
  2978. return ''
  2979. }
  2980. return this.addForm.extValues[fieldCode] == null ? '' : this.addForm.extValues[fieldCode]
  2981. },
  2982. setAddExtValue (fieldCode, val) {
  2983. if (!this.addForm.extValues) {
  2984. this.$set(this.addForm, 'extValues', {})
  2985. }
  2986. this.$set(this.addForm.extValues, fieldCode, val)
  2987. },
  2988. createEmptyAddForm (orderType = '采购订单') {
  2989. return {
  2990. customer: '',
  2991. buyer: '',
  2992. supplierName: '',
  2993. supplierNo: '',
  2994. shortOffice: '',
  2995. shortNpc: '',
  2996. poNo: '',
  2997. orderType: orderType || '采购订单',
  2998. partNo: '',
  2999. item: '',
  3000. category: '',
  3001. categoryName: '',
  3002. sku: '',
  3003. price: '',
  3004. qty: '',
  3005. value: '',
  3006. shipQty: '',
  3007. sumPrice: '',
  3008. departure: '',
  3009. destination: '',
  3010. shipVia: '',
  3011. orderDate: '',
  3012. enquiry: '',
  3013. status: '草稿',
  3014. confirmed: '',
  3015. wantReceiveDate: '',
  3016. narrival: '',
  3017. crd: '',
  3018. inspection: '',
  3019. realCrd: '',
  3020. poPlaceDate: '',
  3021. poPromiseReadyDate: '',
  3022. poActualReadyDate: '',
  3023. chinaOfficeInspectionDate: '',
  3024. shipToNpcDate: '',
  3025. inspectionResult: '',
  3026. flexid: '',
  3027. obd: '',
  3028. docSent: '',
  3029. telexRelease: '',
  3030. advancePayment: 'N',
  3031. advancePaid: '',
  3032. planner: '',
  3033. remarkDelay: '',
  3034. remark: '',
  3035. extValues: {}
  3036. }
  3037. },
  3038. openAddSupplierSelect () {
  3039. const conSql = " and site = '" + this.$store.state.user.site + "'"
  3040. this.openEamList(SUPPLIER_CHOOSELIST_TAG, '', conSql, 'add', 'supplier')
  3041. },
  3042. openAddPartNoSelect () {
  3043. this.openSupplierPartDialog('add')
  3044. },
  3045. openAddDepartureSelect () {
  3046. this.openEamList(2018, '', this.buildDeparturePortConSql(), 'add', 'departure')
  3047. },
  3048. openAddDestinationSelect () {
  3049. this.openEamList(2018, '', this.buildDestinationPortConSql(), 'add', 'destination')
  3050. },
  3051. openAddShipViaSelect () {
  3052. this.openEamList(2019, '', '', 'add', 'shipVia')
  3053. },
  3054. saveAddPoOrder () {
  3055. if (!this.addForm.poNo || !this.addForm.supplierName || !this.addForm.partNo) {
  3056. this.$message.warning('请填写 PO No、Vendor Name、Part No')
  3057. return
  3058. }
  3059. if (!this.validatePriceAndQty(this.addForm.price, this.addForm.qty)) {
  3060. return
  3061. }
  3062. this.recalcAddFormValue()
  3063. this.addFormSaving = true
  3064. const calculatedValue = this.calcPoValue(this.addForm.price, this.addForm.qty)
  3065. const payload = this.buildAddPayload(calculatedValue)
  3066. createPoOrder(payload).then(({ data }) => {
  3067. if (data && data.code === 0) {
  3068. this.$message.success('新增成功')
  3069. this.addDialogVisible = false
  3070. this.getDataList()
  3071. } else {
  3072. this.$message.error((data && data.msg) || '新增失败')
  3073. }
  3074. }).catch(err => {
  3075. this.$message.error((err && err.message) || '新增失败')
  3076. }).finally(() => {
  3077. this.addFormSaving = false
  3078. })
  3079. },
  3080. buildAddPayload (calculatedValue) {
  3081. const payload = {
  3082. site: this.$store.state.user.site,
  3083. customer: this.searchData.customer,
  3084. extValues: {}
  3085. }
  3086. this.addBaseFields.forEach(field => {
  3087. const prop = this.getAddFieldProp(field)
  3088. const code = this.getAddFieldCode(field)
  3089. if (!prop || !code) {
  3090. return
  3091. }
  3092. let value = this.addForm[prop]
  3093. if (code === 'customer') {
  3094. value = this.searchData.customer || value
  3095. } else if (code === 'value') {
  3096. value = calculatedValue === '' ? null : Number(calculatedValue)
  3097. } else if (code === 'price' || code === 'qty' || code === 'ship_qty' || code === 'sum_price') {
  3098. value = (value === '' || value === null || value === undefined) ? null : Number(value)
  3099. }
  3100. payload[prop] = value
  3101. })
  3102. this.addExtFields.forEach(field => {
  3103. const fieldCode = (field && field.fieldCode) ? String(field.fieldCode).trim() : ''
  3104. if (!fieldCode) {
  3105. return
  3106. }
  3107. const value = this.getAddExtValue(fieldCode)
  3108. if (value === '' || value === null || value === undefined) {
  3109. return
  3110. }
  3111. payload.extValues[fieldCode] = value
  3112. })
  3113. return payload
  3114. },
  3115. openPartNoSelect (row) {
  3116. this.openSupplierPartDialog('row', row)
  3117. },
  3118. openDepartureSelect (row) {
  3119. this.currentDepartureRow = row
  3120. this.openEamList(2018, '', this.buildDeparturePortConSql(), 'row', 'departure')
  3121. },
  3122. openDestinationSelect (row) {
  3123. this.currentDestinationRow = row
  3124. this.openEamList(2018, '', this.buildDestinationPortConSql(), 'row', 'destination')
  3125. },
  3126. openShipViaSelect (row) {
  3127. this.currentShipViaRow = row
  3128. this.openEamList(2019, '', '', 'row', 'shipVia')
  3129. },
  3130. /**
  3131. * 判断是否为新增行没有 id id 为空表示新增
  3132. */
  3133. isNewRow(row) {
  3134. return !row.id || row.id === '' || row.id === null || row.id === undefined
  3135. },
  3136. buildDeparturePortConSql () {
  3137. return " and is_departure_port = 'Y'"
  3138. },
  3139. buildDestinationPortConSql () {
  3140. return " and is_destination_port = 'Y'"
  3141. }
  3142. }
  3143. }
  3144. </script>
  3145. <style scoped lang="scss">
  3146. .po-add-form-wrap {
  3147. max-height: calc(100vh - 210px);
  3148. overflow-y: scroll;
  3149. overflow-x: hidden;
  3150. padding: 0 12px 8px;
  3151. }
  3152. /* 预留滚动槽位,避免滚动条出现/消失导致表单宽度抖动 */
  3153. @supports (scrollbar-gutter: stable) {
  3154. .po-add-form-wrap {
  3155. overflow-y: auto;
  3156. scrollbar-gutter: stable both-edges;
  3157. }
  3158. }
  3159. /* 防止滚动条切换时标签换行,进一步降低布局抖动 */
  3160. .po-add-form-wrap /deep/ .el-form--label-top .el-form-item__label {
  3161. white-space: nowrap;
  3162. }
  3163. .el-table /deep/ .cell {
  3164. height: auto;
  3165. line-height: 1.5;
  3166. }
  3167. </style>