inStorage.vue 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361
  1. <template>
  2. <div class="p-4 bg-white">
  3. <el-button type="text" @click="goBack">返回</el-button>
  4. <!-- <h2 class="text-center my-4">发货管理</h2> -->
  5. <div class="text-center my-4">
  6. <!-- <Vue3Barcode v-if="barcodeValue" :value='barcodeValue' width="1" height='30'></Vue3Barcode> -->
  7. <!-- <p>RYKS_DDD-20240527-00201</p> -->
  8. </div>
  9. <el-form :model="goodsExchangeAddForm" ref="ruleFormRef" :rules="rules" label-width="auto"
  10. style="max-width: 600px">
  11. <el-form-item prop="warehouse_id" label="入库仓库" class="change-form-item">
  12. <el-select v-model="goodsExchangeAddForm.warehouse_id" clearable>
  13. <el-option v-for="item in warehouseList" :key="item.id" :label="item.name" :value="item.id" />
  14. </el-select>
  15. </el-form-item>
  16. <el-form-item label="类型" prop="type" class="change-form-item">
  17. <el-select v-model="goodsExchangeAddForm.type" filterable allow-create clearable default-first-option
  18. :disabled="goodsExchangeAddForm.type == 'SALE_AFTER' || goodsExchangeAddForm.type == 'HAIL_ENTRY'">
  19. <el-option v-for="item in typeList" :key="item.id" :label="item.label" :value="item.value"
  20. :disabled="item.value == 'TRANSFER_ENTRY' || item.value == 'HAIL_ENTRY' || item.value == 'SALE_AFTER'" />
  21. </el-select>
  22. </el-form-item>
  23. <el-form-item label="备注" prop="change_desc" class="change-form-item" style="width: 100%">
  24. <el-input style="flex: 1" v-model="goodsExchangeAddForm.memo" type="textarea"
  25. :autosize="{ minRows: 3, maxRows: 4 }" placeholder="请输入"></el-input>
  26. </el-form-item>
  27. <el-button type="primary" size="large" @click="scanCode">扫码入库</el-button>
  28. <el-table :data="goodsExchangeAddForm.product_list" style="width: 100%">
  29. <el-table-column prop="goods_vo.name" label="商品名称" />
  30. <el-table-column prop="product_vo.sku" label="SKU" />
  31. <el-table-column prop="num" label="入库数量" />
  32. <el-table-column prop="orderNum" label="待入库数量" />
  33. </el-table>
  34. </el-form>
  35. <el-dialog v-model="dialogVisible" :modal=false title="扫码入库" :close-on-click-modal="false" width="80%"
  36. :before-close="handleClose">
  37. <el-form :model="snCodeForm" label-width="auto" style="max-width: 600px">
  38. <el-form-item label="SKU">
  39. <el-input v-model="snCodeForm.bar_code" ref="inputRef" @keyup.enter="toSearch()" />
  40. </el-form-item>
  41. <el-form-item label="序列号">
  42. <el-input v-model="snCodeForm.sn_code" ref="snInputRef" @keyup.enter="toSnCode()" />
  43. </el-form-item>
  44. </el-form>
  45. <!-- <template #footer>
  46. <div class="dialog-footer">
  47. <el-button @click="dialogVisible = false"></el-button>
  48. <el-button type="primary" @click="dialogVisible = false">
  49. Confirm
  50. </el-button>
  51. </div>
  52. </template> -->
  53. </el-dialog>
  54. <div class="flex justify-center mt-4">
  55. <el-button type="primary" size="large" @click="save(ruleFormRef)">保存</el-button>
  56. <el-button type="primary" size="large" @click="getOrderNumber(ruleFormRef)">入库</el-button>
  57. <!-- <el-button type="primary" size="large" @click="ship">发货</el-button> -->
  58. </div>
  59. </div>
  60. </template>
  61. <script lang="ts" setup>
  62. import { ref, onMounted, watch, reactive, nextTick } from 'vue';
  63. import { useRouter, useRoute } from 'vue-router';
  64. import { orderApi, infoApi, dictionaryAPI, entryOutAPI } from '@/api/api'
  65. //引入
  66. import Vue3Barcode from 'vue3-barcode'
  67. //定义要生成条形码的值
  68. import { ElMessage, FormRules, FormInstance } from 'element-plus'
  69. const appointment_time = ref('')
  70. const defaultTime = new Date(2000, 1, 1, 12, 0, 0)
  71. let dialogVisible = ref(false)
  72. const tableData = ref([])
  73. let barcodeValue = ref('')
  74. const router = useRouter();
  75. const route = useRoute()
  76. const activeTab = ref('basic-info');
  77. const id = ref(route.params.id);
  78. const goodsExchangeAddForm: any = reactive({
  79. warehouse_id: '',
  80. type: '',
  81. memo: '',
  82. product_list: []
  83. })
  84. interface RuleForm {
  85. warehouse_id: string,
  86. type: string
  87. }
  88. const ruleFormRef = ref<FormInstance>()
  89. //校验表单
  90. const rules = reactive<FormRules<RuleForm>>({
  91. warehouse_id: [
  92. {
  93. required: true,
  94. message: 'Please select Activity zone',
  95. trigger: 'change',
  96. },
  97. ],
  98. type: [
  99. {
  100. required: true,
  101. message: 'Please select Activity count',
  102. trigger: 'change',
  103. },
  104. ],
  105. })
  106. //表单
  107. const snCodeForm = reactive({
  108. bar_code: "",
  109. sn_code: '',
  110. })
  111. const inputRef = ref<any>(null);
  112. const snInputRef = ref<any>(null)
  113. const customerList: any = ref([])//初始化客户列表
  114. const warehouseList: any = ref([])//初始化客户列表
  115. const collectingAccountList: any = ref([])//初始化客户列表
  116. const typeList: any = ref([])//初始化客户列表
  117. const orderTypeList: any = ref([])//初始化客户列表
  118. const index = ref(-1);
  119. let sku = ref('');
  120. watch(activeTab, (newValue, oldValue) => {
  121. console.log(`Tab changed from ${oldValue} to ${newValue}`);
  122. // 这里可以添加一些逻辑,但要确保不会再次修改 activeTab
  123. });
  124. /* 扫sku */
  125. const toSearch = async () => {
  126. activeTab.value = 'product-info'
  127. try {
  128. const res: any = await orderApi.getProduct(
  129. goodsExchangeAddForm.warehouse_id,
  130. snCodeForm.bar_code.replace(/\s+/g, '')
  131. );
  132. res.data.sn_code_list = [];
  133. sku.value = res.data.product_vo.sku;
  134. // 查找当前商品是否已存在于列表中
  135. const indexs = goodsExchangeAddForm.product_list.findIndex(
  136. (el) => {
  137. console.log("Comparing with:", el);
  138. return (
  139. el.goods_vo.id === res.data.goods_id &&
  140. el.product_id === res.data.product_id &&
  141. el.product_vo.sku === res.data.product_vo.sku
  142. );
  143. }
  144. );
  145. // 如果商品不存在,则添加到列表
  146. if (indexs === -1) {
  147. index.value = goodsExchangeAddForm.product_list.length;
  148. goodsExchangeAddForm.product_list.push(res.data);
  149. console.log(goodsExchangeAddForm.product_list);
  150. } else {
  151. index.value = indexs;
  152. }
  153. if (res.data.product_vo.have_sn) {
  154. nextTick(() => {
  155. snInputRef.value.focus();
  156. });
  157. } else {
  158. /* this.scanDialogVisible = false; */
  159. }
  160. } catch (error) {
  161. console.error('Error fetching product:', error);
  162. }
  163. };
  164. //扫描序列号
  165. const toSnCode = async () => {
  166. try {
  167. const res: any = await orderApi.getsnCode(
  168. "in",
  169. sku.value,
  170. snCodeForm.sn_code.replace(/\s+/g, '')
  171. );
  172. snCodeForm.sn_code = "";
  173. const exists = goodsExchangeAddForm.product_list[index.value].sn_code_list.find(
  174. item => item.sn_code === res.sn_code && item.sku === res.sku
  175. );
  176. if (!exists) {
  177. goodsExchangeAddForm.product_list[index.value].sn_code_list.push(res.data);
  178. }
  179. goodsExchangeAddForm.product_list[index.value].num = goodsExchangeAddForm.product_list[index.value].sn_code_list.length;
  180. snCodeForm.bar_code = "";
  181. nextTick(() => {
  182. inputRef.value.focus();
  183. });
  184. } catch (error) {
  185. console.error('Error fetching SN code:', error);
  186. }
  187. }
  188. //关闭弹窗
  189. const handleClose = (done: () => void) => {
  190. done()
  191. }
  192. onMounted(async () => {
  193. await getInforList();
  194. init();
  195. });
  196. const goBack = () => {
  197. router.push({ name: 'InoutStorage' });
  198. };
  199. const scanCode = () => {
  200. dialogVisible.value = true
  201. nextTick(() => {
  202. if (inputRef.value) {
  203. try {
  204. inputRef.value.focus(); // 先尝试聚焦 input 元素
  205. setTimeout(() => {
  206. if (inputRef.value) {
  207. inputRef.value.select();
  208. }
  209. }, 100);
  210. } catch (error) {
  211. console.error('Failed to select input:', error);
  212. }
  213. }
  214. });
  215. };
  216. //入库
  217. const getOrderNumber = async (formEl: FormInstance | undefined) => {
  218. if (!formEl) return
  219. await formEl.validate((valid, fields) => {
  220. if (valid) {
  221. if (!goodsExchangeAddForm.product_list.length) {
  222. ElMessage.error("请选择商品!");
  223. return;
  224. }
  225. goodsExchangeAddForm.save_or_submit = "submit"
  226. goodsExchangeAddForm.product_list.map((el) => {
  227. el.product_stock_id = el.id;
  228. el.product_id = el.product_vo.id;
  229. el.id = "";
  230. });
  231. entryOutAPI.addWarehouseEntry(id.value,goodsExchangeAddForm).then(res => {
  232. ElMessage.success("入库成功!");
  233. router.replace({
  234. name: 'InoutStorage',
  235. });
  236. })
  237. } else {
  238. console.log('error submit!', fields)
  239. }
  240. })
  241. };
  242. //保存
  243. const save = async (formEl: FormInstance | undefined) => {
  244. if (!formEl) return
  245. await formEl.validate((valid, fields) => {
  246. if (valid) {
  247. if (!goodsExchangeAddForm.product_list.length) {
  248. ElMessage.error("请选择商品!");
  249. return;
  250. }
  251. goodsExchangeAddForm.save_or_submit = "save"
  252. goodsExchangeAddForm.product_list.map((el) => {
  253. el.product_stock_id = el.id;
  254. el.product_id = el.product_vo.id;
  255. el.id = "";
  256. });
  257. entryOutAPI.addWarehouseEntry(id.value,goodsExchangeAddForm).then(res => {
  258. ElMessage.success("保存成功!");
  259. router.replace({
  260. name: 'InoutStorage',
  261. });
  262. })
  263. } else {
  264. console.log('error submit!', fields)
  265. }
  266. })
  267. };
  268. const ship = () => {
  269. console.log('发货');
  270. };
  271. const init = async () => {
  272. try {
  273. const res: any = await entryOutAPI.warehouseEntry(id.value);
  274. res.data.product_list.map(el => {
  275. el.orderNum = el.num
  276. el.num=0
  277. el.sn_code_list = []
  278. })
  279. goodsExchangeAddForm.warehouse_id = res.data.warehouse_id;
  280. goodsExchangeAddForm.type = res.data.type;
  281. goodsExchangeAddForm.memo = res.data.memo;
  282. goodsExchangeAddForm.product_list = res.data.product_list;
  283. console.log(goodsExchangeAddForm);
  284. } catch (error) {
  285. console.error("Failed to fetch order details:", error);
  286. }
  287. }
  288. /* 处理客户名称 */
  289. const customerName = (value) => {
  290. if (value && customerList.value && customerList.value.data && customerList.value.data.data) {
  291. const type = customerList.value.data.data.find(type => type.id === value);
  292. return type ? type.name : '';
  293. }
  294. }
  295. /* 仓库名称 */
  296. const warehouseName = (value) => {
  297. if (value && warehouseList.value && warehouseList.value.data) {
  298. const type = warehouseList.value.data.find(type => type.id === value);
  299. return type ? type.name : '';
  300. }
  301. }
  302. /* 支付列表*/
  303. const collectingAccountName = (value) => {
  304. if (value && collectingAccountList.value && collectingAccountList.value.data && collectingAccountList.value.data.data) {
  305. const type = collectingAccountList.value.data.data.find(type => type.id === value);
  306. return type ? type.name : '';
  307. }
  308. }
  309. /* 配送方式*/
  310. const deliveryName = (value) => {
  311. if (value && typeList.value && typeList.value.data && typeList.value.data.data) {
  312. const type = typeList.value.data.data.find(type => type.value === value);
  313. return type ? type.label : '';
  314. }
  315. }
  316. /* 订单状态*/
  317. const orderTypeName = (value) => {
  318. if (value && orderTypeList.value && orderTypeList.value.data && orderTypeList.value.data.data) {
  319. const type = orderTypeList.value.data.data.find(type => type.value === value);
  320. return type ? type.label : '';
  321. }
  322. }
  323. /* 获取仓库,字典,客户信息 */
  324. const getInforList = async () => {
  325. const warehouseData: any = await infoApi.warehouseList({})//获取仓库列表
  326. warehouseList.value = warehouseData.data
  327. customerList.value = await infoApi.customer({})//获取客户列表
  328. collectingAccountList.value = await infoApi.collectingAccount({})//获取支付方式列表
  329. const typeData: any = await dictionaryAPI.getPage({ dictType: "warehouse_entry_type" })//获取配送方式
  330. typeList.value = typeData.data.data
  331. console.log(typeList.value);
  332. orderTypeList.value = await dictionaryAPI.getPage({ dictType: "Sale_order_send_status" })//获取订单状态
  333. }
  334. </script>
  335. <style scoped>
  336. .text-center {
  337. text-align: center;
  338. }
  339. .my-4 {
  340. margin-top: 1rem;
  341. margin-bottom: 1rem;
  342. }
  343. .mx-auto {
  344. margin-left: auto;
  345. margin-right: auto;
  346. }
  347. .p-4 {
  348. padding: 1rem;
  349. }
  350. </style>