CheckEdit.vue 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572
  1. <script setup lang="tsx">
  2. import { onMounted, reactive, ref } from 'vue'
  3. import { ContentWrap } from '@/components/ContentWrap'
  4. import {
  5. ElInput,
  6. FormInstance,
  7. ElTabPane,
  8. ElTabs,
  9. ElForm,
  10. ElFormItem,
  11. ElMessage,
  12. ElSelect,
  13. ElOption,
  14. ElTableColumn,
  15. ElTable,
  16. ElDrawer,
  17. ElMessageBox} from 'element-plus'
  18. import { useRoute, useRouter } from 'vue-router'
  19. import {
  20. getStoreList,
  21. getStoreUser,
  22. getOutGood,
  23. getStoreGood,
  24. addCheck,
  25. addStoreCheck
  26. } from '@/api/erp'
  27. const pageTitle = ref('添加')
  28. const { params } = useRoute()
  29. const { push } = useRouter()
  30. const actinoTabIndex = ref(1)
  31. const selfBuild = reactive<{ [key: string]: any }>({
  32. type: 1,
  33. store_id: '',
  34. wid: '',
  35. create_admin_id: '',
  36. up_store_id: '',
  37. up_wid: '',
  38. product_list: [],
  39. rate: ''
  40. })
  41. const hzBuild = reactive<{ [key: string]: any }>({
  42. create_admin_id: '',
  43. store_id: '',
  44. up_store_id: '',
  45. product_list: [],
  46. type: 1,
  47. rate: ''
  48. })
  49. const rules = reactive({
  50. rate: [{ required: true, message: '请输入调价比例', trigger: 'change' }],
  51. create_admin_id: [{ required: true, message: '请选择创建人', trigger: 'change' }],
  52. wid: [{ required: true, message: '请选择仓库', trigger: 'change' }],
  53. store_id: [{ required: true, message: '请选择门店', trigger: 'change' }]
  54. })
  55. const formRef = ref<FormInstance>()
  56. const formRefs = ref<FormInstance>()
  57. const checkGoodss = ref<any[]>([])
  58. const goSuccess = () => {
  59. ElMessage.success('保存成功')
  60. ElMessageBox.confirm(`创建成功是否返回盘点列表`, '提示', {
  61. confirmButtonText: '返回列表',
  62. cancelButtonText: `继续创建`,
  63. type: 'warning'
  64. })
  65. .then(() => {
  66. backList()
  67. })
  68. .catch(() => {
  69. checkGoods.value = []
  70. checkGoodss.value = []
  71. })
  72. }
  73. /**
  74. * 保存表单数据
  75. * 此函数在用户提交表单时被触发,它首先验证表单数据的有效性,如果有效则处理数据并调用相应的API进行保存
  76. * @param {FormInstance | undefined} formEl - 表单实例,用于表单验证和获取表单数据
  77. * @returns {Promise<Array>} - 返回一个空数组,当前函数没有实际返回值,但为了保持接口一致性,返回了空数组
  78. */
  79. const save = async (formEl: FormInstance | undefined) => {
  80. // 检查表单实例是否存在,如果不存在则返回空数组
  81. if (!formEl) return []
  82. // 验证表单数据,如果验证失败,则显示错误消息并中断保存流程
  83. const valid = await formEl.validate((valid, fields) => {
  84. if (valid) {
  85. } else {
  86. for (const key in fields) {
  87. ElMessage.error(fields[key][0].message)
  88. return
  89. }
  90. console.log('error submit!', fields)
  91. }
  92. })
  93. if (valid) {
  94. let good: any[] = []
  95. let ok = true
  96. if (actinoTabIndex.value == 1) {
  97. checkGoods.value.forEach((item) => {
  98. if (!item.new_stock) {
  99. ok = false
  100. }
  101. if (actinoTabIndex.value == 2) {
  102. item.product_name = item.store_name
  103. item.suk = item.specs[0].name
  104. }
  105. good.push(item)
  106. })
  107. } else {
  108. checkGoodss.value.forEach((item) => {
  109. if (!item.new_stock) {
  110. ok = false
  111. }
  112. good.push(item)
  113. })
  114. }
  115. if (!ok) {
  116. return ElMessage.error('请输入实盘数量')
  117. }
  118. let res:any;
  119. if (actinoTabIndex.value == 1) {
  120. res = await addCheck({
  121. body: good,
  122. create_admin_id:selfBuild.create_admin_id,
  123. wid: selfBuild.wid
  124. })
  125. } else {
  126. res = await addStoreCheck(0,{
  127. body: good,
  128. create_admin_id: hzBuild.create_admin_id,
  129. store_id:hzBuild.store_id
  130. })
  131. }
  132. if (res?.status == 200) {
  133. goSuccess()
  134. }
  135. }
  136. }
  137. const loadingData = ref(false)
  138. onMounted(async () => {
  139. if (params.type == 'add') {
  140. pageTitle.value = '添加盘点'
  141. } else if (params.type == 'edit') {
  142. pageTitle.value = '编辑盘点'
  143. }
  144. })
  145. const backList = () => {
  146. push('/erp/check')
  147. }
  148. const storeLoading = ref(false)
  149. const storeOptions = ref<any[]>([])
  150. const getStore = async (query = '', id = '') => {
  151. try {
  152. storeLoading.value = true
  153. const res = await getStoreList({ page: 1, limit: 1000, name: query, id, store: 1 })
  154. if (res) {
  155. storeOptions.value = res.data.data.map((item) => {
  156. return {
  157. value: item.id,
  158. label: item.name
  159. }
  160. })
  161. } else {
  162. return []
  163. }
  164. } catch (error) {
  165. console.log(error)
  166. } finally {
  167. storeLoading.value = false
  168. }
  169. }
  170. const widOptions = ref<any[]>([])
  171. const adminOptions = ref<any[]>([])
  172. const wareLoading = ref(false)
  173. const adminLoading = ref(false)
  174. const checkGoods = ref<any[]>([])
  175. const getWid = async (query = '', id = '') => {
  176. try {
  177. wareLoading.value = true
  178. const res = await getStoreList({ page: 1, limit: 1000, name: query, id, type: 3 })
  179. if (res) {
  180. widOptions.value = res.data.data.map((item) => {
  181. return {
  182. value: item.id,
  183. label: item.name
  184. }
  185. })
  186. } else {
  187. return []
  188. }
  189. } catch (error) {
  190. console.log(error)
  191. } finally {
  192. wareLoading.value = false
  193. }
  194. }
  195. const getAdmin = async () => {
  196. console.log(actinoTabIndex.value, 'actinoTabIndex')
  197. let id: any = 0
  198. if (actinoTabIndex.value == 1) {
  199. id = selfBuild.wid
  200. } else if (actinoTabIndex.value == 2) {
  201. id = hzBuild.store_id
  202. }
  203. const res = await getStoreUser({ page: 1, limit: 20, relation_id: id })
  204. // adminOptions.value = res.data.list
  205. if (res) {
  206. adminOptions.value = res.data.map((item) => {
  207. return {
  208. value: item.id,
  209. label: item.real_name
  210. }
  211. })
  212. } else {
  213. return []
  214. }
  215. }
  216. const fristCheck = ref<any[]>([])
  217. const changeSw = () => {
  218. selfBuild.create_admin_id = ''
  219. checkGoods.value = []
  220. checkGoodss.value = []
  221. hzBuild.create_admin_id = ''
  222. }
  223. const handleSelectionChange = (e) => {
  224. fristCheck.value = e
  225. }
  226. const handleCurrentChange = (e: number) => {
  227. getPurgood(e, '')
  228. }
  229. const cancelClick = () => {
  230. dialogVisible.value = false
  231. }
  232. const unique = (arr) => {
  233. return arr.filter((item, index, arr) => arr.findIndex((t) => t.id === item.id) === index)
  234. }
  235. type iitem = {
  236. [key: string]: any
  237. }
  238. const confirmClick = () => {
  239. // 关闭弹窗
  240. dialogVisible.value = false
  241. //合并选中去重
  242. fristCheck.value = fristCheck.value.map((item: iitem) => {
  243. if (actinoTabIndex.value == 1) {
  244. item.new_stock = ''
  245. } else {
  246. item.new_stock = ''
  247. }
  248. console.log(item)
  249. return item
  250. })
  251. if (actinoTabIndex.value == 1) {
  252. checkGoods.value = unique(checkGoods.value.concat(fristCheck.value))
  253. } else if (actinoTabIndex.value == 2) {
  254. checkGoodss.value = unique(checkGoodss.value.concat(fristCheck.value))
  255. }
  256. }
  257. const goods = ref([])
  258. const count = ref(0)
  259. const keyword = ref('')
  260. const currentPage = ref(0)
  261. const pageSize = ref(10)
  262. const dialogVisible = ref(false)
  263. const getPurgood = async (page = 1, key = '') => {
  264. if (key == 're') {
  265. keyword.value = ''
  266. }
  267. let qData: {
  268. key: string
  269. page: number
  270. limit: number
  271. store_id?: any
  272. wid?: any
  273. type: any
  274. up_wid?: any
  275. } = {
  276. type: '',
  277. store_id: '',
  278. wid: '',
  279. key: keyword.value,
  280. page: page,
  281. limit: 10,
  282. up_wid: ''
  283. }
  284. if (actinoTabIndex.value == 1) {
  285. if (!selfBuild.wid) {
  286. return ElMessage.error('请选仓库')
  287. }
  288. qData.up_wid = selfBuild.wid
  289. qData.type = 0
  290. const res = await getOutGood(qData)
  291. goods.value = res.data.data
  292. count.value = res.data.count
  293. dialogVisible.value = true
  294. } else if (actinoTabIndex.value == 2) {
  295. if (!hzBuild.store_id) {
  296. return ElMessage.error('请选门店')
  297. }
  298. qData.store_id = hzBuild.store_id
  299. // const res = await getProduct(qData)
  300. const res = await getStoreGood(qData)
  301. goods.value = res.data.data
  302. count.value = res.data.count
  303. dialogVisible.value = true
  304. }
  305. }
  306. const delCheckGoods = (row) => {
  307. console.log(row)
  308. let set1 = new Set(checkGoods.value)
  309. let set2 = new Set([row])
  310. checkGoods.value = Array.from(set1.difference(set2))
  311. }
  312. const delCheckGoodss = (row) => {
  313. console.log(row)
  314. let set1 = new Set(checkGoodss.value)
  315. let set2 = new Set([row])
  316. checkGoodss.value = Array.from(set1.difference(set2))
  317. }
  318. </script>
  319. <template>
  320. <ContentWrap
  321. :title="pageTitle"
  322. class="!min-h-[calc(100vh-var(--top-tool-height)-var(--tags-view-height)-var(--app-footer-height)-var(--app-content-padding))]"
  323. >
  324. <template #header>
  325. <BaseButton size="small" @click="backList"> 返回列表 </BaseButton>
  326. </template>
  327. <ElTabs v-model="actinoTabIndex" type="border-card">
  328. <ElTabPane label="仓库盘点" :name="1">
  329. <ElForm
  330. v-loading="loadingData"
  331. ref="formRef"
  332. :model="selfBuild"
  333. :rules="rules"
  334. label-width="100px"
  335. >
  336. <ElFormItem label="仓库" prop="wid">
  337. <ElSelect
  338. filterable
  339. remote
  340. reserve-keyword
  341. v-model="selfBuild.wid"
  342. :remote-method="getWid"
  343. :loading="wareLoading"
  344. remote-show-suffix
  345. placeholder="请选择仓库"
  346. @change="changeSw"
  347. >
  348. <ElOption
  349. v-for="item in widOptions"
  350. :key="item.value"
  351. :label="item.label"
  352. :value="item.value"
  353. />
  354. </ElSelect>
  355. </ElFormItem>
  356. <ElFormItem label="比例" v-if="selfBuild.type == 0" prop="rate">
  357. <ElInput type="number" v-model="selfBuild.rate" />
  358. </ElFormItem>
  359. <ElFormItem label="创建人员" prop="create_admin_id" v-if="selfBuild.wid">
  360. <ElSelect
  361. filterable
  362. remote
  363. reserve-keyword
  364. :disabled="params.type == 'edit'"
  365. v-model="selfBuild.create_admin_id"
  366. :remote-method="getAdmin"
  367. :loading="adminLoading"
  368. remote-show-suffix
  369. placeholder="请选择创建人员"
  370. >
  371. <ElOption
  372. v-for="item in adminOptions"
  373. :key="item.value"
  374. :label="item.label"
  375. :value="item.value"
  376. />
  377. </ElSelect>
  378. </ElFormItem>
  379. <ElFormItem label="商品">
  380. <BaseButton type="primary" style="margin-bottom: 20px" @click="getPurgood(1, '')">
  381. 选择商品
  382. </BaseButton>
  383. <ElTable
  384. header-cell-class-name="bg-gray-100!"
  385. :data="checkGoods"
  386. class="w-100%"
  387. :border="true"
  388. stripe
  389. >
  390. <ElTableColumn prop="product_id" label="ID"> </ElTableColumn>
  391. <ElTableColumn prop="product_name" label="名称"> </ElTableColumn>
  392. <ElTableColumn prop="suk" label="单位"></ElTableColumn>
  393. <ElTableColumn prop="stock" label="库存">
  394. <template #default="{ row }">
  395. {{ row.is_weigh == 1 ? row.net_weight : row.product_num }}
  396. </template>
  397. </ElTableColumn>
  398. <ElTableColumn prop="new_stock" label="实盘">
  399. <template #header> <span>实盘</span><span class="text-red">*</span> </template>
  400. <template #default="{ row }">
  401. <ElInput type="number" v-model="row.new_stock" />
  402. </template>
  403. </ElTableColumn>
  404. <ElTableColumn prop="action" label="操作">
  405. <template #default="{ row }">
  406. <!-- <div type="text">{{ row.specs.num || 0 }}</div> -->
  407. <BaseButton link size="small" type="primary" @click="delCheckGoods(row)"
  408. >删除</BaseButton
  409. >
  410. </template></ElTableColumn
  411. >
  412. </ElTable>
  413. </ElFormItem>
  414. </ElForm>
  415. </ElTabPane>
  416. <ElTabPane label="门店盘点" :name="2">
  417. <ElForm
  418. v-loading="loadingData"
  419. ref="formRefs"
  420. :model="hzBuild"
  421. :rules="rules"
  422. label-width="100px"
  423. >
  424. <ElFormItem label="门店" prop="store_id">
  425. <ElSelect
  426. filterable
  427. remote
  428. reserve-keyword
  429. :disabled="params.type == 'edit'"
  430. v-model="hzBuild.store_id"
  431. :remote-method="getStore"
  432. :loading="storeLoading"
  433. remote-show-suffix
  434. placeholder="请选择门店"
  435. @change="changeSw"
  436. >
  437. <ElOption
  438. v-for="item in storeOptions"
  439. :key="item.value"
  440. :label="item.label"
  441. :value="item.value"
  442. />
  443. </ElSelect>
  444. </ElFormItem>
  445. <ElFormItem label="比例" v-if="hzBuild.type == 0" prop="rate">
  446. <ElInput type="number" v-model="hzBuild.rate" />
  447. </ElFormItem>
  448. <ElFormItem label="创建人员" prop="create_admin_id" v-if="hzBuild.store_id">
  449. <ElSelect
  450. filterable
  451. remote
  452. reserve-keyword
  453. :disabled="params.type == 'edit'"
  454. v-model="hzBuild.create_admin_id"
  455. :remote-method="getAdmin"
  456. :loading="adminLoading"
  457. remote-show-suffix
  458. placeholder="请选择创建人员"
  459. >
  460. <ElOption
  461. v-for="item in adminOptions"
  462. :key="item.value"
  463. :label="item.label"
  464. :value="item.value"
  465. />
  466. </ElSelect>
  467. </ElFormItem>
  468. <ElFormItem label="商品">
  469. <BaseButton type="primary" style="margin-bottom: 20px" @click="getPurgood(1, '')">
  470. 选择商品
  471. </BaseButton>
  472. <ElTable
  473. header-cell-class-name="bg-gray-100!"
  474. :data="checkGoodss"
  475. class="w-100%"
  476. :border="true"
  477. stripe
  478. >
  479. <ElTableColumn prop="id" label="ID"> </ElTableColumn>
  480. <ElTableColumn prop="store_name" label="名称"> </ElTableColumn>
  481. <ElTableColumn prop="specs[0].name" label="单位"></ElTableColumn>
  482. <ElTableColumn prop="stock" label="库存"></ElTableColumn>
  483. <ElTableColumn prop="new_stock" label="实盘">
  484. <template #header> <span>实盘</span><span class="text-red">*</span> </template>
  485. <template #default="{ row }">
  486. <ElInput type="number" v-model="row.new_stock" />
  487. </template>
  488. </ElTableColumn>
  489. <ElTableColumn prop="action" label="操作">
  490. <template #default="{ row }">
  491. <BaseButton link size="small" type="primary" @click="delCheckGoodss(row)"
  492. >删除</BaseButton
  493. >
  494. </template></ElTableColumn
  495. >
  496. </ElTable>
  497. </ElFormItem>
  498. </ElForm>
  499. </ElTabPane>
  500. </ElTabs>
  501. <ElDrawer v-model="dialogVisible" title="选择商品" size="700px">
  502. <div class="mb5">
  503. <ElInput v-model="keyword" style="width: 200px" placeholder="输入商品名称搜索" />
  504. <BaseButton type="primary" class="ml2" @click="getPurgood(1, '')"> 搜索 </BaseButton>
  505. <BaseButton @click="getPurgood(1, 're')"> 重置 </BaseButton>
  506. </div>
  507. <ElTable
  508. header-cell-class-name="bg-gray-100!"
  509. :data="goods"
  510. class="w-100%"
  511. :border="true"
  512. stripe
  513. @selection-change="handleSelectionChange"
  514. >
  515. <template v-if="actinoTabIndex == 1">
  516. <ElTableColumn type="selection" width="55" />
  517. <ElTableColumn prop="product_name" label="名称"> </ElTableColumn>
  518. <ElTableColumn prop="suk" label="单位"></ElTableColumn>
  519. <ElTableColumn prop="product_num" label="库存">
  520. <template #default="{ row }">
  521. {{ row.is_weigh == 1 ? row.net_weight : row.product_num }}
  522. </template>
  523. </ElTableColumn>
  524. </template>
  525. <template v-if="actinoTabIndex == 2">
  526. <ElTableColumn type="selection" width="55" />
  527. <ElTableColumn prop="store_name" label="名称"> </ElTableColumn>
  528. <ElTableColumn prop="specs[0].name" label="单位"></ElTableColumn>
  529. <ElTableColumn prop="stock" label="库存"></ElTableColumn>
  530. </template>
  531. </ElTable>
  532. <div style="height: 20px"></div>
  533. <ElPagination
  534. v-model:current-page="currentPage"
  535. v-model:page-size="pageSize"
  536. :page-sizes="[2, 3, 4, 5]"
  537. layout="total, prev, pager, next, jumper"
  538. :total="count"
  539. @current-change="handleCurrentChange"
  540. />
  541. <template #footer>
  542. <div style="flex: auto">
  543. <BaseButton @click="cancelClick">取消</BaseButton>
  544. <BaseButton type="primary" @click="confirmClick">确认</BaseButton>
  545. </div>
  546. </template>
  547. </ElDrawer>
  548. </ContentWrap>
  549. <div
  550. class="text-center border-t-1px border-solid border-gray-200 py-10px mt-10px position-sticky bottom-0 left-0 right-0 bg-white"
  551. >
  552. <BaseButton v-if="params.type == 'add' && actinoTabIndex == 1" @click="save(formRef)">
  553. 保存</BaseButton
  554. >
  555. <BaseButton v-if="params.type == 'add' && actinoTabIndex == 2" @click="save(formRefs)">
  556. 保存</BaseButton
  557. >
  558. </div>
  559. </template>