salesOutForm.vue 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500
  1. <template>
  2. <a-spin :spinning="loading">
  3. <JFormContainer :disabled="disabled">
  4. <template #detail>
  5. <a-form v-bind="formItemLayout" name="SaleOrderForm" ref="formRef">
  6. <a-row>
  7. <a-col :span="12">
  8. <a-form-item label="出库单号(bill code)" v-bind="validateInfos.billCode" id="SaleOrderForm-billCode" name="billCode">
  9. <a-input v-model:value="formData.billCode" placeholder="自动生成" disabled />
  10. </a-form-item>
  11. </a-col>
  12. <a-col :span="12">
  13. <a-form-item label="出库日期(bill date)" v-bind="validateInfos.billDate" id="SaleOrderForm-billDate" name="billDate">
  14. <a-date-picker
  15. placeholder="请选择出库日期(bill date)"
  16. v-model:value="formData.billDate"
  17. value-format="YYYY-MM-DD"
  18. style="width: 100%"
  19. allow-clear
  20. />
  21. </a-form-item>
  22. </a-col>
  23. <a-col :span="12">
  24. <a-form-item label="项目(project)" v-bind="validateInfos.projectName" id="SaleOrderForm-projectName" name="projectName">
  25. <a-input-search
  26. v-model:value="formData.projectName"
  27. readonly
  28. placeholder="请输入项目(project)"
  29. allow-clear
  30. enter-button="Search"
  31. :disabled="notAllowEdit"
  32. @search="onSearchProject"
  33. />
  34. </a-form-item>
  35. </a-col>
  36. <a-col :span="12">
  37. <a-form-item label="客户(customer)" v-bind="validateInfos.customerName" id="SaleOrderForm-customerName" name="customerName">
  38. <a-input v-model:value="formData.customerName" placeholder="请输入" disabled allow-clear />
  39. </a-form-item>
  40. </a-col>
  41. <a-col :span="12">
  42. <a-form-item
  43. label="销售部门(sale department)"
  44. v-bind="validateInfos.saleDepartment"
  45. id="SaleOrderForm-saleDepartment"
  46. name="saleDepartment"
  47. >
  48. <a-input v-model:value="formData.saleDepartmentName" placeholder="请输入" disabled allow-clear />
  49. </a-form-item>
  50. </a-col>
  51. <a-col :span="12">
  52. <a-form-item label="业务员(salesman)" v-bind="validateInfos.salesman" id="SaleOrderForm-salesman" name="salesman">
  53. <a-input v-model:value="formData.salesmanName" placeholder="请输入" disabled allow-clear />
  54. </a-form-item>
  55. </a-col>
  56. <a-col :span="12">
  57. <a-form-item
  58. label="货位(goods allocation)"
  59. v-bind="validateInfos.goodsAllocation"
  60. id="SaleOrderForm-goodsAllocation"
  61. name="goodsAllocation"
  62. >
  63. <JDictSelectTag v-model:value="formData.goodsAllocation" placeholder="请选择" dictCode="goods_allocation" />
  64. </a-form-item>
  65. </a-col>
  66. <a-col :span="12">
  67. <a-form-item label="仓库(warehouse)" v-bind="validateInfos.warehouse" id="SaleOrderForm-warehouse" name="warehouse">
  68. <JDictSelectTag v-model:value="formData.warehouse" placeholder="请选择" dictCode="warehouse" />
  69. </a-form-item>
  70. </a-col>
  71. <a-col :span="12">
  72. <a-form-item label="发货通知单号(sourceCode)" v-bind="validateInfos.sourceCode" id="SaleOrderForm-sourceCode" name="sourceCode">
  73. <a-input v-model:value="formData.sourceCode" placeholder="请输入" disabled allow-clear />
  74. </a-form-item>
  75. </a-col>
  76. <a-col :span="12">
  77. <a-form-item label="备注(notes)" v-bind="validateInfos.notes" id="SaleOrderForm-notes" name="notes">
  78. <a-input v-model:value="formData.notes" AutoComplete="off" />
  79. </a-form-item>
  80. </a-col>
  81. </a-row>
  82. </a-form>
  83. </template>
  84. </JFormContainer>
  85. <!-- 子表单区域 -->
  86. <a-tabs v-model:activeKey="activeKey" animated style="padding: 24px; padding-top: 0px">
  87. <a-tab-pane tab="销售出库 - 出库明细(stock out details)" key="stockOut" :forceRender="true">
  88. <a-button type="primary" style="margin-right: 1%; margin-bottom: 1%" @click="selectDelivery" :disabled="disabled||notAllowEdit" >选择发货单(select delivery)</a-button>
  89. <j-vxe-table
  90. :keep-source="true"
  91. resizable
  92. ref="stockOutTableRef"
  93. :loading="stockOutTable.loading"
  94. :columns="stockOutTable.columns"
  95. :dataSource="stockOutTable.dataSource"
  96. :maxHeight="340"
  97. :disabled="disabled"
  98. :rowNumber="true"
  99. :rowSelection="true"
  100. asyncRemove
  101. >
  102. <template #action="props">
  103. <a-popconfirm title="确定删除吗?" @confirm="handleDelete(props)" v-if="!disabled">
  104. <a>删除(delete)</a>
  105. </a-popconfirm>
  106. <!-- 逻辑不通暂时取消次功能 -->
  107. <!-- <a>复制(copy)</a> -->
  108. </template>
  109. <template #inventorySelection="props">
  110. <a-input-search v-model:value="props.row.inventorySelection" allow-clear enter-button="Search" @search="onSearchInventory(props)" />
  111. </template>
  112. </j-vxe-table>
  113. </a-tab-pane>
  114. <a-tab-pane tab="销售出库 - 船明细(ship details)" key="saleShip" :forceRender="true">
  115. <j-vxe-table
  116. :keep-source="true"
  117. resizable
  118. ref="saleShipTableRef"
  119. :loading="saleShipTable.loading"
  120. :columns="saleShipTable.columns"
  121. :dataSource="saleShipTable.dataSource"
  122. :maxHeight="340"
  123. :disabled="disabled"
  124. :rowNumber="true"
  125. :rowSelection="true"
  126. >
  127. <template #action="props">
  128. <a @click="viewAccessory(props)">查看配件信息(view accessory information)</a>
  129. </template>
  130. </j-vxe-table>
  131. </a-tab-pane>
  132. </a-tabs>
  133. <BaseShipArchiveAccessoriesModal ref="BaseShipArchiveAccessoriesModalRef" />
  134. <SelectDeliveryModal ref="SelectDeliveryModalRef" @select-delivery="getDeliveryList" />
  135. <SelectStaningStockModal ref="SelectStaningStockModalRef" @select-staning-stock="editDetailRow" />
  136. <SelectProjectModal ref="SelectProjectModalRef" @select-project="addProject" />
  137. </a-spin>
  138. </template>
  139. <script lang="ts">
  140. import { defineComponent, ref, reactive, computed, toRaw } from 'vue';
  141. import { defHttp } from '/@/utils/http/axios';
  142. import { useValidateAntFormAndTable } from '/@/hooks/system/useJvxeMethods';
  143. import { querySaleOutShipFormShip, querystockOutByMainId, queryDataById, saveOrUpdate,getDeitailFromDelivery } from '../salesOutboundForm.api';
  144. import { JVxeTable } from '/@/components/jeecg/JVxeTable';
  145. import { stockOutShipColumns, stockOutColumns } from '../salesOutboundForm.data';
  146. import BaseShipArchiveAccessoriesModal from '../../../publicComponents/BaseShipArchiveAccessoriesModal.vue';
  147. import SelectStaningStockModal from './SelectStaningStockModal.vue';
  148. import SelectProjectModal from '../../../publicComponents/SelectProjectModal.vue';
  149. import SelectDeliveryModal from './SelectDeliveryModal.vue';
  150. import JFormContainer from '/@/components/Form/src/container/JFormContainer.vue';
  151. import JUpload from '/@/components/Form/src/jeecg/components/JUpload/JUpload.vue';
  152. import { JDictSelectTag } from '/@/components/Form';
  153. import { Form, message } from 'ant-design-vue';
  154. import { useUserStore } from '/@/store/modules/user';
  155. import { initDictOptions } from '/@/utils/dict';
  156. import moment from 'moment';
  157. const useForm = Form.useForm;
  158. export default defineComponent({
  159. name: 'SalesOutForm',
  160. components: {
  161. JVxeTable,
  162. JFormContainer,
  163. JUpload,
  164. JDictSelectTag,
  165. BaseShipArchiveAccessoriesModal,
  166. SelectDeliveryModal,
  167. SelectStaningStockModal,
  168. SelectProjectModal
  169. },
  170. props: {
  171. formDisabled: {
  172. type: Boolean,
  173. default: false,
  174. },
  175. formData: { type: Object, default: () => {} },
  176. formBpm: { type: Boolean, default: true },
  177. },
  178. emits: ['success'],
  179. setup(props, { emit }) {
  180. const userStore = useUserStore();
  181. const loading = ref(false);
  182. const formRef = ref();
  183. var notAllowEdit = ref(false);
  184. const saleShipTableRef = ref();
  185. var SelectProjectModalRef = ref();
  186. const SelectStaningStockModalRef = ref();
  187. const BaseShipArchiveAccessoriesModalRef = ref();
  188. const saleShipTable = reactive<Record<string, any>>({
  189. loading: false,
  190. columns: stockOutShipColumns,
  191. dataSource: [],
  192. });
  193. const stockOutTableRef = ref();
  194. const stockOutTable = reactive<Record<string, any>>({
  195. loading: false,
  196. columns: stockOutColumns,
  197. dataSource: [],
  198. });
  199. const SelectDeliveryModalRef = ref();
  200. const activeKey = ref('stockOut');
  201. const formData = reactive<Record<string, any>>({
  202. id: '',
  203. status: undefined,
  204. delFlag: undefined,
  205. sourceCode: '',
  206. billCode: '',
  207. billDate: moment(new Date()).format('YYYY-MM-DD'),
  208. project: '',
  209. projectName: '',
  210. customer: '',
  211. customerName: '',
  212. saleDepartment: '',
  213. saleDepartmentName: '',
  214. productionClass: '',
  215. salesman: '',
  216. salesmanName: '',
  217. goodsAllocation: '',
  218. warehouse: '',
  219. notes: '',
  220. isExport: '',
  221. maker: '',
  222. model: '',
  223. });
  224. //表单验证
  225. const validatorRules = reactive({});
  226. const { resetFields, validate, validateInfos } = useForm(formData, validatorRules, { immediate: false });
  227. const dbData = {};
  228. const formItemLayout = {
  229. labelCol: { xs: { span: 24 }, sm: { span: 5 } },
  230. wrapperCol: { xs: { span: 24 }, sm: { span: 16 } },
  231. labelCol1: { xs: { span: 24 }, sm: { span: 7 } },
  232. wrapperCol1: { xs: { span: 24 }, sm: { span: 15 } },
  233. };
  234. // 表单禁用
  235. const disabled = computed(() => {
  236. if (props.formBpm === true) {
  237. if (props.formData.disabled === false) {
  238. return false;
  239. } else {
  240. return true;
  241. }
  242. }
  243. return props.formDisabled;
  244. });
  245. async function add() {
  246. resetFields();
  247. saleShipTable.dataSource = [];
  248. stockOutTable.dataSource = [];
  249. activeKey.value = 'stockOut';
  250. formData.salesman = userStore.getUserInfo.username;
  251. formData.salesmanName = userStore.getUserInfo.realname;
  252. formData.saleDepartment = userStore.getUserInfo.orgCode;
  253. formData.saleDepartmentName = userStore.getUserInfo.orgName;
  254. var warehouseArr = await initDictOptions('warehouse');
  255. var goodsAllocationArr = await initDictOptions('goods_allocation');
  256. formData.warehouse = warehouseArr[0].value;
  257. formData.goodsAllocation = goodsAllocationArr[0].value;
  258. notAllowEdit.value = false;
  259. }
  260. async function edit(row) {
  261. //主表数据
  262. await queryMainData(row.id);
  263. //子表数据
  264. const saleShipDataList = await querySaleOutShipFormShip(row['id']);
  265. saleShipTable.dataSource = [...saleShipDataList];
  266. const stockOutDataList = await querystockOutByMainId(row['id']);
  267. stockOutTable.dataSource = [...stockOutDataList];
  268. notAllowEdit.value = true;
  269. }
  270. async function queryMainData(id) {
  271. const row = await queryDataById(id);
  272. resetFields();
  273. const tmpData = {};
  274. Object.keys(formData).forEach((key) => {
  275. if (row.hasOwnProperty(key)) {
  276. tmpData[key] = row[key];
  277. }
  278. });
  279. //赋值
  280. Object.assign(formData, tmpData);
  281. }
  282. const { getSubFormAndTableData, transformData } = useValidateAntFormAndTable(activeKey, {
  283. storeSaleOutShip: saleShipTableRef,
  284. storeSaleOutDetails: stockOutTableRef,
  285. });
  286. async function getFormData() {
  287. try {
  288. // 触发表单验证
  289. await validate();
  290. } catch ({ errorFields }) {
  291. if (errorFields) {
  292. const firstField = errorFields[0];
  293. if (firstField) {
  294. formRef.value.scrollToField(firstField.name, { behavior: 'smooth', block: 'center' });
  295. }
  296. }
  297. return Promise.reject(errorFields);
  298. }
  299. return transformData(toRaw(formData));
  300. }
  301. async function submitForm() {
  302. if (formData.sourceCode == '') {
  303. message.error('请添加出库明细!');
  304. } else {
  305. stockOutTableRef.value!.validateTable().then(async (errMap) => {
  306. if (errMap) {
  307. console.log('表单验证未通过:', { errMap });
  308. } else {
  309. const mainData = await getFormData();
  310. const subData = await getSubFormAndTableData();
  311. const values = Object.assign({}, dbData, mainData, subData);
  312. console.log('表单提交数据', values);
  313. const isUpdate = values.id ? true : false;
  314. await saveOrUpdate(values, isUpdate);
  315. //关闭弹窗
  316. emit('success');
  317. }
  318. })
  319. }
  320. }
  321. function setFieldsValue(values) {
  322. if (values) {
  323. Object.keys(values).map((k) => {
  324. formData[k] = values[k];
  325. });
  326. }
  327. }
  328. function getShipList(id) {
  329. let params = { id: id };
  330. let url = '/saleCode/saleDelivery/querySaleDeliveryShipByMainId';
  331. defHttp.get({ url: url, params }, { isTransformResponse: false }).then((res) => {
  332. if (res) {
  333. saleShipTable.dataSource = res.result;
  334. }
  335. });
  336. }
  337. //查看配件信息
  338. function viewAccessory(prop) {
  339. BaseShipArchiveAccessoriesModalRef.value.getTable(prop.row);
  340. }
  341. //产品明细-删除行
  342. function handleDelete(prop) {
  343. var xTable = stockOutTableRef.value!.getXTable()
  344. var newArray = [...xTable.data];
  345. newArray.splice(prop.rowIndex, 1);
  346. stockOutTable.dataSource = newArray;
  347. if (stockOutTable.dataSource.length == 0) {
  348. formData.sourceCode = '';
  349. add();
  350. }
  351. }
  352. /**
  353. * 值改变事件触发-树控件回调
  354. * @param key
  355. * @param value
  356. */
  357. function handleFormChange(key, value) {
  358. formData[key] = value;
  359. }
  360. function selectDelivery() {
  361. SelectDeliveryModalRef.value.getTable(formData);
  362. }
  363. async function getDeliveryList(data) {
  364. var arr = await getDeitailFromDelivery({headId:data[0].id,pageSize:-1})
  365. if(arr.records.length!==0){
  366. arr.records.map((item) => {
  367. item.model = item.childModel;
  368. item.sourceId = item.childId;
  369. item.deliveryQuantity = item.quantity;
  370. item.stockOutQuantity = item.quantity;
  371. });
  372. notAllowEdit.value = true;
  373. stockOutTable.dataSource = arr.records;
  374. formData.sourceCode = arr.records[0].billCode;
  375. formData.project = arr.records[0].project;
  376. formData.projectName = arr.records[0].projectName;
  377. formData.customerName = arr.records[0].customerName;
  378. formData.customer = arr.records[0].customer;
  379. formData.productionClass = arr.records[0].productionClass;
  380. formData.model = arr.records[0].headModel;
  381. formData.maker = arr.records[0].maker;
  382. formData.isExport = arr.records[0].isExport;
  383. getShipList(arr.records[0].headId);
  384. }
  385. }
  386. function onSearchInventory(props) {
  387. if (
  388. formData.projectName == '' ||
  389. formData.customerName == '' ||
  390. formData.customerName == '' ||
  391. !props.row.productId ||
  392. props.row.productId == '' ||
  393. formData.warehouse == '' ||
  394. formData.goodsAllocation == ''
  395. ) {
  396. message.error('请先选择项目、客户、仓库、货位、产品编码!');
  397. } else {
  398. var obj = Object.assign({}, formData);
  399. obj.productCode = props.row.productCode;
  400. obj.identification = props.row.childId ? props.row.childId : props.row.sourceId;
  401. SelectStaningStockModalRef.value.getTable(obj);
  402. }
  403. }
  404. function editDetailRow(data, rowId) {
  405. var xTable = stockOutTableRef.value!.getXTable()
  406. var arr = [...xTable.data];
  407. arr.map((item) => {
  408. var id = item.childId ? item.childId : item.sourceId;
  409. if (id == rowId) {
  410. item.inventorySelection = data[0].batchCode;
  411. item.batchId = data[0].id;
  412. }
  413. });
  414. stockOutTable.dataSource = [...arr];
  415. }
  416. //选择项目
  417. function onSearchProject() {
  418. SelectProjectModalRef.value.getTable();
  419. }
  420. //选择项目
  421. function addProject(data) {
  422. if (data.length == 0) {
  423. formData.project = formData.projectName = '';
  424. } else {
  425. formData.project = data[0].id;
  426. formData.projectName = data[0].code;
  427. }
  428. }
  429. return {
  430. saleShipTableRef,
  431. saleShipTable,
  432. stockOutTableRef,
  433. stockOutTable,
  434. validatorRules,
  435. validateInfos,
  436. activeKey,
  437. loading,
  438. formData,
  439. setFieldsValue,
  440. handleFormChange,
  441. formItemLayout,
  442. disabled,
  443. getFormData,
  444. submitForm,
  445. add,
  446. edit,
  447. formRef,
  448. handleDelete,
  449. BaseShipArchiveAccessoriesModalRef,
  450. viewAccessory,
  451. SelectDeliveryModalRef,
  452. selectDelivery,
  453. getDeliveryList,
  454. onSearchInventory,
  455. SelectStaningStockModalRef,
  456. editDetailRow,
  457. notAllowEdit,
  458. onSearchProject,
  459. SelectProjectModalRef,
  460. addProject
  461. };
  462. },
  463. });
  464. </script>
  465. <style lang="less" scoped>
  466. /** 时间和数字输入框样式 */
  467. :deep(.ant-input-number) {
  468. width: 100%;
  469. }
  470. :deep(.ant-calendar-picker) {
  471. width: 100%;
  472. }
  473. /deep/.vxe-table--body-wrapper {
  474. height: 100% !important;
  475. }
  476. /deep/.ant-modal-body {
  477. padding: 24px !important;
  478. }
  479. /deep/.ant-form-item {
  480. margin-bottom: 8px !important;
  481. }
  482. /deep/.vxe-cell--valid-error-msg{
  483. color: white !important;
  484. background-color: white !important;
  485. }
  486. </style>