InventoryStatistics.vue 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402
  1. <script setup lang="ts">
  2. import {
  3. Storehouse_Stock_List,
  4. Storehouse_Depot_List,
  5. Storehouse_ProductClass_List,
  6. Storehouse_Product_Model_List,
  7. Storehouse_Product_Name_List,
  8. Storehouse_Stock_Detail_List,
  9. Storehouse_Stock_Detail_Excel
  10. } from '@/api/storehouse/index'
  11. import { ref, reactive, onMounted } from 'vue'
  12. import { List } from '@element-plus/icons-vue'
  13. import Drawer from '@/components/Drawer/index.vue'
  14. import { GlobalStore } from '@/stores/index'
  15. import TableBase from '@/components/TableBase/index.vue'
  16. import type { ColumnProps } from '@/components/TableBase/interface/index'
  17. import { dayJs } from '@/utils/common'
  18. import ImageCom from '@/components/Image/index.vue'
  19. import { useTablePublic } from '@/hooks/useTablePublic'
  20. const userInfo = ref({
  21. Id: '',
  22. T_name: ''
  23. })
  24. const loading = ref(false)
  25. const globalStore = GlobalStore()
  26. const DrawerRef = ref<InstanceType<typeof Drawer> | null>(null)
  27. const TableRef = ref<InstanceType<typeof TableBase> | null>(null)
  28. const TableDetailRef = ref<InstanceType<typeof TableBase> | null>(null)
  29. const { tableRowClassName } = useTablePublic()
  30. const tableRowClassNameHandle = (data: any): any => tableRowClassName(data.row.Id, userInfo.value.Id)
  31. const initParam = reactive({
  32. User_tokey: globalStore.GET_User_tokey,
  33. T_depot_id: '',
  34. T_product_class: '',
  35. T_product_name: '',
  36. T_product_model: ''
  37. })
  38. const detailInitParam = reactive({
  39. T_depot_id: '',
  40. T_product_id: '',
  41. T_start_date: '',
  42. T_end_date: ''
  43. })
  44. const columns: ColumnProps[] = [
  45. { type: 'index', label: '序号', width: 80 },
  46. { prop: 'T_depot_name', label: '仓库名称' },
  47. { prop: 'T_product_img', label: '产品图片', name: 'T_product_img' },
  48. { prop: 'T_product_name', label: '产品名称' },
  49. { prop: 'T_product_class_name', label: '产品分类' },
  50. { prop: 'T_product_model', label: '产品型号', ellipsis: true },
  51. { prop: 'T_product_spec', label: '产品规格' },
  52. { prop: 'T_total', label: '库存数量' },
  53. { prop: 'operation', label: '操作', width: 80, fixed: 'right' }
  54. ]
  55. const detailColumns: ColumnProps[] = [
  56. { type: 'index', label: '序号', width: 80 },
  57. { prop: 'T_product_name', label: '产品名称' },
  58. { prop: 'T_product_model', label: '产品型号', ellipsis: true },
  59. { prop: 'T_product_spec', label: '产品规格' },
  60. { prop: 'T_month', label: '月份' },
  61. { prop: 'T_beginning', label: '期初库存' },
  62. { prop: 'T_in', label: '入库' },
  63. { prop: 'T_out', label: '出库' },
  64. { prop: 'T_ending', label: '期末库存' }
  65. ]
  66. const searchHandle = () => {
  67. TableRef.value?.searchTable()
  68. }
  69. const dataCallback = (res: any) => {
  70. return res.Data.Data.map((item: any) => {
  71. if (item.T_depot_id === userInfo.value.Id) {
  72. item.T_depot_name = userInfo.value.T_name
  73. }
  74. return item
  75. })
  76. }
  77. const detailDataCallback = (res: any) => res.Data
  78. /**
  79. * 导出表格
  80. */
  81. const T_date = ref<string[]>([]) // 作为初始值
  82. const T_date_detail = ref<string[]>([])
  83. const T_date_export = ref<string[]>([])
  84. const visible = ref(false)
  85. const exportExcel = () => (visible.value = true)
  86. const confirmExpor = async (project_id?: string) => {
  87. const params = {
  88. User_tokey: globalStore.GET_User_tokey,
  89. T_depot_id: initParam.T_depot_id,
  90. T_start_date: T_date.value[0],
  91. T_end_date: T_date.value[1],
  92. T_product_id: ''
  93. }
  94. if (typeof project_id === 'number') {
  95. params['T_product_id'] = project_id
  96. }
  97. const res: any = await Storehouse_Stock_Detail_Excel(params)
  98. if (res.Code === 200) {
  99. window.open(res.Data)
  100. }
  101. }
  102. const NameOptions = ref<any[]>([])
  103. const classOptions = ref<any[]>([])
  104. const modelOptions = ref<any[]>([])
  105. // 获取产品分类
  106. const getProductClassList = async () => {
  107. const res: any = await Storehouse_ProductClass_List({ page: 1, page_z: 999 })
  108. classOptions.value = res.Data.Data
  109. }
  110. /**
  111. * 模糊搜索名称
  112. * @param str 名称字符串
  113. */
  114. const getNameAsync = async (str: string): Promise<any> => {
  115. const res: any = await Storehouse_Product_Name_List({ T_name: str, T_class: initParam.T_product_class })
  116. if (!res.Data) return
  117. return res.Data.map((item: any, index: number) => {
  118. return {
  119. value: item,
  120. index: index
  121. }
  122. })
  123. }
  124. /**
  125. * 模糊搜索名称
  126. * @param queryString 输入框的输入字符
  127. */
  128. const querySearchAsync = async (queryString: string) => {
  129. if (queryString) {
  130. loading.value = true
  131. globalStore.SET_isloading(true)
  132. const results = await getNameAsync(queryString)
  133. NameOptions.value = results
  134. globalStore.SET_isloading(false)
  135. loading.value = false
  136. }
  137. }
  138. /**
  139. * 异步获取产品型号
  140. */
  141. const getProductModelList = async () => {
  142. globalStore.SET_isloading(true)
  143. const res: any = await Storehouse_Product_Model_List({ T_name: initParam.T_product_name })
  144. modelOptions.value = res.Data.map((item: any, index: number) => {
  145. return {
  146. value: item,
  147. index: index
  148. }
  149. })
  150. globalStore.SET_isloading(false)
  151. }
  152. const handleSelect = (item: any) => {
  153. initParam.T_product_name = item.value
  154. getProductModelList()
  155. }
  156. // 明细
  157. const callbackDrawer = (done: () => void) => done()
  158. const previewDetail = (id: string) => {
  159. DrawerRef.value?.openDrawer()
  160. T_date_detail.value = [...T_date.value]
  161. if (detailInitParam.T_product_id === id) return
  162. detailInitParam.T_depot_id = initParam.T_depot_id
  163. detailInitParam.T_product_id = id
  164. detailInitParam.T_start_date = T_date.value[0]
  165. detailInitParam.T_end_date = T_date.value[1]
  166. TableDetailRef.value?.searchTable()
  167. }
  168. const dateDetailChange = (str: string[]) => {
  169. if (!str) return
  170. detailInitParam.T_start_date = str[0]
  171. detailInitParam.T_end_date = str[1]
  172. TableDetailRef.value?.searchTable()
  173. }
  174. onMounted(() => {
  175. getProductClassList()
  176. T_date.value = [dayJs().startOf('year').format('YYYY-MM-DD'), dayJs().format('YYYY-MM-DD')]
  177. T_date_export.value = [...T_date.value]
  178. })
  179. const getSalaryParams = (row: any) => {
  180. userInfo.value.Id = ''
  181. setTimeout(() => {
  182. userInfo.value = { ...row }
  183. initParam.T_depot_id = userInfo.value.Id
  184. }, 100)
  185. }
  186. </script>
  187. <template>
  188. <div class="inventory-statistics">
  189. <div style="width: 290px" class="inventory-table">
  190. <TableBase
  191. ref="TableRef"
  192. :columns="[{ prop: 'T_name', label: '仓库名称' }]"
  193. :requestApi="Storehouse_Depot_List"
  194. :initParam="{ User_tokey: globalStore.GET_User_tokey }"
  195. layout="prev, pager, next"
  196. :rowClick="getSalaryParams"
  197. :tableRowClassName="tableRowClassNameHandle"
  198. >
  199. <template #table-header>
  200. <h3 class="title">仓库列表</h3>
  201. </template>
  202. </TableBase>
  203. </div>
  204. <transition
  205. leave-active-class="animate__animated animate__fadeOutRight"
  206. enter-active-class="animate__animated animate__fadeInLeft"
  207. >
  208. <div class="project-container" v-if="userInfo.Id">
  209. <TableBase
  210. ref="TableRef"
  211. :columns="columns"
  212. :requestApi="Storehouse_Stock_List"
  213. :initParam="initParam"
  214. :dataCallback="dataCallback"
  215. >
  216. <template #table-header>
  217. <div class="head-search active">
  218. <el-form :model="initParam" class="result-form" label-width="100px">
  219. <el-row>
  220. <el-col :span="12"
  221. ><el-form-item label="产品分类" :inline-message="true">
  222. <el-select v-model="initParam.T_product_class" clearable placeholder="请选择分类~" class="w-50">
  223. <el-option v-for="item in classOptions" :key="item.Id" :label="item.T_name" :value="item.Id" />
  224. </el-select> </el-form-item
  225. ></el-col>
  226. <el-col :span="12"
  227. ><el-form-item label="产品名称">
  228. <el-select
  229. v-model="initParam.T_product_name"
  230. filterable
  231. clearable
  232. remote
  233. reserve-keyword
  234. placeholder="按产品名称搜索"
  235. remote-show-suffix
  236. :remote-method="querySearchAsync"
  237. :loading="loading"
  238. @change="handleSelect"
  239. >
  240. <el-option
  241. v-for="item in NameOptions"
  242. :key="item.value"
  243. :label="item.value"
  244. :value="item.value"
  245. />
  246. </el-select> </el-form-item
  247. ></el-col>
  248. </el-row>
  249. <el-row class="search-bottom">
  250. <el-col :span="12">
  251. <el-form-item label="产品型号">
  252. <el-select v-model="initParam.T_product_model" clearable placeholder="请选择型号~" class="w-50">
  253. <el-option
  254. v-for="item in modelOptions"
  255. :key="item.index"
  256. :label="item.value"
  257. :value="item.value"
  258. />
  259. </el-select>
  260. </el-form-item>
  261. </el-col>
  262. <el-col :span="6" :offset="6">
  263. <el-button type="primary" @click="searchHandle">搜索</el-button>
  264. <el-popover :visible="visible" placement="bottom" :width="400" trigger="click">
  265. <template #reference>
  266. <el-button type="success" @click="exportExcel">导出</el-button>
  267. </template>
  268. <el-date-picker
  269. v-model="T_date_export"
  270. type="daterange"
  271. range-separator="~"
  272. start-placeholder="开始时间"
  273. end-placeholder="结束时间"
  274. format="YYYY-MM-DD"
  275. value-format="YYYY-MM-DD"
  276. />
  277. <div class="export-popover">
  278. <el-button size="small" @click="visible = false">取消</el-button>
  279. <el-button size="small" type="primary" @click="confirmExpor">确认</el-button>
  280. </div>
  281. </el-popover>
  282. </el-col>
  283. </el-row>
  284. </el-form>
  285. </div>
  286. </template>
  287. <template #T_product_img="{ row }">
  288. <ImageCom :src="row.T_product_img" />
  289. </template>
  290. <template #right="{ row }">
  291. <el-button link type="primary" size="small" :icon="List" @click="previewDetail(row.T_product_id)"
  292. >明细</el-button
  293. >
  294. </template>
  295. </TableBase>
  296. </div>
  297. </transition>
  298. <Drawer ref="DrawerRef" :handleClose="callbackDrawer" size="80%">
  299. <template #header="{ params }">
  300. <h4 :id="params.titleId" :class="params.titleClass">库存明细</h4>
  301. </template>
  302. <TableBase
  303. border
  304. ref="TableDetailRef"
  305. :pagination="false"
  306. :columns="detailColumns"
  307. :requestApi="Storehouse_Stock_Detail_List"
  308. :initParam="detailInitParam"
  309. :dataCallback="detailDataCallback"
  310. >
  311. <template #table-header>
  312. <el-row class="head-search">
  313. <el-col :span="12"
  314. ><el-form-item label="日期范围">
  315. <el-date-picker
  316. v-model="T_date_detail"
  317. type="daterange"
  318. range-separator="~"
  319. start-placeholder="开始时间"
  320. end-placeholder="结束时间"
  321. format="YYYY-MM-DD"
  322. value-format="YYYY-MM-DD"
  323. @change="dateDetailChange" /></el-form-item
  324. ></el-col>
  325. <el-col :span="12">
  326. <el-button type="success" @click="confirmExpor(detailInitParam.T_product_id)">导出</el-button>
  327. </el-col>
  328. </el-row>
  329. </template>
  330. </TableBase>
  331. </Drawer>
  332. </div>
  333. </template>
  334. <style scoped lang="scss">
  335. @import '@/styles/var.scss';
  336. .export-popover {
  337. padding: 5px;
  338. display: flex;
  339. justify-content: center;
  340. }
  341. :deep(.drawer__content) {
  342. @include f-direction;
  343. }
  344. :deep(.el-drawer__header) {
  345. margin-bottom: 0;
  346. }
  347. .inventory-statistics {
  348. height: 100%;
  349. display: flex;
  350. overflow: hidden;
  351. .title {
  352. width: 100%;
  353. text-align: center;
  354. line-height: 1.7em;
  355. font-size: 20px;
  356. color: #707b84;
  357. }
  358. :deep(.table-header),
  359. :deep(.card) {
  360. margin: 0;
  361. border-radius: 8px;
  362. }
  363. .inventory-table {
  364. @include f-direction;
  365. z-index: 1;
  366. }
  367. .project-container {
  368. @include f-direction;
  369. z-index: 0;
  370. margin-left: 12px;
  371. width: calc(100% - 290px);
  372. }
  373. .head-search {
  374. width: 100%;
  375. height: 33px;
  376. overflow: hidden;
  377. transition: all 0.5s ease-in-out;
  378. .result-form.el-form .el-form-item {
  379. margin-bottom: 0 !important;
  380. }
  381. .search-bottom {
  382. margin-top: 18px;
  383. }
  384. }
  385. .head-search.active {
  386. height: 85px;
  387. }
  388. .w-50 {
  389. flex: 0 0 50%;
  390. }
  391. }
  392. </style>