addInventory.vue 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400
  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="goodsInventoryAddForm" ref="ruleFormRef" :rules="rules" label-width="auto"
  10. style="max-width: 600px">
  11. <el-form-item prop="inventory_time" label="盘点时间:" class="change-form-item">
  12. <el-date-picker v-model="goodsInventoryAddForm.inventory_time" style="width: 170px" size="small"
  13. type="datetime" placeholder="Select date and time" :default-time="defaultTime" />
  14. </el-form-item>
  15. <el-form-item prop="warehouse_id" label="仓库:" class="change-form-item">
  16. <span>{{ warehouseName(goodsInventoryAddForm.warehouse_id) }}</span>
  17. </el-form-item>
  18. <el-form-item label="盘点人:" prop="inventory_person_id" class="change-form-item">
  19. <span> {{ getadminList(goodsInventoryAddForm.inventory_person_id) }}</span>
  20. </el-form-item>
  21. <el-form-item label="制单人:" prop="creator_id" class="change-form-item">
  22. <span>{{ getadminList(goodsInventoryAddForm.creator_id) }}</span>
  23. </el-form-item>
  24. <el-form-item label="盘点类型:" prop="inventory_type" class="change-form-item">
  25. <span>{{ deliveryName(goodsInventoryAddForm.inventory_type) }}</span>
  26. </el-form-item>
  27. <el-button type="primary" size="large" @click="scanCode">商品扫码</el-button>
  28. <el-table :data="goodsInventoryAddForm.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="inventory_num" label="盘点数量">
  32. <template #default="scope">
  33. <span :style="{ color: scope.row.inventory_num > 0 ? 'red' : 'black' }">
  34. {{ scope.row.inventory_num }}
  35. </span>
  36. </template>
  37. </el-table-column>
  38. <el-table-column prop="actual_stock" label="库存数量">
  39. <!-- <template #default="scope">
  40. <span style="color: red;">{{ scope.actual_stock }}</span>
  41. </template> -->
  42. </el-table-column>
  43. </el-table>
  44. </el-form>
  45. <el-dialog v-model="dialogVisible" :modal=false title="商品扫码" :close-on-click-modal="false" top="80px"
  46. width="90%" style="height: 200px" :before-close="handleClose">
  47. <el-form :model="snCodeForm" label-width="auto" style="max-width: 600px">
  48. <el-form-item label="SKU">
  49. <el-input v-model="snCodeForm.bar_code" ref="inputRef" clearable :inputmode="inputmode" @keyup.enter="toSearch()" >
  50. <template #append> <img src="../../assets/images/JP.png" @click="getInfo" class="w-8 h-8" /> </template>
  51. </el-input>
  52. </el-form-item>
  53. <el-form-item label="序列号">
  54. <el-input v-model="snCodeForm.sn_code" ref="snInputRef" clearable :inputmode="inputmode"
  55. @keyup.enter="toSnCode()" />
  56. </el-form-item>
  57. </el-form>
  58. <!-- <template #footer>
  59. <div class="dialog-footer">
  60. <el-button @click="dialogVisible = false"></el-button>
  61. <el-button type="primary" @click="dialogVisible = false">
  62. Confirm
  63. </el-button>
  64. </div>
  65. </template> -->
  66. </el-dialog>
  67. <div class="flex justify-center mt-4">
  68. <el-button type="primary" size="large" @click="getOrderNumber(ruleFormRef)">保存</el-button>
  69. <!-- <el-button type="primary" size="large" @click="ship">发货</el-button> -->
  70. </div>
  71. </div>
  72. </template>
  73. <script lang="ts" setup>
  74. import { ref, onMounted, watch, reactive, nextTick } from 'vue';
  75. import { useRouter, useRoute } from 'vue-router';
  76. import { orderApi, infoApi, dictionaryAPI, inventoryAPI } from '@/api/api'
  77. //引入
  78. import Vue3Barcode from 'vue3-barcode'
  79. //定义要生成条形码的值
  80. import { ElMessage, FormRules, FormInstance } from 'element-plus'
  81. const appointment_time = ref('')
  82. const defaultTime = new Date()
  83. let dialogVisible = ref(false)
  84. const tableData = ref([])
  85. let inputmode = ref('text')
  86. let barcodeValue = ref('')
  87. const router = useRouter();
  88. const route = useRoute()
  89. const activeTab = ref('basic-info');
  90. const id = ref(route.params.id);
  91. const goodsInventoryAddForm: any = reactive({
  92. warehouse_id: '',
  93. inventory_person_id: '',
  94. product_list: [],
  95. creator_id: '',
  96. inventory_type: '',
  97. inventory_time: new Date(),
  98. })
  99. interface RuleForm {
  100. warehouse_id: string,
  101. type: string
  102. }
  103. const ruleFormRef = ref<FormInstance>()
  104. //校验表单
  105. const rules = reactive<FormRules<RuleForm>>({
  106. warehouse_id: [
  107. {
  108. required: true,
  109. message: 'Please select Activity zone',
  110. trigger: 'change',
  111. },
  112. ],
  113. type: [
  114. {
  115. required: true,
  116. message: 'Please select Activity count',
  117. trigger: 'change',
  118. },
  119. ],
  120. })
  121. //表单
  122. const snCodeForm = reactive({
  123. bar_code: "",
  124. sn_code: '',
  125. })
  126. const inputRef = ref<any>(null);
  127. const snInputRef = ref<any>(null)
  128. const customerList: any = ref([])//初始化客户列表
  129. const warehouseList: any = ref([])//初始化客户列表
  130. const collectingAccountList: any = ref([])//初始化客户列表
  131. const typeList: any = ref([])//初始化客户列表
  132. const orderTypeList: any = ref([])//初始化客户列表
  133. const index = ref(-1);
  134. let sku = ref('');
  135. const adminList: any = ref([])
  136. watch(activeTab, (newValue, oldValue) => {
  137. console.log(`Tab changed from ${oldValue} to ${newValue}`);
  138. // 这里可以添加一些逻辑,但要确保不会再次修改 activeTab
  139. });
  140. const getInfo = () => {
  141. if (inputmode.value == 'none') {
  142. inputmode.value = 'text'
  143. inputRef.value.focus();
  144. } else {
  145. inputmode.value = 'none'
  146. inputRef.value.focus();
  147. }
  148. }
  149. /* 扫sku */
  150. const toSearch = async () => {
  151. activeTab.value = 'product-info'
  152. try {
  153. const res: any = await orderApi.getProduct(
  154. goodsInventoryAddForm.warehouse_id,
  155. snCodeForm.bar_code.replace(/\s+/g, '')
  156. );
  157. res.data.sn_code_list = [];
  158. sku.value = res.data.product_vo.sku;
  159. // 查找当前商品是否已存在于列表中
  160. const indexs = goodsInventoryAddForm.product_list.findIndex(
  161. (el) => {
  162. console.log("Comparing with:", el);
  163. return (
  164. el.goods_vo.id === res.data.goods_id &&
  165. el.product_id === res.data.product_id &&
  166. el.product_vo.sku === res.data.product_vo.sku
  167. );
  168. }
  169. );
  170. // 如果商品不存在,则添加到列表
  171. if (indexs === -1) {
  172. index.value = goodsInventoryAddForm.product_list.length;
  173. goodsInventoryAddForm.product_list.push(res.data);
  174. } else {
  175. index.value = indexs;
  176. }
  177. if (res.data.product_vo.have_sn) {
  178. nextTick(() => {
  179. snInputRef.value.focus();
  180. });
  181. } else {
  182. /* this.scanDialogVisible = false; */
  183. }
  184. } catch (error) {
  185. goodsInventoryAddForm.product_list[index.value].inventory_num += 1
  186. console.error('Error fetching product:', error);
  187. }
  188. };
  189. //扫描序列号
  190. const toSnCode = async () => {
  191. if(!sku.value) return ElMessage.error('请先扫描sku!')
  192. try {
  193. const res: any = await orderApi.getsnCode(
  194. "inventory",
  195. sku.value,
  196. snCodeForm.sn_code.replace(/\s+/g, '')
  197. );
  198. snCodeForm.sn_code = "";
  199. const exists = goodsInventoryAddForm.product_list[index.value].sn_code_list.find(
  200. item => item.sn_code === res.sn_code && item.sku === res.sku
  201. );
  202. if (!exists) {
  203. await infoApi.skuRedis({ send_order_id: id.value, item_id: goodsInventoryAddForm.product_list[index.value].id, sku: res.data }).then((respons: any) => {
  204. goodsInventoryAddForm.product_list[index.value].sn_code_list.push(res.data);
  205. })
  206. }
  207. goodsInventoryAddForm.product_list[index.value].inventory_num = goodsInventoryAddForm.product_list[index.value].sn_code_list.length;
  208. snCodeForm.bar_code = "";
  209. nextTick(() => {
  210. inputRef.value.focus();
  211. });
  212. } catch (error) {
  213. console.error('Error fetching SN code:', error);
  214. }
  215. }
  216. //关闭弹窗
  217. const handleClose = (done: () => void) => {
  218. done()
  219. }
  220. onMounted(async () => {
  221. await getInforList();
  222. init();
  223. });
  224. const goBack = () => {
  225. router.push({ name: 'Inventory' });
  226. };
  227. const scanCode = () => {
  228. dialogVisible.value = true
  229. nextTick(() => {
  230. if (inputRef.value) {
  231. try {
  232. inputRef.value.focus(); // 先尝试聚焦 input 元素
  233. setTimeout(() => {
  234. if (inputRef.value) {
  235. inputRef.value.select();
  236. inputmode.value='none'
  237. }
  238. }, 100);
  239. } catch (error) {
  240. console.error('Failed to select input:', error);
  241. }
  242. }
  243. });
  244. };
  245. // 格式化日期时间为本地格式
  246. function formatDate(date) {
  247. const y = date.getFullYear();
  248. const m = date.getMonth() + 1; // 月份是从0开始的
  249. const d = date.getDate();
  250. const hr = date.getHours();
  251. const min = date.getMinutes();
  252. const sec = date.getSeconds();
  253. return `${y}-${pad(m)}-${pad(d)} ${pad(hr)}:${pad(min)}:${pad(sec)}`;
  254. }
  255. // 补零函数
  256. function pad(n) {
  257. return n < 10 ? '0' + n : n;
  258. }
  259. const getOrderNumber = async (formEl: FormInstance | undefined) => {
  260. if (!formEl) return
  261. await formEl.validate((valid, fields) => {
  262. if (valid) {
  263. if (!goodsInventoryAddForm.product_list.length) {
  264. ElMessage.error("请选择商品!");
  265. return;
  266. }
  267. goodsInventoryAddForm.product_list.map(el => {
  268. el.diff_num = el.usable_stock - el.inventory_num
  269. })
  270. goodsInventoryAddForm.inventory_time = formatDate(goodsInventoryAddForm.inventory_time)
  271. inventoryAPI.editInventory(id.value, goodsInventoryAddForm).then(res => {
  272. ElMessage.success("保存成功!");
  273. router.replace({
  274. name: 'Inventory',
  275. });
  276. })
  277. } else {
  278. console.log('error submit!', fields)
  279. }
  280. })
  281. };
  282. const ship = () => {
  283. console.log('发货');
  284. };
  285. const init = async () => {
  286. try {
  287. const res: any = await inventoryAPI.inventory(id.value);
  288. await infoApi.skuRedis({ send_order_id: id.value, type: 'enter' }).then((response: any) => {
  289. res.data.product_list.map(el => {
  290. Object.keys(response.data).map(item => {
  291. if (el.id == item) {
  292. el.sn_code_list = response.data[item]
  293. el.num = el.sn_code_list.length
  294. }
  295. })
  296. if (!el.sn_code_list) {
  297. el.sn_code_list = []
  298. }
  299. })
  300. })
  301. goodsInventoryAddForm.warehouse_id = res.data.warehouse_id;
  302. goodsInventoryAddForm.inventory_person_id = res.data.inventory_person_id;
  303. goodsInventoryAddForm.creator_id = res.data.creator_id;
  304. goodsInventoryAddForm.inventory_type = res.data.inventory_type;
  305. //goodsInventoryAddForm.inventory_time = res.data.inventory_time;
  306. goodsInventoryAddForm.type = res.data.type;
  307. goodsInventoryAddForm.product_list = res.data.product_list;
  308. console.log(goodsInventoryAddForm);
  309. } catch (error) {
  310. console.error("Failed to fetch order details:", error);
  311. }
  312. }
  313. /* 处理客户名称 */
  314. const customerName = (value) => {
  315. if (value && customerList.value && customerList.value.data && customerList.value.data.data) {
  316. const type = customerList.value.data.data.find(type => type.id === value);
  317. return type ? type.name : '';
  318. }
  319. }
  320. /* 仓库名称 */
  321. const warehouseName = (value) => {
  322. if (value && warehouseList.value) {
  323. const type = warehouseList.value.find(type => type.id === value);
  324. return type ? type.name : '';
  325. }
  326. }
  327. /* 支付列表*/
  328. const collectingAccountName = (value) => {
  329. if (value && collectingAccountList.value && collectingAccountList.value.data && collectingAccountList.value.data.data) {
  330. const type = collectingAccountList.value.data.data.find(type => type.id === value);
  331. return type ? type.name : '';
  332. }
  333. }
  334. /* 盘点类型*/
  335. const deliveryName = (value) => {
  336. if (value && typeList.value) {
  337. const type = typeList.value.find(type => type.id === value);
  338. return type ? type.label : '';
  339. }
  340. }
  341. /* 订单状态*/
  342. const orderTypeName = (value) => {
  343. if (value && orderTypeList.value && orderTypeList.value.data && orderTypeList.value.data.data) {
  344. const type = orderTypeList.value.data.data.find(type => type.value === value);
  345. return type ? type.label : '';
  346. }
  347. }
  348. const getadminList = (value) => {
  349. if (value && adminList.value && adminList.value.data && adminList.value.data.data) {
  350. // Access orderTypeList directly from the component's data
  351. const type = adminList.value.data.data.find(type => type.id === value);
  352. return type ? type.real_name : '未知类型';
  353. }
  354. }
  355. /* 获取仓库,字典,客户信息 */
  356. const getInforList = async () => {
  357. const warehouseData: any = await infoApi.warehouseList({})//获取仓库列表
  358. warehouseList.value = warehouseData.data
  359. customerList.value = await infoApi.customer({})//获取客户列表
  360. adminList.value = await infoApi.getAdmin({
  361. page_no: 1,
  362. page_size: 9999,
  363. user_state: 0
  364. })//获取管理员列表
  365. console.log(adminList);
  366. collectingAccountList.value = await infoApi.collectingAccount({})//获取支付方式列表
  367. const typeData: any = await dictionaryAPI.getPage({ dictType: "inventory_type" })//获取配送方式
  368. typeList.value = typeData.data.data
  369. orderTypeList.value = await dictionaryAPI.getPage({ dictType: "Sale_order_send_status" })//获取订单状态
  370. }
  371. </script>
  372. <style scoped>
  373. .text-center {
  374. text-align: center;
  375. }
  376. .my-4 {
  377. margin-top: 1rem;
  378. margin-bottom: 1rem;
  379. }
  380. .mx-auto {
  381. margin-left: auto;
  382. margin-right: auto;
  383. }
  384. .p-4 {
  385. padding: 1rem;
  386. }
  387. </style>