| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224 |
- <template>
- <div class="app-container">
- <div class="search-wrap">
- <van-search v-model="searchKey" placeholder="搜索菌毒种名称" @search="onSearch" />
- </div>
- <van-tabs v-model:active="activeTab" @change="onTabChange">
- <van-tab title="入库记录" name="inbound"></van-tab>
- <van-tab title="领用记录" name="usage"></van-tab>
- </van-tabs>
- <div class="list-container">
- <van-list v-model:loading="state.loading" :finished="state.finished" finished-text="没有更多了" @load="onLoad">
- <van-cell v-for="item in state.list" :key="item.id" @click="onDetail(item)">
- <template #default>
- <!-- 入库记录卡片 -->
- <div v-if="activeTab === 'inbound'" class="card-item">
- <header class="flex justify-between">
- <strong class="title">{{ item.strainName }}</strong>
- <van-tag type="primary" size="medium">{{ item.quantity }}</van-tag>
- </header>
- <p class="info-row"><span>保存温度</span><span class="val">{{ item.preservationTemp }}</span></p>
- <p class="info-row"><span>存放地点</span><span class="val">{{ item.storageLocation }}</span></p>
- <p class="info-row"><span>入库日期</span><span class="val">{{ item.inboundDate ? formatDate(new Date(item.inboundDate), 'YYYY-mm-dd') : '-' }}</span></p>
- <p class="info-row"><span>入库人</span><span class="val">{{ item.inboundPerson }}</span></p>
- <div class="flex mt10 btns">
- <van-button v-auth="'instr_strain_inbound_edit'" size="small" type="primary" @click.stop="onEditInbound(item)">修改</van-button>
- <van-button v-auth="'instr_strain_inbound_del'" size="small" type="danger" @click.stop="onDelInbound(item)">删除</van-button>
- </div>
- </div>
- <!-- 领用记录卡片 -->
- <div v-else class="card-item">
- <header class="flex justify-between">
- <strong class="title">{{ item.strainName }}</strong>
- <van-tag type="success" size="medium">{{ item.usageQuantity }}</van-tag>
- </header>
- <p class="info-row"><span>领用日期</span><span class="val">{{ item.usageDate ? formatDate(new Date(item.usageDate), 'YYYY-mm-dd') : '-' }}</span></p>
- <p class="info-row"><span>领用人</span><span class="val">{{ item.usagePerson }}</span></p>
- <p class="info-row" v-if="item.purpose"><span>用途</span><span class="val">{{ item.purpose }}</span></p>
- <p class="info-row"><span>剩余量</span><span class="val">{{ item.remainingQuantity || '-' }}</span></p>
- <div class="flex mt10 btns">
- <van-button v-auth="'instr_strain_usage_del'" size="small" type="danger" @click.stop="onDelUsage(item)">删除</van-button>
- </div>
- </div>
- </template>
- </van-cell>
- </van-list>
- </div>
- <van-floating-bubble v-if="hasAddPerm" icon="plus" @click="onAdd" axis="y" />
- </div>
- </template>
- <script lang="ts" setup>
- import to from 'await-to-js'
- import { formatDate } from '/@/utils/formatTime'
- import { onMounted, reactive, ref, computed } from 'vue'
- import { useRouter } from 'vue-router'
- import { useStrainApi } from '/@/api/strain'
- import { useUserInfo } from '/@/stores/userInfo'
- import { showConfirmDialog, showNotify } from 'vant'
- const router = useRouter()
- const strainApi = useStrainApi()
- const userStore = useUserInfo()
- const activeTab = ref('inbound')
- const searchKey = ref('')
- const hasAddPerm = computed(() => {
- const key = activeTab.value === 'inbound' ? 'instr_strain_inbound_add' : 'instr_strain_usage_add'
- return userStore.userInfos.authBtnList?.includes(key)
- })
- const state = reactive({
- loading: true,
- finished: false,
- list: [] as any[],
- queryForm: {
- strainName: '',
- pageNum: 1,
- pageSize: 10
- }
- })
- const resetList = () => {
- state.queryForm.pageNum = 1
- state.list = []
- state.finished = false
- state.loading = true
- }
- const onLoad = async () => {
- const query = { ...state.queryForm }
- const api = activeTab.value === 'inbound' ? strainApi.getInboundList : strainApi.getUsageList
- const [err, res]: any = await to(api(query))
- if (err) {
- state.loading = false
- return
- }
- const list = res?.data?.list|| []
- for (const item of list) {
- state.list.push(item)
- }
- state.queryForm.pageNum++
- state.loading = false
- if (list.length < state.queryForm.pageSize) {
- state.finished = true
- }
- }
- const onSearch = () => {
- state.queryForm.strainName = searchKey.value
- resetList()
- onLoad()
- }
- const onTabChange = () => {
- resetList()
- onLoad()
- }
- const onAdd = () => {
- if (activeTab.value === 'inbound') {
- router.push('/strain/inbound/add')
- } else {
- router.push('/strain/usage/add')
- }
- }
- const onDetail = (item: any) => {
- if (activeTab.value === 'inbound') {
- router.push(`/strain/inbound/add?mode=detail&id=${item.id}`)
- } else {
- router.push(`/strain/usage/add?mode=detail&id=${item.id}`)
- }
- }
- const onEditInbound = (item: any) => {
- router.push(`/strain/inbound/add?mode=edit&id=${item.id}`)
- }
- const onDelInbound = async (item: any) => {
- showConfirmDialog({
- title: '提示',
- message: `确认删除入库记录(${item.strainName})?`
- }).then(async () => {
- const [err]: any = await to(strainApi.deleteInbound({ ids: [item.id] }))
- if (err) return
- showNotify({ type: 'success', message: '删除成功' })
- resetList()
- onLoad()
- }).catch(() => {})
- }
- const onDelUsage = async (item: any) => {
- showConfirmDialog({
- title: '提示',
- message: `确认删除领用记录(${item.strainName})?`
- }).then(async () => {
- const [err]: any = await to(strainApi.deleteUsage({ ids: [item.id] }))
- if (err) return
- showNotify({ type: 'success', message: '删除成功' })
- resetList()
- onLoad()
- }).catch(() => {})
- }
- onMounted(() => {
- onLoad()
- })
- </script>
- <style lang="scss" scoped>
- .app-container {
- display: flex;
- flex-direction: column;
- min-height: 100vh;
- background-color: #f7f8fa;
- }
- .search-wrap {
- background: #fff;
- }
- .list-container {
- overflow-y: auto;
- padding: 10px;
- flex: 1;
- .van-list {
- .van-cell {
- background-color: #fff;
- border-radius: 8px;
- + .van-cell {
- margin-top: 10px;
- }
- }
- }
- }
- .card-item {
- header {
- .title {
- flex: 1;
- white-space: nowrap;
- overflow: hidden;
- text-overflow: ellipsis;
- font-size: 16px;
- }
- }
- .info-row {
- display: flex;
- justify-content: space-between;
- color: #333;
- margin-top: 4px;
- span:first-child {
- color: #787878;
- flex: 0 0 70px;
- }
- .val {
- flex: 1;
- text-align: right;
- }
- }
- .btns {
- justify-content: flex-end;
- gap: 10px;
- }
- }
- </style>
|