|
|
@@ -0,0 +1,968 @@
|
|
|
+<template>
|
|
|
+ <div>
|
|
|
+ <transition appear enter-active-class="animated fadeIn">
|
|
|
+ <q-table
|
|
|
+ class="my-sticky-header-column-table shadow-24"
|
|
|
+ :data="table_list"
|
|
|
+ row-key="id"
|
|
|
+ :separator="separator"
|
|
|
+ :loading="loading"
|
|
|
+ :columns="columns"
|
|
|
+ hide-bottom
|
|
|
+ :pagination.sync="pagination"
|
|
|
+ no-data-label="No data"
|
|
|
+ no-results-label="No data you want"
|
|
|
+ :table-style="{ height: height }"
|
|
|
+ flat
|
|
|
+ bordered
|
|
|
+ >
|
|
|
+ <template v-slot:header-cell="props">
|
|
|
+ <q-th :props="props" @dblclick="handleHeaderDblClick(props.col)">
|
|
|
+ <!-- 为特定列添加下拉选择器 -->
|
|
|
+ <template
|
|
|
+ v-if="['check_status', 'log_type'].includes(props.col.name)"
|
|
|
+ >
|
|
|
+ <q-select
|
|
|
+ dense
|
|
|
+ outlined
|
|
|
+ v-model="filterModels[props.col.name]"
|
|
|
+ :options="getFilterOptions(props.col.name)"
|
|
|
+ option-label="label"
|
|
|
+ option-value="value"
|
|
|
+ emit-value
|
|
|
+ map-options
|
|
|
+ clearable
|
|
|
+ @input="handleFilterChange"
|
|
|
+ style="min-width: 120px"
|
|
|
+ >
|
|
|
+ <template v-slot:prepend>
|
|
|
+ <span class="text-caption">{{ props.col.label }}</span>
|
|
|
+ </template>
|
|
|
+ </q-select>
|
|
|
+ </template>
|
|
|
+ <template v-else>
|
|
|
+ {{ props.col.label }}
|
|
|
+ </template>
|
|
|
+ </q-th>
|
|
|
+ </template>
|
|
|
+ <template v-slot:top>
|
|
|
+ <q-btn-group push>
|
|
|
+ <q-btn :label="$t('refresh')" icon="refresh" @click="reFresh()">
|
|
|
+ <q-tooltip
|
|
|
+ content-class="bg-amber text-black shadow-4"
|
|
|
+ :offset="[10, 10]"
|
|
|
+ content-style="font-size: 12px"
|
|
|
+ >{{ $t("refreshtip") }}</q-tooltip
|
|
|
+ >
|
|
|
+ </q-btn>
|
|
|
+ <q-btn
|
|
|
+ :label="$t('downloadasnlist')"
|
|
|
+ icon="cloud_download"
|
|
|
+ @click="downloadlistData()"
|
|
|
+ >
|
|
|
+ </q-btn>
|
|
|
+ <!-- <q-btn :label="'日志'" icon="logout" @click="getlog()"> </q-btn> -->
|
|
|
+ </q-btn-group>
|
|
|
+
|
|
|
+ <q-space />
|
|
|
+
|
|
|
+ <div class="flex items-center">
|
|
|
+ <div class="q-mr-md">{{ $t("download_center.createTime") }}</div>
|
|
|
+ <q-input
|
|
|
+ readonly
|
|
|
+ outlined
|
|
|
+ dense
|
|
|
+ v-model="createDate2"
|
|
|
+ :placeholder="interval"
|
|
|
+ >
|
|
|
+ <template v-slot:append>
|
|
|
+ <q-icon name="event" class="cursor-pointer">
|
|
|
+ <q-popup-proxy
|
|
|
+ ref="qDateProxy"
|
|
|
+ transition-show="scale"
|
|
|
+ transition-hide="scale"
|
|
|
+ >
|
|
|
+ <q-date v-model="createDate1" range>
|
|
|
+ <div class="row items-center justify-end q-gutter-sm">
|
|
|
+ <q-btn
|
|
|
+ :label="$t('index.cancel')"
|
|
|
+ color="primary"
|
|
|
+ flat
|
|
|
+ v-close-popup
|
|
|
+ />
|
|
|
+ <q-btn
|
|
|
+ :label="$t('index.clear')"
|
|
|
+ color="primary"
|
|
|
+ @click="
|
|
|
+ createDate2 = '';
|
|
|
+ createDate1 = '';
|
|
|
+ "
|
|
|
+ v-close-popup
|
|
|
+ />
|
|
|
+ </div>
|
|
|
+ </q-date>
|
|
|
+ </q-popup-proxy>
|
|
|
+ </q-icon>
|
|
|
+ </template>
|
|
|
+ </q-input>
|
|
|
+ <q-btn-group push class="q-ml-md"> </q-btn-group>
|
|
|
+ </div>
|
|
|
+ </template>
|
|
|
+
|
|
|
+ <template v-slot:body="props">
|
|
|
+ <q-tr :props="props" :style="getRowStyle(props.row)">
|
|
|
+ <q-td
|
|
|
+ v-for="col in columns.filter((c) => c.name !== 'expand')"
|
|
|
+ :key="col.name"
|
|
|
+ :props="props"
|
|
|
+ >
|
|
|
+ <span v-if="col.name === 'check_status'">
|
|
|
+ {{ checkStatusToText(props.row[col.field]) }}
|
|
|
+ </span>
|
|
|
+ <span v-else-if="col.name === 'goods_qty'">
|
|
|
+ {{ props.row.goods_in_qty - props.row.goods_out_qty }}
|
|
|
+ </span>
|
|
|
+ <span v-else-if="col.name === 'log_type'">
|
|
|
+ {{ logtypeToText(props.row[col.field]) }}
|
|
|
+ </span>
|
|
|
+ <span
|
|
|
+ v-else-if="
|
|
|
+ ['check_status', 'goods_qty'].indexOf(col.name) === -1
|
|
|
+ "
|
|
|
+ >
|
|
|
+ {{ col.field ? props.row[col.field] : props.row[col.name] }}
|
|
|
+ </span>
|
|
|
+ </q-td>
|
|
|
+ </q-tr>
|
|
|
+
|
|
|
+ <!-- 第二级:时间轴 -->
|
|
|
+ <q-tr
|
|
|
+ v-show="props.row.expand"
|
|
|
+ :props="props"
|
|
|
+ class="expanded-row"
|
|
|
+ :style="getRowStyle(props.row)"
|
|
|
+ >
|
|
|
+ <template>
|
|
|
+ <q-td colspan="100%">
|
|
|
+ <div class="q-pa-md timeline-wrapper">
|
|
|
+ <q-timeline
|
|
|
+ color="#e0e0e0"
|
|
|
+ v-if="props.row.containers?.length"
|
|
|
+ >
|
|
|
+ <q-timeline-entry
|
|
|
+ v-for="(container, index) in props.row.containers"
|
|
|
+ :key="index"
|
|
|
+ class="custom-node"
|
|
|
+ >
|
|
|
+ <template v-slot:title>
|
|
|
+ <span>
|
|
|
+ <div>
|
|
|
+ 托盘 {{ container.container_code }}
|
|
|
+ <span class="text-caption">
|
|
|
+ 操作时间:{{ container.change_time }}
|
|
|
+ </span>
|
|
|
+ </div>
|
|
|
+ </span>
|
|
|
+ </template>
|
|
|
+
|
|
|
+ <template v-slot:subtitle>
|
|
|
+ <div class="text-caption">
|
|
|
+ 批次: {{ container.batch }} | 物料编码:
|
|
|
+ {{ container.goods_code }} |{{ container.goods_desc }}
|
|
|
+ |
|
|
|
+ <br />
|
|
|
+ 批次计划入库数:
|
|
|
+ {{ container.batch_goods_qty }} | 批次总组盘数:
|
|
|
+ {{ container.batch_goods_in_qty }} | 批次总出库数:
|
|
|
+ {{ container.batch_goods_out_qty }} | 在库数量:
|
|
|
+ {{ container.batch_goods_in_location_qty }} |
|
|
|
+ </div>
|
|
|
+ </template>
|
|
|
+
|
|
|
+ <div class="timeline-content">
|
|
|
+ <div class="row">
|
|
|
+ <div class="col-6">
|
|
|
+ <div class="text-caption">
|
|
|
+ 操作类型: {{ logtypeToText(container.log_type) }}
|
|
|
+ </div>
|
|
|
+ <div class="text-caption">
|
|
|
+ 操作人: {{ container.creater }}
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <div class="col-6">
|
|
|
+ 数量变化:<br />
|
|
|
+ <span v-if="container.log_type === 'delete'">
|
|
|
+ {{ container.old_goods_qty }} →
|
|
|
+ {{ container.new_goods_qty }}
|
|
|
+ </span>
|
|
|
+ <span v-else-if="container.log_type === 'out'">
|
|
|
+ 出库数量:{{ container.old_goods_out_qty }} →
|
|
|
+ {{ container.new_goods_out_qty }}
|
|
|
+ </span>
|
|
|
+ <span
|
|
|
+ v-else-if="container.log_type === 'cancel_out'"
|
|
|
+ >
|
|
|
+ 出库数量:{{ container.old_goods_out_qty }} →
|
|
|
+ {{ container.new_goods_out_qty }}
|
|
|
+ </span>
|
|
|
+ <span v-else-if="container.log_type === 'create'">
|
|
|
+ 入库数量:{{ container.old_goods_qty }} →
|
|
|
+ {{ container.new_goods_in_qty }}
|
|
|
+ </span>
|
|
|
+
|
|
|
+ <span v-else-if="container.log_type === 'update'">
|
|
|
+ 入库数量:{{ container.old_goods_qty }} →
|
|
|
+ {{ container.new_goods_qty }}
|
|
|
+ <br />
|
|
|
+ 出库数量:{{ container.old_goods_out_qty }} →
|
|
|
+ {{ container.new_goods_out_qty }}
|
|
|
+ </span>
|
|
|
+
|
|
|
+ <!-- <div class="text-caption">
|
|
|
+ 状态:
|
|
|
+ <span v-if="container.old_status !== null">
|
|
|
+ {{ getStatusText(container.old_status) }} →
|
|
|
+ {{ getStatusText(container.new_status) }}
|
|
|
+ </span>
|
|
|
+ </div> -->
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </q-timeline-entry>
|
|
|
+ </q-timeline>
|
|
|
+ <div v-else class="text-caption text-grey">
|
|
|
+ 暂无容器操作记录
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </q-td>
|
|
|
+ </template>
|
|
|
+ </q-tr>
|
|
|
+ </template>
|
|
|
+ </q-table>
|
|
|
+ </transition>
|
|
|
+
|
|
|
+ <template>
|
|
|
+ <div v-show="max !== 0" class="q-pa-lg flex flex-center">
|
|
|
+ <div>{{ total }}</div>
|
|
|
+ <q-pagination
|
|
|
+ v-model="current"
|
|
|
+ color="black"
|
|
|
+ :max="max"
|
|
|
+ :max-pages="6"
|
|
|
+ boundary-links
|
|
|
+ @click="
|
|
|
+ getSearchList(current);
|
|
|
+ paginationIpt = current;
|
|
|
+ "
|
|
|
+ />
|
|
|
+ <div>
|
|
|
+ <input
|
|
|
+ v-model="paginationIpt"
|
|
|
+ @blur="changePageEnter"
|
|
|
+ @keyup.enter="changePageEnter"
|
|
|
+ style="width: 60px; text-align: center"
|
|
|
+ />
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <div v-show="max === 0" class="q-pa-lg flex flex-center">
|
|
|
+ <q-btn flat push color="dark" :label="$t('no_data')"></q-btn>
|
|
|
+ </div>
|
|
|
+ </template>
|
|
|
+ </div>
|
|
|
+</template>
|
|
|
+<router-view />
|
|
|
+
|
|
|
+<script>
|
|
|
+import { getauth, postauth, putauth } from 'boot/axios_request'
|
|
|
+import { date, exportFile, LocalStorage } from 'quasar'
|
|
|
+import containercard from 'components/containercard.vue'
|
|
|
+
|
|
|
+export default {
|
|
|
+ name: 'PageTask',
|
|
|
+ components: {
|
|
|
+ containercard
|
|
|
+ },
|
|
|
+ data () {
|
|
|
+ return {
|
|
|
+ createDate1: '',
|
|
|
+ createDate2: '',
|
|
|
+ date_range: '',
|
|
|
+ proxyDate: '',
|
|
|
+ date: '',
|
|
|
+ goods_code: '',
|
|
|
+ goods_desc: '',
|
|
|
+ openid: '',
|
|
|
+ login_name: '',
|
|
|
+ authin: '0',
|
|
|
+ searchUrl: '',
|
|
|
+ pathname: 'reportcenter/flows_statements/',
|
|
|
+ pathfilename: 'reportcenter/MaterialChangeHistory/file/',
|
|
|
+ pathname_previous: '',
|
|
|
+ pathname_next: '',
|
|
|
+ separator: 'cell',
|
|
|
+ loading: false,
|
|
|
+ height: '',
|
|
|
+ viewForm: false,
|
|
|
+ editDialog: false,
|
|
|
+
|
|
|
+ table_list: [],
|
|
|
+ columns: [
|
|
|
+ // {
|
|
|
+ // name: 'change_time',
|
|
|
+ // label: '操作时间',
|
|
|
+ // field: 'change_time',
|
|
|
+ // align: 'center'
|
|
|
+ // },
|
|
|
+ // {
|
|
|
+ // name: 'change_type',
|
|
|
+ // label: '变更类型',
|
|
|
+ // field: 'change_type',
|
|
|
+ // align: 'center'
|
|
|
+ // },
|
|
|
+ {
|
|
|
+ name: 'goods_code',
|
|
|
+ label: '存货编码',
|
|
|
+ field: 'goods_code',
|
|
|
+ align: 'center'
|
|
|
+ },
|
|
|
+
|
|
|
+ {
|
|
|
+ name: 'goods_desc',
|
|
|
+ label: '存货名称',
|
|
|
+ field: 'goods_desc',
|
|
|
+ align: 'center'
|
|
|
+ },
|
|
|
+ {
|
|
|
+ name: 'opening_quantity',
|
|
|
+ label: '期初数量',
|
|
|
+ field: 'opening_quantity',
|
|
|
+ align: 'center'
|
|
|
+ },
|
|
|
+ {
|
|
|
+ name: 'closing_quantity',
|
|
|
+ label: '期末数量',
|
|
|
+ field: 'closing_quantity',
|
|
|
+ align: 'center'
|
|
|
+ },
|
|
|
+ {
|
|
|
+ name: 'net_change',
|
|
|
+ label: '期间变化',
|
|
|
+ field: 'net_change',
|
|
|
+ align: 'center'
|
|
|
+ },
|
|
|
+ {
|
|
|
+ name: 'total_in',
|
|
|
+ label: '入库数量',
|
|
|
+ field: 'total_in',
|
|
|
+ align: 'center'
|
|
|
+ },
|
|
|
+ {
|
|
|
+ name: 'total_out',
|
|
|
+ label: '出库数量',
|
|
|
+ field: 'total_out',
|
|
|
+ align: 'center'
|
|
|
+ },
|
|
|
+ {
|
|
|
+ name: 'theoretical_change',
|
|
|
+ label: '出入库差异',
|
|
|
+ field: 'theoretical_change',
|
|
|
+ align: 'center'
|
|
|
+ },
|
|
|
+ {
|
|
|
+ name: 'is_consistent',
|
|
|
+ label: '对比结果',
|
|
|
+ field: 'is_consistent',
|
|
|
+ align: 'center'
|
|
|
+ },
|
|
|
+ {
|
|
|
+ name: 'goods_unit',
|
|
|
+ label: '计量单位',
|
|
|
+ field: 'goods_unit',
|
|
|
+ align: 'center'
|
|
|
+ }
|
|
|
+ ],
|
|
|
+ filter: '',
|
|
|
+ pagination: {
|
|
|
+ page: 1,
|
|
|
+ rowsPerPage: 11
|
|
|
+ },
|
|
|
+ current: 1,
|
|
|
+ max: 0,
|
|
|
+ total: 0,
|
|
|
+ paginationIpt: 1,
|
|
|
+ containers: {},
|
|
|
+ timer: null,
|
|
|
+ showInventoryDetails: false,
|
|
|
+ select_container_number: 0,
|
|
|
+ select_container_code: 0,
|
|
|
+ filterModels: {
|
|
|
+ bound_department: null
|
|
|
+ },
|
|
|
+ editForm: {
|
|
|
+ id: '',
|
|
|
+ bound_number: '',
|
|
|
+ goods_code: '',
|
|
|
+ goods_desc: '',
|
|
|
+ goods_qty: '',
|
|
|
+ goods_unit: '',
|
|
|
+ goods_package: '',
|
|
|
+ goods_in_qty: '',
|
|
|
+ goods_out_qty: '',
|
|
|
+ goods_std: '',
|
|
|
+ check_status: '',
|
|
|
+ check_user: '默认质检人',
|
|
|
+ change_time: '',
|
|
|
+ note: '无'
|
|
|
+ },
|
|
|
+ activeSearchField: '',
|
|
|
+ activeSearchLabel: '',
|
|
|
+ filterdata: {}
|
|
|
+ }
|
|
|
+ },
|
|
|
+ computed: {
|
|
|
+ interval () {
|
|
|
+ return (
|
|
|
+ this.$t('download_center.start') +
|
|
|
+ ' - ' +
|
|
|
+ this.$t('download_center.end')
|
|
|
+ )
|
|
|
+ }
|
|
|
+ },
|
|
|
+ methods: {
|
|
|
+ downloadlistData () {
|
|
|
+ this.getfileList()
|
|
|
+ },
|
|
|
+ getfileList () {
|
|
|
+ var _this = this
|
|
|
+ _this.loading = true
|
|
|
+ const params = {
|
|
|
+ change_time__range: _this.date_range
|
|
|
+ }
|
|
|
+ const queryParams = new URLSearchParams({
|
|
|
+ ...params
|
|
|
+ })
|
|
|
+ console.log(queryParams)
|
|
|
+ // 过滤空值参数
|
|
|
+ Array.from(queryParams.entries()).forEach(([key, value]) => {
|
|
|
+ if (value === '' || value === null || value === undefined) {
|
|
|
+ queryParams.delete(key)
|
|
|
+ }
|
|
|
+ })
|
|
|
+ console.log(`${_this.pathfilename}?${queryParams}`)
|
|
|
+ postauth(`${_this.pathfilename}?${queryParams}`)
|
|
|
+ .then((res) => {
|
|
|
+ var timeStamp = Date.now()
|
|
|
+ var formattedString = date.formatDate(timeStamp, 'YYYYMMDDHHmmss')
|
|
|
+ const status = exportFile(
|
|
|
+ _this.pathfilename + 'list' + formattedString + '.csv',
|
|
|
+ '\uFEFF' + res,
|
|
|
+ 'text/csv'
|
|
|
+ )
|
|
|
+ if (status !== true) {
|
|
|
+ _this.$q.notify({
|
|
|
+ message: 'Browser denied file download...',
|
|
|
+ color: 'negative',
|
|
|
+ icon: 'warning'
|
|
|
+ })
|
|
|
+ }
|
|
|
+ })
|
|
|
+ .catch((err) => {
|
|
|
+ _this.$q.notify({
|
|
|
+ message: err.detail,
|
|
|
+ icon: 'close',
|
|
|
+ color: 'negative'
|
|
|
+ })
|
|
|
+ })
|
|
|
+ .finally(() => {
|
|
|
+ _this.loading = false
|
|
|
+ })
|
|
|
+ },
|
|
|
+ handleEditRow (row) {
|
|
|
+ this.editForm = { ...row } // 复制当前行的数据到表单
|
|
|
+ this.editForm.note = this.editForm.note || '无' // 防止note为空
|
|
|
+ this.editForm.check_user = this.editForm.check_user || '默认质检人' // 防止check_user为空
|
|
|
+ console.log(this.editForm)
|
|
|
+ this.editDialog = true // 打开对话框
|
|
|
+ },
|
|
|
+ saveEditRow () {
|
|
|
+ const _this = this
|
|
|
+ putauth(`bound/batch/${_this.editForm.id}/`, _this.editForm) // 假设修改API是这样的
|
|
|
+ .then((res) => {
|
|
|
+ _this.editDialog = false // 关闭对话框
|
|
|
+
|
|
|
+ if (res.status_code !== 400) {
|
|
|
+ _this.$q.notify({ message: '修改成功', color: 'positive' })
|
|
|
+ _this.getSearchList() // 刷新列表
|
|
|
+ } else {
|
|
|
+ // 错误信息的键值映射到中文字段名称
|
|
|
+ const errorFieldMap = {
|
|
|
+ note: '备注',
|
|
|
+ check_user: '质检人'
|
|
|
+ }
|
|
|
+
|
|
|
+ // 遍历 res 对象的属性,查找错误信息
|
|
|
+ let errorMessage = '修改失败'
|
|
|
+ for (const key in res) {
|
|
|
+ if (Array.isArray(res[key]) && res[key].length > 0) {
|
|
|
+ const fieldLabel = errorFieldMap[key] || key
|
|
|
+ errorMessage = `${fieldLabel}: ${res[key].join(' ')}`
|
|
|
+ break
|
|
|
+ }
|
|
|
+ }
|
|
|
+ console.error('修改失败', errorMessage)
|
|
|
+ _this.$q.notify({ message: errorMessage, color: 'negative' })
|
|
|
+ }
|
|
|
+ })
|
|
|
+ .catch((error) => {
|
|
|
+ console.error('修改失败', error)
|
|
|
+ _this.$q.notify({
|
|
|
+ message: '发生未知错误,请联系管理员',
|
|
|
+ color: 'negative'
|
|
|
+ })
|
|
|
+ })
|
|
|
+ },
|
|
|
+
|
|
|
+ checkStatusToText (check_status) {
|
|
|
+ const statusTexts = {
|
|
|
+ 0: '待质检',
|
|
|
+ 1: '质检合格',
|
|
|
+ 2: '质检问题'
|
|
|
+ }
|
|
|
+
|
|
|
+ return statusTexts[check_status] || '未知状态'
|
|
|
+ },
|
|
|
+ logtypeToText (log) {
|
|
|
+ const logtypeTexts = {
|
|
|
+ create: '批次入库',
|
|
|
+ out: '批次出库',
|
|
|
+ delete: '批次删除',
|
|
|
+ update: '批次更新',
|
|
|
+ cancel_out: '取消出库'
|
|
|
+ }
|
|
|
+
|
|
|
+ return logtypeTexts[log] || '未知状态'
|
|
|
+ },
|
|
|
+ getRowStyle (row) {
|
|
|
+ // 根据check_status值返回不同的背景色
|
|
|
+ const statusColors = {
|
|
|
+ 0: '#fff9c4', // 更浅的黄色 - 待质检
|
|
|
+ true: '#c8e6c9', // 更浅的绿色 - 质检合格
|
|
|
+ false: '#ffcdd2' // 更浅的红色 - 质检问题
|
|
|
+ }
|
|
|
+
|
|
|
+ const color = statusColors[row.is_consistent] || ''
|
|
|
+ return color ? { backgroundColor: color } : {}
|
|
|
+ },
|
|
|
+ // 处理过滤变化
|
|
|
+ handleFilterChange () {
|
|
|
+ this.pagination.page = 1
|
|
|
+ this.getSearchList(1)
|
|
|
+ },
|
|
|
+
|
|
|
+ getFilterOptions (columnName) {
|
|
|
+ switch (columnName) {
|
|
|
+ case 'type':
|
|
|
+ return [
|
|
|
+ { label: '生产入库', value: 1 },
|
|
|
+ { label: '采购入库', value: 2 },
|
|
|
+ { label: '其他入库', value: 3 },
|
|
|
+ { label: '调拨入库', value: 4 }
|
|
|
+ ]
|
|
|
+ case 'bound_status':
|
|
|
+ return [
|
|
|
+ { label: '待质检', value: 0 },
|
|
|
+ { label: '质检合格', value: 1 }
|
|
|
+ ]
|
|
|
+ case 'bound_department':
|
|
|
+ return this.bound_department_list
|
|
|
+
|
|
|
+ case 'check_status':
|
|
|
+ return [
|
|
|
+ { label: '待质检', value: 0 },
|
|
|
+ { label: '质检合格', value: 1 },
|
|
|
+ { label: '质检问题', value: 2 }
|
|
|
+ ]
|
|
|
+
|
|
|
+ case 'log_type':
|
|
|
+ return [
|
|
|
+ { label: '批次入库', value: 'create' },
|
|
|
+ { label: '批次出库', value: 'out' },
|
|
|
+ { label: '批次删除', value: 'delete' },
|
|
|
+ { label: '批次更新', value: 'update' }
|
|
|
+ ]
|
|
|
+ default:
|
|
|
+ return []
|
|
|
+ }
|
|
|
+ },
|
|
|
+ getStatusText (status) {
|
|
|
+ const statusMap = {
|
|
|
+ 0: '待入库',
|
|
|
+ 1: '在库',
|
|
|
+ 2: '待出库',
|
|
|
+ 3: '已出库',
|
|
|
+ 4: '异常'
|
|
|
+ }
|
|
|
+ return statusMap[status] || '未知状态'
|
|
|
+ },
|
|
|
+ handleHeaderDblClick (column) {
|
|
|
+ // 排除不需要搜索的列
|
|
|
+ if (['detail', 'action'].includes(column.name)) return
|
|
|
+
|
|
|
+ this.activeSearchField = column.field
|
|
|
+ this.activeSearchLabel = column.label
|
|
|
+
|
|
|
+ // 弹出搜索对话框
|
|
|
+ this.$q
|
|
|
+ .dialog({
|
|
|
+ title: `搜索${column.label}`,
|
|
|
+ message: `请输入${column.label}的搜索条件`,
|
|
|
+ prompt: {
|
|
|
+ model: '',
|
|
|
+ type: 'text'
|
|
|
+ },
|
|
|
+ cancel: true,
|
|
|
+ persistent: true
|
|
|
+ })
|
|
|
+ .onOk((data) => {
|
|
|
+ // 执行搜索
|
|
|
+ this.executeColumnSearch(column.field, data)
|
|
|
+ })
|
|
|
+ .onCancel(() => {
|
|
|
+ this.activeSearchField = ''
|
|
|
+ this.activeSearchLabel = ''
|
|
|
+ })
|
|
|
+ },
|
|
|
+ // 执行列搜索
|
|
|
+ executeColumnSearch (field, value) {
|
|
|
+ // 构建搜索参数
|
|
|
+ if (
|
|
|
+ field === 'type' ||
|
|
|
+ field === 'audit_status' ||
|
|
|
+ field === 'save_status' ||
|
|
|
+ field === 'bound_status'
|
|
|
+ ) {
|
|
|
+ const searchParams = {
|
|
|
+ [field]: value
|
|
|
+ }
|
|
|
+ // 清除其他搜索条件
|
|
|
+ this.filter = ''
|
|
|
+ this.date_range = ''
|
|
|
+
|
|
|
+ // 执行搜索
|
|
|
+ this.getList({
|
|
|
+ ...searchParams,
|
|
|
+ page: 1
|
|
|
+ })
|
|
|
+ this.filterdata = searchParams
|
|
|
+ this.$q.notify({
|
|
|
+ message: `已搜索 ${this.activeSearchLabel} 含有 "${value}" 的结果`,
|
|
|
+ icon: 'search',
|
|
|
+ color: 'positive'
|
|
|
+ })
|
|
|
+
|
|
|
+ // 重置激活的搜索字段
|
|
|
+ this.activeSearchField = ''
|
|
|
+ this.activeSearchLabel = ''
|
|
|
+ } else {
|
|
|
+ const searchParams = {
|
|
|
+ [field + '__icontains']: value
|
|
|
+ }
|
|
|
+ // 清除其他搜索条件
|
|
|
+ this.filter = ''
|
|
|
+ this.date_range = ''
|
|
|
+
|
|
|
+ // 执行搜索
|
|
|
+ this.getList({
|
|
|
+ ...searchParams,
|
|
|
+ page: 1
|
|
|
+ })
|
|
|
+ this.filterdata = searchParams
|
|
|
+ this.$q.notify({
|
|
|
+ message: `已搜索 ${this.activeSearchLabel} 含有 "${value}" 的结果`,
|
|
|
+ icon: 'search',
|
|
|
+ color: 'positive'
|
|
|
+ })
|
|
|
+ // 重置激活的搜索字段
|
|
|
+ this.activeSearchField = ''
|
|
|
+ this.activeSearchLabel = ''
|
|
|
+ }
|
|
|
+ },
|
|
|
+
|
|
|
+ class_to_name (class_id) {
|
|
|
+ const class_map = {
|
|
|
+ 1: '整盘',
|
|
|
+ 2: '托盘组',
|
|
|
+ 3: '零盘'
|
|
|
+ }
|
|
|
+ return class_map[class_id]
|
|
|
+ },
|
|
|
+ handle_row_expand (row) {
|
|
|
+ const _this = this
|
|
|
+ row.expand = !row.expand
|
|
|
+ if (row.expand) {
|
|
|
+ // 添加行级 loading 状态
|
|
|
+ _this.$set(row, 'loading', true)
|
|
|
+ getauth('container/batchdetaillog/containerlog/?batchlog_id=' + row.id)
|
|
|
+ .then((res) => {
|
|
|
+ // 将数据存储到当前行的 containers 属性
|
|
|
+
|
|
|
+ _this.$set(row, 'containers', res)
|
|
|
+ console.log('当前的', row.containers)
|
|
|
+ })
|
|
|
+ .catch((err) => {
|
|
|
+ _this.$q.notify({ message: err.detail, color: 'negative' })
|
|
|
+ })
|
|
|
+ .finally(() => {
|
|
|
+ row.loading = false // 关闭加载状态
|
|
|
+ })
|
|
|
+ }
|
|
|
+ },
|
|
|
+ getlog () {
|
|
|
+ // console.log(this.table_list)
|
|
|
+ console.log('当前loading状态:', this.loading)
|
|
|
+ },
|
|
|
+ getList (params = {}) {
|
|
|
+ var _this = this
|
|
|
+ _this.loading = true
|
|
|
+ // 合并基础参数
|
|
|
+ const baseParams = {
|
|
|
+ page: _this.current,
|
|
|
+ page_size: _this.pagination.rowsPerPage
|
|
|
+ }
|
|
|
+
|
|
|
+ // 创建URLSearchParams处理参数
|
|
|
+ const queryParams = new URLSearchParams({
|
|
|
+ ...baseParams,
|
|
|
+ ...params
|
|
|
+ })
|
|
|
+ console.log(queryParams)
|
|
|
+ // 过滤空值参数
|
|
|
+ Array.from(queryParams.entries()).forEach(([key, value]) => {
|
|
|
+ if (value === '' || value === null || value === undefined) {
|
|
|
+ queryParams.delete(key)
|
|
|
+ }
|
|
|
+ })
|
|
|
+
|
|
|
+ postauth(`${_this.pathname}?${queryParams}`)
|
|
|
+ .then((res) => {
|
|
|
+ _this.table_list = res.results.map((item) => ({
|
|
|
+ ...item,
|
|
|
+ expand: false,
|
|
|
+ containers: [
|
|
|
+ // {
|
|
|
+ // id: 0,
|
|
|
+ // container_code: 0,
|
|
|
+ // current_location: '0',
|
|
|
+ // goods_qty: 0,
|
|
|
+ // class: 0
|
|
|
+ // }
|
|
|
+ ],
|
|
|
+ loading: false
|
|
|
+ }))
|
|
|
+ _this.total = res.count
|
|
|
+ _this.max = Math.ceil(res.count / _this.pagination.rowsPerPage) || 0
|
|
|
+ _this.pathname_previous = res.previous
|
|
|
+ _this.pathname_next = res.next
|
|
|
+ })
|
|
|
+ .catch((err) => {
|
|
|
+ _this.$q.notify({
|
|
|
+ message: err.detail,
|
|
|
+ icon: 'close',
|
|
|
+ color: 'negative'
|
|
|
+ })
|
|
|
+ })
|
|
|
+ .finally(() => {
|
|
|
+ _this.loading = false
|
|
|
+ })
|
|
|
+ },
|
|
|
+ changePageEnter () {
|
|
|
+ if (Number(this.paginationIpt) < 1) {
|
|
|
+ this.current = 1
|
|
|
+ this.paginationIpt = 1
|
|
|
+ } else if (Number(this.paginationIpt) > this.max) {
|
|
|
+ this.current = this.max
|
|
|
+ this.paginationIpt = this.max
|
|
|
+ } else {
|
|
|
+ this.current = Number(this.paginationIpt)
|
|
|
+ }
|
|
|
+ this.getSearchList(this.current)
|
|
|
+ },
|
|
|
+
|
|
|
+ // 修改搜索方法以包含过滤条件
|
|
|
+ getSearchList (page = 1) {
|
|
|
+ this.current = page
|
|
|
+ this.paginationIpt = page
|
|
|
+
|
|
|
+ // 构建过滤参数
|
|
|
+ const filterParams = {}
|
|
|
+ for (const [key, value] of Object.entries(this.filterModels)) {
|
|
|
+ if (value !== null && value !== '') {
|
|
|
+ filterParams[key] = value
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ this.getList({
|
|
|
+ number__icontains: this.filter,
|
|
|
+ change_time__range: this.date_range,
|
|
|
+ ...filterParams, // 添加过滤条件
|
|
|
+ ...this.filterdata // 添加其他过滤条件
|
|
|
+ })
|
|
|
+ },
|
|
|
+
|
|
|
+ getListPrevious () {
|
|
|
+ var _this = this
|
|
|
+ if (LocalStorage.has('auth')) {
|
|
|
+ postauth(_this.pathname_previous, {})
|
|
|
+ .then((res) => {
|
|
|
+ _this.table_list = res.results
|
|
|
+ _this.pathname_previous = res.previous
|
|
|
+ _this.pathname_next = res.next
|
|
|
+ })
|
|
|
+ .catch((err) => {
|
|
|
+ _this.$q.notify({
|
|
|
+ message: err.detail,
|
|
|
+ icon: 'close',
|
|
|
+ color: 'negative'
|
|
|
+ })
|
|
|
+ })
|
|
|
+ } else {
|
|
|
+ }
|
|
|
+ },
|
|
|
+ getListNext () {
|
|
|
+ var _this = this
|
|
|
+ if (LocalStorage.has('auth')) {
|
|
|
+ postauth(_this.pathname_next, {})
|
|
|
+ .then((res) => {
|
|
|
+ _this.table_list = res.results
|
|
|
+
|
|
|
+ _this.pathname_previous = res.previous
|
|
|
+ _this.pathname_next = res.next
|
|
|
+ })
|
|
|
+ .catch((err) => {
|
|
|
+ _this.$q.notify({
|
|
|
+ message: err.detail,
|
|
|
+ icon: 'close',
|
|
|
+ color: 'negative'
|
|
|
+ })
|
|
|
+ })
|
|
|
+ }
|
|
|
+ },
|
|
|
+ reFresh () {
|
|
|
+ var _this = this
|
|
|
+ this.filterdata = {}
|
|
|
+ this.filterModels = {
|
|
|
+ bound_department: null
|
|
|
+ }
|
|
|
+ _this.getSearchList()
|
|
|
+ },
|
|
|
+
|
|
|
+ updateProxy () {
|
|
|
+ var _this = this
|
|
|
+ _this.proxyDate = _this.date
|
|
|
+ }
|
|
|
+ },
|
|
|
+ created () {
|
|
|
+ var _this = this
|
|
|
+ if (LocalStorage.has('openid')) {
|
|
|
+ _this.openid = LocalStorage.getItem('openid')
|
|
|
+ } else {
|
|
|
+ _this.openid = ''
|
|
|
+ LocalStorage.set('openid', '')
|
|
|
+ }
|
|
|
+ if (LocalStorage.has('login_name')) {
|
|
|
+ _this.login_name = LocalStorage.getItem('login_name')
|
|
|
+ } else {
|
|
|
+ _this.login_name = ''
|
|
|
+ LocalStorage.set('login_name', '')
|
|
|
+ }
|
|
|
+ if (LocalStorage.has('auth')) {
|
|
|
+ const timeStamp = Date.now()
|
|
|
+ const formattedString = date.formatDate(timeStamp, 'YYYY/MM/DD')
|
|
|
+ _this.date = formattedString
|
|
|
+ console.log(_this.date)
|
|
|
+ _this.authin = '1'
|
|
|
+ _this.getList()
|
|
|
+ } else {
|
|
|
+ _this.authin = '0'
|
|
|
+ }
|
|
|
+ },
|
|
|
+ mounted () {
|
|
|
+ var _this = this
|
|
|
+ if (_this.$q.platform.is.electron) {
|
|
|
+ _this.height = String(_this.$q.screen.height - 290) + 'px'
|
|
|
+ } else {
|
|
|
+ _this.height = _this.$q.screen.height - 290 + '' + 'px'
|
|
|
+ }
|
|
|
+ // _this.timer = setInterval(() => {
|
|
|
+ // _this.getlog()
|
|
|
+ // }, 1000)
|
|
|
+ },
|
|
|
+ updated () {},
|
|
|
+ destroyed () {},
|
|
|
+ // 在 watch 或方法中添加调试代码
|
|
|
+ watch: {
|
|
|
+ createDate1 (val) {
|
|
|
+ if (val) {
|
|
|
+ if (val.to) {
|
|
|
+ this.createDate2 = `${val.from} - ${val.to}`
|
|
|
+ this.date_range = `${val.from},${val.to} `
|
|
|
+
|
|
|
+ // this.downloadhUrl = this.pathname + 'filelist/?' + 'change_time__range=' + this.date_range
|
|
|
+ } else {
|
|
|
+ this.createDate2 = `${val}`
|
|
|
+ this.dateArray = val.split('/')
|
|
|
+ this.searchUrl =
|
|
|
+ this.pathname +
|
|
|
+ '?' +
|
|
|
+ 'change_time__year=' +
|
|
|
+ this.dateArray[0] +
|
|
|
+ '&' +
|
|
|
+ 'change_time__month=' +
|
|
|
+ this.dateArray[1] +
|
|
|
+ '&' +
|
|
|
+ 'change_time__day=' +
|
|
|
+ this.dateArray[2]
|
|
|
+ // this.downloadhUrl = this.pathname + 'filelist/?' + 'change_time__year=' + this.dateArray[0] + '&' + 'change_time__month=' + this.dateArray[1] + '&' + 'change_time__day=' + this.dateArray[2]
|
|
|
+ }
|
|
|
+ this.date_range = this.date_range.replace(/\//g, '-')
|
|
|
+
|
|
|
+ this.getSearchList()
|
|
|
+ this.$refs.qDateProxy.hide()
|
|
|
+ } else {
|
|
|
+ this.createDate2 = ''
|
|
|
+ this.date_range = ''
|
|
|
+ this.getSearchList()
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+</script>
|
|
|
+<style scoped>
|
|
|
+/* 添加在 <style> 中 */
|
|
|
+.q-date__calendar-item--selected {
|
|
|
+ transition: all 0.3s ease;
|
|
|
+ background-color: #1976d2 !important;
|
|
|
+}
|
|
|
+
|
|
|
+.q-date__range {
|
|
|
+ background-color: rgba(25, 118, 210, 0.1);
|
|
|
+}
|
|
|
+
|
|
|
+.custom-title {
|
|
|
+ font-size: 0.9rem; /* 推荐使用相对单位 */
|
|
|
+ font-weight: 500;
|
|
|
+}
|
|
|
+/* 添加以下样式 */
|
|
|
+.custom-timeline {
|
|
|
+ --q-timeline-color: #e0e0e0; /* 覆盖时间轴线颜色变量 */
|
|
|
+}
|
|
|
+
|
|
|
+.custom-node .q-timeline__dot {
|
|
|
+ background: #485573 !important; /* 节点填充色 */
|
|
|
+ border: 2px solid #5c6b8c !important; /* 节点边框色 */
|
|
|
+}
|
|
|
+
|
|
|
+.custom-node .q-timeline__content {
|
|
|
+ color: #485573; /* 文字颜色 */
|
|
|
+}
|
|
|
+</style>
|