feat: 库存管理
出库管理、采购管理、报废管理 新增时物品查询增加机构限制
18个文件已修改
599 ■■■■■ 已修改文件
admin-web/src/main.js 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
admin-web/src/store/modules/user.js 4 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
admin-web/src/styles/store.scss 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
admin-web/src/utils/base.js 18 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
admin-web/src/views/dashboard/index.vue 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
admin-web/src/views/departmentitem/itemdis/distribution/detail.vue 23 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
admin-web/src/views/departmentitem/itemdis/distribution/edit.vue 58 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
admin-web/src/views/departmentitem/itemdis/distribution/index.vue 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
admin-web/src/views/stock/accessStock/outbound/detail.vue 65 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
admin-web/src/views/stock/accessStock/outbound/edit.vue 59 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
admin-web/src/views/stock/index.scss 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
admin-web/src/views/stock/ledger/inventoryAlert/edit.vue 63 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
admin-web/src/views/stock/procure/purchaseOrder/edit.vue 43 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
admin-web/src/views/stock/scrap/itemScrapping/detail.vue 4 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
admin-web/src/views/stock/scrap/itemScrapping/edit.vue 56 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
admin-web/src/views/stock/transfer/transferApplication/detail.vue 63 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
admin-web/src/views/stock/transfer/transferApplication/edit.vue 62 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
admin-web/src/views/stock/transfer/transferissue/detail.vue 71 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
admin-web/src/main.js
@@ -33,7 +33,7 @@
import './directive/num';
import searchInfo from '@/utils/changeColor';
import exportExcel from '@/utils/exportExcel'; // 导出
import {downLoad, previewDoc} from '@/utils/base';
import {downLoad} from '@/utils/base';
import '@/mock'
Vue.config.devtools = true;
@@ -44,7 +44,6 @@
});
Vue.prototype.exportExcelUtils = exportExcel;
Vue.prototype.previewDoc = previewDoc;
Vue.prototype.downLoad = downLoad;
Vue.prototype.$searchInfo = searchInfo;
Vue.use(VueLazyload, {
admin-web/src/store/modules/user.js
@@ -102,8 +102,10 @@
          commit('SET_USERINFO', data.userInfo);
          getCurInfo().then(res=>{
            commit('SET_USER_INFO',res)
          })
          resolve();
                    }).catch((error) => {
                        reject(error);
                    })
        })
        .catch((error) => {
          reject(error);
admin-web/src/styles/store.scss
@@ -187,6 +187,8 @@
    cursor: pointer;
    .img {
      width: 100%;
      height: 100%;
      object-fit: cover;
    }
  }
admin-web/src/utils/base.js
@@ -23,24 +23,6 @@
  return getBaseUrl() + '/pc/fin/file/uploadMore'
}
// 预览文件
export function previewDoc(obj) {
  const routeUrl = this.$router.resolve({url: '/webOffice/preview'})
  let url = obj.url
  const wordLIst = ['doc', 'docm', 'docx', 'docxf', 'dot', 'dotm', 'dotx', 'epub', 'fodt', 'fb2', 'htm', 'html', 'mht', 'odt', 'oform', 'ott', 'oxps', 'pdf', 'rtf', 'txt', 'djvu', 'xml', 'xps', 'csv', 'fods', 'ods', 'ots', 'xls', 'xlsb', 'xlsm', 'xlsx', 'xlt', 'xltm', 'xltx', 'fodp', 'odp', 'otp', 'pot', 'potm', 'potx', 'pps', 'ppsm', 'ppsx', 'ppt', 'pptm', 'pptx']
  const arr = url.split('.')
  if (arr.length === 2) {
    if (wordLIst.includes(arr[arr.length - 1])) {
      if (obj.url.indexOf('http') !== 0) {
        url = SettingIplatform.ftpUrl + url
      }
      const newWindow = window.open(routeUrl.href + '?url=' + encodeURIComponent(url) + '&docName=' + encodeURIComponent(encodeURIComponent(obj.fileName)), '_blank')
      if (newWindow) newWindow.opener = null
    } else {
      Message.warning('文件格式不支持预览!')
    }
  }
}
// 下载文件
export function downLoad(obj) {
admin-web/src/views/dashboard/index.vue
@@ -182,6 +182,7 @@
    };
  },
  created() {
    console.log(this.userInfo)
    this.getAuditList()
    this.getWarningList()
    getGoodsNumPrice().then(res => {
admin-web/src/views/departmentitem/itemdis/distribution/detail.vue
@@ -1,5 +1,5 @@
<template>
  <win-lg class="stock-detail" :title="setting.title" @close="close" :width="'800px'" :loading="loading">
  <win-md class="stock-detail" :title="setting.title" @close="close" :width="'800px'" :loading="loading">
    <el-row :gutter="20">
      <el-col :span="8">
        <span>分发单号:</span>
@@ -110,11 +110,11 @@
        />
      </span>
    </div>
  </win-lg>
  </win-md>
</template>
<script>
import {transferDetail} from '@/api/stock/transfer';
import winLg from '@/components/win/win-lg';
import winMd from '@/components/win/win-md';
import * as DateFormatter from '@/utils/DateFormatter';
import {getDownUrl} from '@/utils/base';
import Viewer from 'viewerjs';
@@ -129,16 +129,17 @@
      return de
    }
  },
  components: { winLg },
  components: {winMd},
  props: {
    setting: {
      type: Object,
      default: () => {},
      default: () => {
      },
    },
  },
  data() {
    return {
      loading:false,
      loading: true,
      fileList: [],
      detail: {
        baseCategoryName: '',
@@ -167,6 +168,7 @@
  created() {
    transferDetail({ id: this.setting.id }).then((res) => {
      this.detail = res;
      this.loading = false
      this.fileList = this.detail.procureDoc ? JSON.parse(this.detail.procureDoc) : [];
      this.$nextTick(() => {
        this.initPreviewImg();
@@ -226,18 +228,11 @@
</script>
<style lang="scss" scoped>
@import url(../../../../styles/store.scss);
.card3 {
  padding: 10px;
  margin-top: 10px;
  border-radius: 2px;
  background: #ffffff;
}
.img-box{
  width: 100px;
  height: 100px;
}
.img-box .img{
  width: 100px;
  height: 100px;
}
</style>
admin-web/src/views/departmentitem/itemdis/distribution/edit.vue
@@ -1,11 +1,11 @@
<template>
  <win-md class="stock-edit" title="物品分发" @close="close" width="900px">
    <el-form v-loading="loading" class="form" ref="ruleForm" :model="formData" :rules="rules" label-width="120px">
  <win-md class="stock-edit" title="物品分发" @close="close" width="900px" :loading="loading">
    <el-form class="form" ref="ruleForm" :model="formData" :rules="rules" label-width="120px">
      <div class="main-w">
        <el-row :gutter="24" class="headerHeight">
          <el-col :span="12">
            <el-form-item label="部门" prop="departmentId">
              <el-select ref="department" v-model="formData.departmentId" placeholder="请选择" style="width: 100%">
              <el-select ref="department" v-model="formData.departmentId" clearable placeholder="请选择" style="width: 100%">
                <el-option v-for="item in departmentOptions" :key="item.id" :label="item.name" :value="item.id"
                           clearable/>
              </el-select>
@@ -75,7 +75,7 @@
              >
                <el-select
                    v-model="goodsItem.baseGoodsTemplateId"
                    placeholder="请选择物品"
                    :placeholder="goodsItem.baseCategoryId?'请选择物品':'请先选择物品分类'"
                    filterable
                    clearable
                    :disabled="!goodsItem.baseCategoryId"
@@ -97,11 +97,11 @@
              <el-form-item
                  label="规格型号"
                  :prop="`transferGoods.${goodsIndex}.modelsIds`"
                  :rules="{required: true,message: '请选择',trigger: 'change',}">
                  :rules="{required: true,message: '请选择规格型号',trigger: 'change',}">
                <el-select
                    v-model="goodsItem.modelsIds"
                    multiple
                    placeholder="请选择物品规格型号"
                    :placeholder="goodsItem.baseCategoryId?'请选择规格型号':'请先选择物品名称'"
                    :disabled="!goodsItem.baseCategoryId"
                    @change="modelChange($event, goodsIndex)"
                    @remove-tag="modelRemoveTag($event, goodsIndex)"
@@ -290,17 +290,7 @@
        }
        callback();
      },
      loading: false,
      buyTypeOptions: [
        {
          label: '集采',
          value: '1',
        },
        {
          label: '自采',
          value: '2',
        },
      ],
      loading: true,
      fileList: [],
      departmentOptions: [], // 部门列表
      categoryOptions: [], // 物品分类列表
@@ -342,7 +332,7 @@
        createTime: [{required: true, message: '请选择分发时间', trigger: 'change'}],
        procureDoc: [{required: true, message: '请上传审批手续', trigger: 'change'}],
        baseCategoryIds: [{required: true, message: '请选择', trigger: 'change'}],
        baseGoodsTemplateId: [{validator: checkGoodsTemplateId, trigger: ['blur', 'change']}],
        baseGoodsTemplateId: [{required: true, message: '请选择', trigger: 'change'},{validator: checkGoodsTemplateId, trigger: ['blur', 'change']}],
        modelsIds: [{required: true, message: '请选择', trigger: 'change'}],
        transferGoods: [
          {
@@ -369,7 +359,6 @@
        title: '上传',
        max: 20, // 最大大小,单位M
        num: 10, // 支持上传图片个数
        accept: '.jpg,.png', // 限制格式
        tip: '', // 提示 默认:`只能上传${this.defaultSettings.num}个${this.defaultSettings.accept}文件,且不超过${this.defaultSettings.max}kb`
        uploadUrl: getUploadUrl(), // 上传路径
        multiple: true, // 是否支持批量上传
@@ -386,34 +375,13 @@
  },
  methods: {
    async init() {
      this.getdeptmentList();
      this.getgoodsTemplate();
      this.getgoodsModel();
      await this.getdeptmentList();
      // 获取物品分类列表
      const treeRes = await getTree();
      this.categoryOptions = this.removeEmptyChildren(treeRes);
      /*if (this.setting.id) {
        const detail = await procureDetail({ id: this.setting.id });
        this.formData = Object.assign(this.formData, detail);
        if (this.formData.procureDoc) {
          this.fileList = JSON.parse(this.formData.procureDoc);
        }
        this.$set(this.formData, 'buyType', this.formData.buyType.toString());
        this.formData.procureTime = this.formData.procureTime.toString();
        this.formData.transferGoods.map((item, index) => {
          this.$set(
            this.formData.transferGoods[index],
            'modelsIds',
            item.models.map((v) => v.baseGoodsModelsId),
          );
          this.getgoodsTemplate(item.baseCategoryId, index);
          this.getgoodsModel(item.baseGoodsTemplateId, index);
          item.models.forEach((child, childIndex) => {
            this.$set(this.formData.transferGoods[index].models[childIndex], 'priceYuan', child.price / 100);
          });
          return item;
        });
      }*/
      this.loading = false
      this.getgoodsTemplate();
      this.getgoodsModel();
    },
    // 获取入库仓库列表
@@ -568,7 +536,6 @@
    // 提交
    handleSubmit() {
      console.log('formData', this.formData);
      if(this.loading) return
      this.$refs['ruleForm'].validate((valid) => {
        if (valid) {
          this.formData.transferGoods.map(goods => {
@@ -585,6 +552,7 @@
          this.formData.departmentName = this.$refs.department.selected.currentLabel
          this.formData.outAgencyId = this.userInfo.tenantId
          if(this.loading) return
          this.loading = true
          transferAdd(this.formData)
              .then((res) => {
admin-web/src/views/departmentitem/itemdis/distribution/index.vue
@@ -172,6 +172,7 @@
        qryType: 1,
        pageNum: this.pageNum,
        pageSize: this.pageSize,
        outAgencyId: this.userInfo.tenantId,
        ...this.filterFrom,
      }).then((res) => {
        this.list = res.datas;
admin-web/src/views/stock/accessStock/outbound/detail.vue
@@ -24,10 +24,12 @@
        <span>{{ detail.dealTime | formatTime }}</span>
      </el-col>
    </el-row>
    <el-row v-if="detail.procureDoc" :gutter="20" style="margin-top: 20px">
    <el-row v-if="fileList && fileList.length" :gutter="20" style="margin-top: 20px">
      <el-col class="img-row" :span="24">
        <span>出库手续:</span>
        <div class="img-box"></div>
        <div class="img-box" v-for="(item, index) in fileList" :key="index" @click="handlePreview(item)">
          <img class="img" :src="getUrl(item.path)" alt=""/>
        </div>
      </el-col>
    </el-row>
    <div class="goods-card" v-for="(goodsItem, goodsIndex) in detail.fromOutputGoods" :key="goodsIndex">
@@ -64,6 +66,17 @@
        </el-table-column>
      </el-table>
    </div>
    <div id="uploadPreviewImages" style="display: none">
      <span v-for="(src, index) in fileList" :key="index">
        <img
            v-if="checkImg(src.name)"
            class="v-img"
            :src="src.url"
            :alt="src.name"
            style="width: 100px; height: 100px"
        />
      </span>
    </div>
  </win-md>
</template>
<script>
@@ -71,6 +84,11 @@
import winMd from '@/components/win/win-md';
import * as DateFormatter from '@/utils/DateFormatter';
import {getDownUrl} from "@/utils/base";
import Viewer from 'viewerjs';
import 'viewerjs/dist/viewer.css';
let viewer = null;
export default {
  components: { winMd },
@@ -83,6 +101,7 @@
  data() {
    return {
      loading:true,
      fileList: [],
      detail: {
        categoryName: '',
        businessFormCode: '',
@@ -107,10 +126,50 @@
  created() {
    outputDetail({ id: this.setting.id }).then((res) => {
      this.detail = res;
      this.loading = false
      this.fileList = this.detail.doc ? JSON.parse(this.detail.doc) : [];
      this.loading = false;
      this.$nextTick(() => {
        this.initPreviewImg();
      });
    });
  },
  methods: {
    initPreviewImg() {
      if (viewer != null) {
        viewer.destroy();
      }
      const ViewerDom = document.querySelector('#uploadPreviewImages');
      viewer = new Viewer(ViewerDom, {});
    },
    handlePreview(file) {
      if (!this.checkImg(file.name)) {
        return false;
      }
      let index = 0;
      for (let i = 0; i < this.fileList.length; i++) {
        const f = this.fileList[i];
        if (this.checkImg(f.name)) {
          if (file.id == f.id) {
            break;
          }
          index++;
        }
      }
      viewer.view(index);
    },
    checkImg(name) {
      const suffix = name.substring(name.lastIndexOf('.'), name.length);
      const imgArray = ['.jpg', '.jpeg', '.png', '.bmp'];
      return imgArray.indexOf(suffix) >= 0;
    },
    getUrl(path) {
      if (path.substr(0, 7).toLowerCase() == 'http://' || path.substr(0, 8).toLowerCase() == 'https://') {
        return path;
      } else {
        return getDownUrl() + path;
      }
    },
    close() {
      this.$emit('close')
    },
admin-web/src/views/stock/accessStock/outbound/edit.vue
@@ -5,7 +5,7 @@
        <el-row :gutter="24" class="headerHeight">
          <el-col :span="12">
            <el-form-item label="出库仓库" prop="warehouseId">
              <el-select v-model="formData.warehouseId" placeholder="请选择" style="width: 100%">
              <el-select v-model="formData.warehouseId" placeholder="请选择" clearable style="width: 100%">
                <el-option
                  v-for="item in warehouseOptions"
                  :key="item.id"
@@ -20,6 +20,7 @@
              <el-date-picker
                v-model="formData.dealTime"
                type="datetime"
                clearable
                value="yyyy-MM-dd HH:mm:ss"
                value-format="yyyyMMddHHmmss"
                placeholder="请选择日期"
@@ -31,7 +32,7 @@
        </el-row>
        <el-row :gutter="24" class="headerHeight">
          <el-col :span="24">
            <el-form-item label="出库手续" prop="procureDoc">
            <el-form-item label="出库手续" prop="doc">
              <upload ref="uploadRef" :settings="uploadSettings" @on-change="uploadChange"></upload>
            </el-form-item>
          </el-col>
@@ -41,7 +42,7 @@
            <el-col :span="12">
              <el-form-item
                label="物品分类"
                :prop="`goods[${goodsIndex}].baseCategoryIds`"
                :prop="`goods.${goodsIndex}.baseCategoryId`"
                :rules="{
                  required: true,
                  message: '请选择',
@@ -49,9 +50,13 @@
                }"
              >
                <el-cascader
                  v-model="goodsItem.baseCategoryIds"
                  v-model="goodsItem.baseCategoryId"
                  :options="categoryOptions"
                  :props="{ value: 'id' }"
                  placeholder="请选择物品分类"
                  :props="{ value: 'id',emitPath: false }"
                  :show-all-levels="false"
                  filterable
                  clearable
                  @change="categoryChange($event, goodsIndex)"
                  style="width: 100%"
                ></el-cascader>
@@ -60,13 +65,14 @@
            <el-col :span="12">
              <el-form-item
                label="物品名称"
                :prop="`goods[${goodsIndex}].baseGoodsTemplateId`"
                :prop="`goods.${goodsIndex}.baseGoodsTemplateId`"
                :rules="rules.baseGoodsTemplateId"
              >
                <el-select
                  v-model="goodsItem.baseGoodsTemplateId"
                  placeholder="请先择物品分类"
                  :placeholder="goodsItem.baseCategoryId?'请选择物品':'请先选择物品分类'"
                  filterable
                  clearable
                  :disabled="!goodsItem.baseCategoryId"
                  style="width: 100%"
                  @change="goodsTemplateChange($event, goodsIndex)"
@@ -85,20 +91,22 @@
            <el-col :span="12">
              <el-form-item
                label="规格型号"
                :prop="`goods[${goodsIndex}].modelsIds`"
                :prop="`goods.${goodsIndex}.modelsIds`"
                :rules="{
                  required: true,
                  message: '请选择',
                  message: '请选择规格型号',
                  trigger: 'change',
                }"
              >
                <el-select
                  v-model="goodsItem.modelsIds"
                  multiple
                  placeholder="请先择物品名称"
                  clearable
                  :placeholder="goodsItem.baseCategoryId?'请选择规格型号':'请先选择物品名称'"
                  :disabled="!goodsItem.baseCategoryId"
                  @change="modelChange($event, goodsIndex)"
                  @remove-tag="modelRemoveTag($event, goodsIndex)"
                  @clear="modelRemoveTag(-1, goodsIndex)"
                  style="width: 100%"
                >
                  <el-option
@@ -131,8 +139,7 @@
              <template slot-scope="scope">
                <el-form-item
                  label-width="0"
                  style="margin-bottom: 0"
                  :prop="`goods[${goodsIndex}].models[${scope.$index}].counts`"
                  :prop="`goods.${goodsIndex}.models.${scope.$index}.counts`"
                  :rules="rules.counts"
                >
                  <el-input
@@ -213,7 +220,7 @@
      formData: {
        warehouseId: '', // 出库仓库id
        dealTime: '', // 出库时间
        procureDoc: '',
        doc: '',
        goods: [],
      },
      goodsItem: {
@@ -233,13 +240,12 @@
        unit: null, //单位
      },
      rules: {
        warehouseId: [{ required: true, message: '请选择', trigger: 'change' }],
        dealTime: [{ required: true, message: '请选择', trigger: 'change' }],
        buyType: [{ required: true, message: '请选择', trigger: 'change' }],
        baseCategoryIds: [{ required: true, message: '请选择', trigger: 'change' }],
        baseGoodsTemplateId: [{ validator: checkGoodsTemplateId, trigger: ['blur', 'change'] }],
        modelsIds: [{ required: true, message: '请选择', trigger: 'change' }],
        warehouseId: [{ required: true, message: '请选择仓库', trigger: 'change' }],
        dealTime: [{ required: true, message: '请选择时间', trigger: 'change' }],
        doc: [{required: true, message: '请上传审批手续', trigger: 'change'}],
        baseCategoryId: [{ required: true, message: '请选择物品分类', trigger: 'change' }],
        baseGoodsTemplateId: [{ required: true, message: '请选择物品', trigger: 'change' },{ validator: checkGoodsTemplateId, trigger: ['blur', 'change'] }],
        modelsIds: [{ required: true, message: '请选择规格型号', trigger: 'change' }],
        counts: [{ required: true, message: '请输入', trigger: 'change' }],
      },
@@ -247,7 +253,6 @@
        title: '上传',
        max: 20, // 最大大小,单位M
        num: 10, // 支持上传图片个数
        accept: '.jpg,.png', // 限制格式
        tip: '', // 提示 默认:`只能上传${this.defaultSettings.num}个${this.defaultSettings.accept}文件,且不超过${this.defaultSettings.max}kb`
        uploadUrl: getUploadUrl(), // 上传路径
        multiple: true, // 是否支持批量上传
@@ -304,7 +309,7 @@
    // 获取物品名称列表
    async getgoodsTemplate(id, index) {
      await goodsTemplate({ categoryId: id || '' }).then((res) => {
      await goodsTemplate({ agencyId: this.userInfo.tenantId, categoryId: id || '' }).then((res) => {
        if (index || index == 0) {
          this.$set(this.formData.goods[index], 'goodsOptions', res);
        } else {
@@ -350,10 +355,8 @@
      this.formData.goods[index].modelsOptions = [];
      this.formData.goods[index].modelsIds = [];
      this.formData.goods[index].models = [];
      this.formData.goods[index].baseCategoryId = e[e.length - 1];
      // 根据选中分类请求物品名称列表
      this.getgoodsTemplate(e[e.length - 1], index);
      this.getgoodsTemplate(e, index);
    },
    // 物品名称列表选择
@@ -390,6 +393,10 @@
    // 规格型号移除
    modelRemoveTag(e, index) {
      if(e===-1){
        this.formData.goods[index].models = []
        return
      }
      let arr = this.formData.goods[index].models;
      let delIndex = arr.findIndex((v) => v.baseGoodsModelsId == e);
      this.formData.goods[index].models.splice(delIndex, 1);
@@ -398,7 +405,7 @@
    // 上传
    uploadChange() {
      let arr = this.$refs.uploadRef.fileList;
      this.formData.procureDoc = JSON.stringify(arr);
      this.formData.doc = JSON.stringify(arr);
    },
    // 点击新增物品
admin-web/src/views/stock/index.scss
@@ -187,12 +187,13 @@
    cursor: pointer;
    .img {
      width: 100%;
      height: 100%;
      object-fit: cover;
    }
  }
  .goods-card {
    position: relative;
    background: #f6f6f6;
    padding: 20px;
    box-sizing: border-box;
    border-radius: 4px;
admin-web/src/views/stock/ledger/inventoryAlert/edit.vue
@@ -1,12 +1,12 @@
<template>
  <win-md :title="`${setting.title}预警设置`" @close="close" :width="'800px'">
  <win-md :title="`${setting.title}预警设置`" @close="close" :width="'800px'" :loading="loading">
    <el-form ref="ruleForm" :model="formData" :rules="rules" class="demo-ruleForm" label-width="100px">
      <el-row :gutter="24">
        <el-col :span="12">
          <el-form-item label="入库仓库" prop="baseWarehouseId">
          <el-form-item label="预警仓库" prop="baseWarehouseId">
            <el-select
              v-model="formData.baseWarehouseId"
              placeholder="请选择"
                placeholder="请选择预警仓库"
              style="width: 100%"
              :disabled="type == 'edit'"
            >
@@ -15,11 +15,14 @@
          </el-form-item>
        </el-col>
        <el-col :span="12">
          <el-form-item label="物品分类" prop="baseCategoryIds">
          <el-form-item label="物品分类" prop="baseCategoryId">
            <el-cascader
              v-model="formData.baseCategoryIds"
                v-model="formData.baseCategoryId"
              :options="categoryOptions"
              :props="{ value: 'id' }"
                :props="{ value: 'id',emitPath: false }"
                :show-all-levels="false"
                filterable
                clearable
              @change="categoryChange"
              style="width: 100%"
              :disabled="type == 'edit'"
@@ -32,8 +35,9 @@
          <el-form-item label="物品名称" prop="baseGoodsTemplateId">
            <el-select
              :value="formData.baseGoodsTemplateId"
              placeholder="请先择物品分类"
                :placeholder="formData.baseCategoryId?'请选择物品':'请先选择物品分类'"
              filterable
                clearable
              :disabled="!formData.baseCategoryId || type == 'edit'"
              @change="goodsTemplateChange"
              style="width: 100%"
@@ -52,10 +56,12 @@
            <el-select
              v-model="formData.modelsIds"
              multiple
                clearable
              :disabled="!formData.baseGoodsTemplateId || type == 'edit'"
              placeholder="请先择物品名称"
                :placeholder="formData.baseCategoryId?'请选择规格型号':'请先选择物品名称'"
              @change="modelChange"
              @remove-tag="modelRemoveTag"
                @clear="modelRemoveTag(-1)"
              style="width: 100%"
            >
              <el-option v-for="item in modelsOptions" :key="item.id" :label="item.modelName" :value="item.id" />
@@ -135,11 +141,13 @@
  props: {
    setting: {
      type: Object,
      default: () => {},
      default: () => {
      },
    },
  },
  data() {
    return {
      loading: true,
      type: '',
      warehouses: [], // 入库仓库列表
      agencyOptions: [], // 调拨机构
@@ -156,9 +164,10 @@
        models: [],
      },
      rules: {
        baseCategoryIds: [{ required: true, message: '请选择', trigger: 'blur' }],
        baseGoodsTemplateId: [{ required: true, message: '请选择', trigger: 'blur' }],
        modelsIds: [{ required: true, message: '请选择', trigger: 'blur' }],
        baseWarehouseId: [{required: true, message: '请选择预警仓库', trigger: 'change'}],
        baseCategoryId: [{required: true, message: '请选择物品分类', trigger: 'change'}],
        baseGoodsTemplateId: [{required: true, message: '请选择物品', trigger: 'change'}],
        modelsIds: [{required: true, message: '请选择规格型号', trigger: 'change'}],
        lowerLimit: [
          { required: true, message: '请输入', trigger: 'blur' },
          { type: 'number', message: '请输入数字值', trigger: 'blur' },
@@ -178,10 +187,11 @@
  },
  methods: {
    async init() {
      await this.getWarehouseList();
      await this.getCategoryTree();
      if (this.setting.id) {
        this.type = 'edit';
        const detail = await warningConfigGetById({ id: this.setting.id });
        await this.getCategoryTree();
        this.formData = Object.assign({}, detail);
        // 分类反显
        let res = await queryGoodsModelInfo({ baseGoodsModelsId: this.formData.baseGoodsModelsId });
@@ -193,10 +203,8 @@
        this.getgoodsModel(this.formData.baseGoodsTemplateId);
        this.formData.modelsIds = [this.formData.baseGoodsModelsId];
        this.getWarehouseList();
      } else {
        this.getWarehouseList();
        this.getCategoryTree();
      }
      this.loading = false
    },
    // 获取入库仓库列表
    getWarehouseList() {
@@ -247,23 +255,19 @@
    // 物品分类选择
    categoryChange(e) {
      if (!e) return;
      this.goodsTemplatelOptions = [];
      this.modelsOptions = [];
      this.formData.baseGoodsTemplateId = '';
      this.formData.modelsIds = [];
      this.formData.models = [];
      this.formData.baseCategoryId = e[e.length - 1];
      // 根据选中分类请求物品名称列表
      this.getgoodsTemplate(this.formData.baseCategoryId);
      this.getgoodsTemplate(e);
    },
    // 物品名称列表选择
    goodsTemplateChange(e) {
      this.formData.modelsIds = [];
      this.formData.models = [];
      this.formData.baseGoodsTemplateId = e;
      // 根据选中物品名称id获取规格型号列表
      this.getgoodsModel(e);
@@ -293,17 +297,24 @@
    // 规格型号移除
    modelRemoveTag(e) {
      if (e === -1) {
        this.formData.models = []
        return
      }
      let delIndex = this.formData.models.findIndex((v) => v.baseGoodsModelsId == e);
      this.formData.models.splice(delIndex, 1);
    },
    getEditInfo(id) {},
    getEditInfo(id) {
    },
    close() {
      this.$emit('close');
    },
    save() {
      this.$refs.ruleForm.validate((valid) => {
        if (valid) {
          if (this.loading) return
          this.loading = true;
          if (this.setting.id) {
            // 编辑接口
            const params = {
@@ -312,9 +323,13 @@
              upperLimit: this.formData.upperLimit,
            };
            warningConfigUpd(params).then((res) => {
              this.loading = false;
              this.$message.success('保存成功!');
              this.close();
              this.$emit('search');
            }).catch((err) => {
              this.loading = false;
              this.$message.error('保存失败');
            });
          } else {
            const params = {
@@ -324,9 +339,13 @@
              modelConfigStr: JSON.stringify(this.formData.models),
            };
            warningConfigAdd(params).then((res) => {
              this.loading = false;
              this.$message.success('保存成功!');
              this.close();
              this.$emit('search');
            }).catch((err) => {
              this.loading = false;
              this.$message.error('保存失败');
            });
          }
        } else {
admin-web/src/views/stock/procure/purchaseOrder/edit.vue
@@ -5,7 +5,7 @@
        <el-row :gutter="24" class="headerHeight">
          <el-col :span="12">
            <el-form-item label="入库仓库" prop="warehouseId">
              <el-select v-model="formData.warehouseId" placeholder="请选择" style="width: 100%">
              <el-select v-model="formData.warehouseId" placeholder="请选择" clearable style="width: 100%">
                <el-option v-for="item in warehouses" :key="item.id" :label="item.warehouseName" :value="item.id"/>
              </el-select>
            </el-form-item>
@@ -15,6 +15,7 @@
              <el-date-picker
                  v-model="formData.procureTime"
                  type="datetime"
                  clearable
                  value="yyyy-MM-dd HH:mm:ss"
                  value-format="yyyyMMddHHmmss"
                  placeholder="请选择日期"
@@ -45,17 +46,20 @@
            <el-col :span="12">
              <el-form-item
                  label="物品分类"
                  :prop="`procureGoods[${goodsIndex}].baseCategoryIds`"
                  :prop="`procureGoods.${goodsIndex}.baseCategoryId`"
                  :rules="{
                  required: true,
                  message: '请选择',
                  message: '请选择物品分类',
                  trigger: 'change',
                }"
              >
                <el-cascader
                    v-model="goodsItem.baseCategoryIds"
                    v-model="goodsItem.baseCategoryId"
                    :options="categoryOptions"
                    :props="{ value: 'id' }"
                    :props="{ value: 'id',emitPath: false }"
                    :show-all-levels="false"
                    filterable
                    clearable
                    @change="categoryChange($event, goodsIndex)"
                    style="width: 100%"
                ></el-cascader>
@@ -64,13 +68,14 @@
            <el-col :span="12">
              <el-form-item
                  label="物品名称"
                  :prop="`procureGoods[${goodsIndex}].baseGoodsTemplateId`"
                  :prop="`procureGoods.${goodsIndex}.baseGoodsTemplateId`"
                  :rules="rules.baseGoodsTemplateId"
              >
                <el-select
                    v-model="goodsItem.baseGoodsTemplateId"
                    placeholder="请先择物品分类"
                    :placeholder="goodsItem.baseCategoryId?'请选择物品':'请先选择物品分类'"
                    filterable
                    clearable
                    :disabled="!goodsItem.baseCategoryId"
                    style="width: 100%"
                    @change="goodsTemplateChange($event, goodsIndex)"
@@ -89,20 +94,22 @@
            <el-col :span="12">
              <el-form-item
                  label="规格型号"
                  :prop="`procureGoods[${goodsIndex}].modelsIds`"
                  :prop="`procureGoods.${goodsIndex}.modelsIds`"
                  :rules="{
                  required: true,
                  message: '请选择',
                  message: '请选择规格型号',
                  trigger: 'change',
                }"
              >
                <el-select
                    v-model="goodsItem.modelsIds"
                    multiple
                    placeholder="请先择物品名称"
                    clearable
                    :placeholder="goodsItem.baseCategoryId?'请选择规格型号':'请先选择物品名称'"
                    :disabled="!goodsItem.baseCategoryId"
                    @change="modelChange($event, goodsIndex)"
                    @remove-tag="modelRemoveTag($event, goodsIndex)"
                    @clear="modelRemoveTag(-1, goodsIndex)"
                    style="width: 100%"
                >
                  <el-option
@@ -305,7 +312,7 @@
        procureDoc: [{required: true, message: '请上传', trigger: 'change'}],
        baseCategoryIds: [{required: true, message: '请选择', trigger: 'change'}],
        baseGoodsTemplateId: [{validator: checkGoodsTemplateId, trigger: ['blur', 'change']}],
        baseGoodsTemplateId: [{required: true, message: '请选择', trigger: 'change'},{validator: checkGoodsTemplateId, trigger: ['blur', 'change']}],
        modelsIds: [{required: true, message: '请选择', trigger: 'change'}],
        priceYuan: [{validator: checkPrice, trigger: 'blur'}],
        counts: [{validator: checkCounts, trigger: 'blur'}],
@@ -332,6 +339,8 @@
  methods: {
    async init() {
      await this.getWarehouseList();
      await this.getgoodsTemplate();
      await this.getgoodsModel();
      // 获取物品分类列表
      const treeRes = await getTree();
@@ -359,9 +368,6 @@
          });
          return item;
        });
      } else {
        await this.getgoodsTemplate();
        await this.getgoodsModel();
      }
      this.loading = false;
    },
@@ -397,7 +403,7 @@
    // 获取物品名称列表
    async getgoodsTemplate(id, index) {
      await goodsTemplate({categoryId: id || ''}).then((res) => {
      await goodsTemplate({agencyId: this.userInfo.tenantId, categoryId: id || ''}).then((res) => {
        if (index || index == 0) {
          this.$set(this.formData.procureGoods[index], 'goodsOptions', res);
        } else {
@@ -444,9 +450,8 @@
      this.formData.procureGoods[index].modelsIds = [];
      this.formData.procureGoods[index].models = [];
      this.formData.procureGoods[index].baseCategoryId = e[e.length - 1];
      // 根据选中分类请求物品名称列表
      this.getgoodsTemplate(e[e.length - 1], index);
      this.getgoodsTemplate(e, index);
    },
    // 物品名称列表
@@ -475,6 +480,10 @@
    // 规格型号移除
    modelRemoveTag(e, index) {
      if(e===-1){
        this.formData.procureGoods[index].models = []
        return
      }
      let arr = this.formData.procureGoods[index].models;
      let delIndex = arr.findIndex((v) => v.baseGoodsModelsId == e);
      this.formData.procureGoods[index].models.splice(delIndex, 1);
admin-web/src/views/stock/scrap/itemScrapping/detail.vue
@@ -1,5 +1,5 @@
<template>
  <win-md class="stock-detail" :title="setting.title" @close="close" :width="'800px'">
  <win-md class="stock-detail" :title="setting.title" @close="close" :width="'800px'" :loading="loading">
    <el-row :gutter="20">
      <el-col :span="8">
        <span>报废单号:</span>
@@ -85,6 +85,7 @@
  },
  data() {
    return {
      loading: true,
      scrapReasonOptions: [],
      fileList: [],
      detail: {
@@ -110,6 +111,7 @@
  created() {
    scrappedDetail({ id: this.setting.id }).then((res) => {
      this.detail = res;
      this.loading = false
      this.fileList = this.detail.uploadFiles ? JSON.parse(this.detail.uploadFiles) : [];
      this.$nextTick(() => {
        this.initPreviewImg();
admin-web/src/views/stock/scrap/itemScrapping/edit.vue
@@ -1,6 +1,6 @@
<template>
  <win-md class="stock-edit" :title="`${setting.title}报废`" @close="close" :width="'800px'">
    <el-form class="form" ref="ruleForm" :model="formData" :rules="rules" label-width="120px">
    <el-form v-loading="loading" class="form" ref="ruleForm" :model="formData" :rules="rules" label-width="120px">
      <div class="main-w">
        <el-row :gutter="24" class="headerHeight">
          <el-col :span="12">
@@ -26,6 +26,7 @@
            <el-form-item label="报废时间" prop="dealTime">
              <el-date-picker
                v-model="formData.dealTime"
                clearable
                type="datetime"
                value="yyyy-MM-dd HH:mm:ss"
                value-format="yyyyMMddHHmmss"
@@ -48,17 +49,20 @@
            <el-col :span="12">
              <el-form-item
                label="物品分类"
                :prop="`scrappedGoodsInfo[${goodsIndex}].baseCategoryIds`"
                :prop="`scrappedGoodsInfo.${goodsIndex}.baseCategoryId`"
                :rules="{
                  required: true,
                  message: '请选择',
                  message: '请选择物品分类',
                  trigger: 'change',
                }"
              >
                <el-cascader
                  v-model="goodsItem.baseCategoryIds"
                  v-model="goodsItem.baseCategoryId"
                  :options="categoryOptions"
                  :props="{ value: 'id' }"
                  :props="{ value: 'id',emitPath: false }"
                  :show-all-levels="false"
                  filterable
                  clearable
                  @change="categoryChange($event, goodsIndex)"
                  style="width: 100%"
                ></el-cascader>
@@ -67,13 +71,14 @@
            <el-col :span="12">
              <el-form-item
                label="物品名称"
                :prop="`scrappedGoodsInfo[${goodsIndex}].baseGoodsTemplateId`"
                :prop="`scrappedGoodsInfo.${goodsIndex}.baseGoodsTemplateId`"
                :rules="rules.baseGoodsTemplateId"
              >
                <el-select
                  v-model="goodsItem.baseGoodsTemplateId"
                  placeholder="请先择物品分类"
                  :placeholder="goodsItem.baseCategoryId?'请选择物品':'请先选择物品分类'"
                  filterable
                  clearable
                  :disabled="!goodsItem.baseCategoryId"
                  style="width: 100%"
                  @change="goodsTemplateChange($event, goodsIndex)"
@@ -95,17 +100,19 @@
                :prop="`scrappedGoodsInfo[${goodsIndex}].modelsIds`"
                :rules="{
                  required: true,
                  message: '请选择',
                  message: '请选择规格型号',
                  trigger: 'change',
                }"
              >
                <el-select
                  v-model="goodsItem.modelsIds"
                  multiple
                  placeholder="请先择物品名称"
                  clearable
                  :placeholder="goodsItem.baseCategoryId?'请选择规格型号':'请先选择物品名称'"
                  :disabled="!goodsItem.baseCategoryId"
                  @change="modelChange($event, goodsIndex)"
                  @remove-tag="modelRemoveTag($event, goodsIndex)"
                  @clear="modelRemoveTag(-1, goodsIndex)"
                  style="width: 100%"
                >
                  <el-option
@@ -209,7 +216,7 @@
      callback();
    };
    return {
      loading: false,
      loading: true,
      fileList: [],
      warehouses: [], // 报废仓库列表
      categoryOptions: [], // 物品分类列表
@@ -236,8 +243,8 @@
        dealTime: [{ required: true, message: '请选择', trigger: 'change' }],
        buyType: [{ required: true, message: '请选择', trigger: 'change' }],
        uploadFiles: [{ required: true, message: '请上传', trigger: 'change' }],
        baseCategoryIds: [{ required: true, message: '请选择', trigger: 'change' }],
        baseGoodsTemplateId: [{ validator: checkGoodsTemplateId, trigger: ['blur', 'change'] }],
        baseCategoryId: [{ required: true, message: '请选择', trigger: 'change' }],
        baseGoodsTemplateId: [{ required: true, message: '请选择', trigger: 'change' },{ validator: checkGoodsTemplateId, trigger: ['blur', 'change'] }],
        modelsIds: [{ required: true, message: '请选择', trigger: 'change' }],
      },
@@ -261,9 +268,7 @@
  },
  methods: {
    async init() {
      this.getWarehouseList();
      this.getgoodsTemplate();
      this.getgoodsModel();
      await this.getWarehouseList();
      await this.getCategoryTree();
      this.formData.scrappedGoodsInfo.push(JSON.parse(JSON.stringify(this.goodsItem)));
      this.formData.operatorId = this.userInfo.id;
@@ -271,6 +276,9 @@
      this.formData.agencyId = this.userInfo.tenantId;
      this.formData.agencyName = this.userInfo.tenantName;
      this.formData.warehouseType = 0;
      this.getgoodsTemplate();
      this.getgoodsModel();
      this.loading = false
      getDicts('SCRAP_REASON').then((res) => {
        this.scrapReasonOptions = res;
      });
@@ -282,8 +290,8 @@
    },
    // 获取报废仓库列表
    getWarehouseList() {
      selectTenantWarehouse({ agencyId: this.userInfo.tenantId })
    async getWarehouseList() {
      await selectTenantWarehouse({ agencyId: this.userInfo.tenantId })
        .then((res) => {
          this.warehouses = res;
          if (this.warehouses.length && !this.formData.warehouseId) {
@@ -309,7 +317,7 @@
    // 获取物品名称列表
    getgoodsTemplate(id, index) {
      goodsTemplate({ categoryId: id || '' }).then((res) => {
      goodsTemplate({ agencyId: this.userInfo.tenantId, categoryId: id || '' }).then((res) => {
        if (index || index == 0) {
          this.$set(this.formData.scrappedGoodsInfo[index], 'goodsOptions', res);
        } else {
@@ -355,10 +363,8 @@
      this.formData.scrappedGoodsInfo[index].modelsOptions = [];
      this.formData.scrappedGoodsInfo[index].modelsIds = [];
      this.formData.scrappedGoodsInfo[index].scrappedGoodsList = [];
      this.formData.scrappedGoodsInfo[index].baseCategoryId = e[e.length - 1];
      // 根据选中分类请求物品名称列表
      this.getgoodsTemplate(e[e.length - 1], index);
      this.getgoodsTemplate(e, index);
    },
    // 物品名称列表
@@ -394,6 +400,10 @@
    // 规格型号移除
    modelRemoveTag(e, index) {
      if(e===-1){
        this.formData.scrappedGoodsInfo[index].scrappedGoodsList = []
        return
      }
      let arr = this.formData.scrappedGoodsInfo[index].scrappedGoodsList;
      let delIndex = arr.findIndex((v) => v.baseGoodsModelsId == e);
      this.formData.scrappedGoodsInfo[index].scrappedGoodsList.splice(delIndex, 1);
@@ -419,13 +429,17 @@
    handleSubmit() {
      this.$refs['ruleForm'].validate((valid) => {
        if (valid) {
          if (this.loading) return
          this.loading = true;
          scrappedAdd(this.formData)
            .then((res) => {
              this.loading = false;
              this.$message.success('保存成功!');
              this.close();
              this.$emit('search');
            })
            .catch((err) => {
              this.loading = false;
              console.log('create err', err);
              this.$message.error('保存失败');
            });
admin-web/src/views/stock/transfer/transferApplication/detail.vue
@@ -1,6 +1,6 @@
<template>
  <win-md class="stock-detail" :title="setting.title" @close="close" :width="'800px'" :loading="loading">
    <div v-loading="loading">
      <el-row :gutter="20">
        <el-col :span="8">
          <span>调拨单号:</span>
@@ -71,6 +71,17 @@
          </el-table-column>
        </el-table>
      </div>
    <div id="uploadPreviewImages" style="display: none">
      <span v-for="(src, index) in fileList" :key="index">
        <img
            v-if="checkImg(src.name)"
            class="v-img"
            :src="src.url"
            :alt="src.name"
            style="width: 100px; height: 100px"
        />
      </span>
    </div>
  </win-md>
</template>
@@ -79,6 +90,12 @@
import * as DateFormatter from '@/utils/DateFormatter';
import winMd from '@/components/win/win-md';
import transfer from '../../../mixins/transfer';
import {getDownUrl} from "@/utils/base";
import Viewer from 'viewerjs';
import 'viewerjs/dist/viewer.css';
let viewer = null;
export default {
  mixins: [transfer],
@@ -86,7 +103,8 @@
  props: {
    setting: {
      type: Object,
      default: () => {},
      default: () => {
      },
    },
  },
  data() {
@@ -107,9 +125,50 @@
      this.detail = res;
      this.fileList = this.detail.procureDoc ? JSON.parse(this.detail.procureDoc) : [];
      this.loading = false;
      this.$nextTick(() => {
        this.initPreviewImg();
      });
    });
  },
  methods: {
    initPreviewImg() {
      if (viewer != null) {
        viewer.destroy();
      }
      const ViewerDom = document.querySelector('#uploadPreviewImages');
      viewer = new Viewer(ViewerDom, {});
    },
    handlePreview(file) {
      if (!this.checkImg(file.name)) {
        return false;
      }
      let index = 0;
      for (let i = 0; i < this.fileList.length; i++) {
        const f = this.fileList[i];
        if (this.checkImg(f.name)) {
          if (file.id == f.id) {
            break;
          }
          index++;
        }
      }
      viewer.view(index);
    },
    checkImg(name) {
      const suffix = name.substring(name.lastIndexOf('.'), name.length);
      const imgArray = ['.jpg', '.jpeg', '.png', '.bmp'];
      if (imgArray.indexOf(suffix) < 0) {
        return false;
      }
      return true;
    },
    getUrl(path) {
      if (path.substr(0, 7).toLowerCase() == 'http://' || path.substr(0, 8).toLowerCase() == 'https://') {
        return path;
      } else {
        return getDownUrl() + path;
      }
    },
    close() {
      this.$emit('close');
    },
admin-web/src/views/stock/transfer/transferApplication/edit.vue
@@ -1,6 +1,6 @@
<template>
  <win-md class="stock-edit" title="调拨申请" @close="close" :width="'800px'">
    <el-form class="form" ref="ruleForm" :model="formData" :rules="rules" label-width="120px">
    <el-form v-loading="loading" class="form" ref="ruleForm" :model="formData" :rules="rules" label-width="120px">
      <div class="main-w">
        <el-row :gutter="24" class="headerHeight">
          <el-col :span="12">
@@ -11,10 +11,11 @@
            </el-form-item>
          </el-col>
          <el-col :span="12">
            <el-form-item label="调拨时间" prop="createTime">
            <el-form-item label="调拨时间" clearable prop="createTime">
              <el-date-picker
                v-model="formData.createTime"
                type="datetime"
                clearable
                value="yyyy-MM-dd HH:mm:ss"
                value-format="yyyyMMddHHmmss"
                placeholder="请选择日期"
@@ -27,7 +28,7 @@
        <el-row :gutter="24" class="headerHeight">
          <el-col :span="24">
            <el-form-item label="调拨手续" prop="procureDoc">
              <upload :settings="uploadSettings" @on-change="uploadChange"></upload>
              <upload ref="uploadRef" :settings="uploadSettings" @on-change="uploadChange"></upload>
            </el-form-item>
          </el-col>
        </el-row>
@@ -36,17 +37,20 @@
            <el-col :span="12">
              <el-form-item
                label="物品分类"
                :prop="`transferGoods[${goodsIndex}].baseCategoryIds`"
                :prop="`transferGoods.${goodsIndex}.baseCategoryId`"
                :rules="{
                  required: true,
                  message: '请选择',
                  message: '请选择物品分类',
                  trigger: 'change',
                }"
              >
                <el-cascader
                  v-model="goodsItem.baseCategoryIds"
                  v-model="goodsItem.baseCategoryId"
                  :options="categoryOptions"
                  :props="{ value: 'id' }"
                  :props="{ value: 'id',emitPath: false }"
                  :show-all-levels="false"
                  filterable
                  clearable
                  @change="categoryChange($event, goodsIndex)"
                  style="width: 100%"
                ></el-cascader>
@@ -55,13 +59,14 @@
            <el-col :span="12">
              <el-form-item
                label="物品名称"
                :prop="`transferGoods[${goodsIndex}].baseGoodsTemplateId`"
                :prop="`transferGoods.${goodsIndex}.baseGoodsTemplateId`"
                :rules="rules.baseGoodsTemplateId"
              >
                <el-select
                  v-model="goodsItem.baseGoodsTemplateId"
                  placeholder="请先择物品分类"
                  :placeholder="goodsItem.baseCategoryId?'请选择物品':'请先选择物品分类'"
                  filterable
                  clearable
                  :disabled="!goodsItem.baseCategoryId"
                  style="width: 100%"
                  @change="goodsTemplateChange($event, goodsIndex)"
@@ -90,10 +95,12 @@
                <el-select
                  v-model="goodsItem.modelsIds"
                  multiple
                  placeholder="请先择物品名称"
                  clearable
                  :placeholder="goodsItem.baseCategoryId?'请选择规格型号':'请先选择物品名称'"
                  :disabled="!goodsItem.baseCategoryId"
                  @change="modelChange($event, goodsIndex)"
                  @remove-tag="modelRemoveTag($event, goodsIndex)"
                  @clear="modelRemoveTag(-1, goodsIndex)"
                  style="width: 100%"
                >
                  <el-option
@@ -199,12 +206,13 @@
      callback();
    };
    return {
      loading: false,
      loading: true,
      agencyOptions: [], // 调拨机构
      categoryOptions: [], // 物品分类列表
      modelList: [], //型号列表
      formData: {
        transferBusinessType: 0, // 单据类型。0仓库调拨;1部门分发;2部门物品回退
        procureDoc: '',
        outAgencyId: '', // 调拨机构id
        createTime: '', // 调拨时间
        transferGoods: [],
@@ -228,9 +236,9 @@
      rules: {
        outAgencyId: [{ required: true, message: '请选择', trigger: 'change' }],
        createTime: [{ required: true, message: '请选择', trigger: 'change' }],
        procureDoc: [{ required: true, message: '请上传调拨手续', trigger: 'change' }],
        baseCategoryIds: [{ required: true, message: '请选择', trigger: 'change' }],
        baseGoodsTemplateId: [{ validator: checkGoodsTemplateId, trigger: ['blur', 'change'] }],
        baseGoodsTemplateId: [{ required: true, message: '请选择', trigger: 'change' },{ validator: checkGoodsTemplateId, trigger: ['blur', 'change'] }],
        modelsIds: [{ required: true, message: '请选择', trigger: 'change' }],
        counts: [
          { required: true, message: '请输入', trigger: 'change' },
@@ -242,12 +250,11 @@
        title: '上传',
        max: 20, // 最大大小,单位M
        num: 2, // 支持上传图片个数
        accept: '.jpg,.png', // 限制格式
        tip: '', // 提示 默认:`只能上传${this.defaultSettings.num}个${this.defaultSettings.accept}文件,且不超过${this.defaultSettings.max}kb`
        uploadUrl: getUploadUrl(), // 上传路径
        multiple: true, // 是否支持批量上传
        disabled: false, // 是否禁用
        type: 'text', // text/picture
        type: 'picture', // text/picture
      },
    };
  },
@@ -259,15 +266,16 @@
  },
  methods: {
    async init() {
      this.handegetParentTenant();
      await this.handegetParentTenant();
      await this.getCategoryTree();
      this.loading = false
      this.getgoodsTemplate();
      this.getgoodsModel();
      this.getCategoryTree();
    },
    // 获取上级机构
    handegetParentTenant() {
      getParentTenant().then((res) => {
    async handegetParentTenant() {
      await getParentTenant().then((res) => {
        if (res.id != this.userInfo.tenantId) {
          this.agencyOptions = [res];
          this.formData.outAgencyId = res.id;
@@ -343,10 +351,8 @@
      this.formData.transferGoods[index].modelsOptions = [];
      this.formData.transferGoods[index].modelsIds = [];
      this.formData.transferGoods[index].models = [];
      this.formData.transferGoods[index].baseCategoryId = e[e.length - 1];
      // 根据选中分类请求物品名称列表
      this.getgoodsTemplate(e[e.length - 1], index);
      this.getgoodsTemplate(e, index);
    },
    // 物品名称列表选择
@@ -382,6 +388,10 @@
    // 规格型号移除
    modelRemoveTag(e, index) {
      if(e===-1){
        this.formData.transferGoods[index].models = []
        return
      }
      let arr = this.formData.transferGoods[index].models;
      let delIndex = arr.findIndex((v) => v.baseGoodsModelsId == e);
      this.formData.transferGoods[index].models.splice(delIndex, 1);
@@ -389,7 +399,8 @@
    // 上传
    uploadChange(e) {
      console.log('uploadChange', e);
      let arr = this.$refs.uploadRef.fileList;
      this.formData.procureDoc = JSON.stringify(arr);
    },
    // 点击新增物品
@@ -420,14 +431,17 @@
    handleSubmit() {
      this.$refs['ruleForm'].validate((valid) => {
        if (valid) {
          console.log('this.formData', this.formData);
          if(this.loading) return
          this.loading = true
          transferAdd(this.formData)
            .then((res) => {
              this.loading = false
              this.$message.success('保存成功!');
              this.close();
              this.$emit('search');
            })
            .catch((err) => {
              this.loading = false
              console.log('edit err', err);
              this.$message.error('保存失败');
            });
admin-web/src/views/stock/transfer/transferissue/detail.vue
@@ -1,6 +1,5 @@
<template>
  <win-md class="stock-detail" :title="setting.title" @close="close" :width="'1100px'">
    <div v-loading="loading">
  <win-md class="stock-detail" :loading="loading" :title="setting.title" @close="close" :width="'1100px'">
      <el-row :gutter="20">
        <el-col :span="6">
          <span>调拨单号:</span>
@@ -79,6 +78,17 @@
          </el-table-column>
        </el-table>
      </div>
    <div id="uploadPreviewImages" style="display: none">
      <span v-for="(src, index) in fileList" :key="index">
        <img
            v-if="checkImg(src.name)"
            class="v-img"
            :src="src.url"
            :alt="src.name"
            style="width: 100px; height: 100px"
        />
      </span>
    </div>
  </win-md>
</template>
@@ -87,6 +97,11 @@
import * as DateFormatter from '@/utils/DateFormatter';
import winMd from '@/components/win/win-md';
import transfer from '../../../mixins/transfer';
import {getDownUrl} from "@/utils/base";
import Viewer from 'viewerjs';
import 'viewerjs/dist/viewer.css';
let viewer = null;
export default {
  mixins: [transfer],
@@ -94,7 +109,8 @@
  props: {
    setting: {
      type: Object,
      default: () => {},
      default: () => {
      },
    },
  },
  data() {
@@ -114,11 +130,58 @@
    this.loading = true;
    transferDetail({ id: this.setting.id }).then((res) => {
      this.detail = res;
      this.fileList = this.detail.procureDoc ? JSON.parse(this.detail.procureDoc) : [];
      this.fileList = this.detail.doc ? JSON.parse(this.detail.doc) : [];
      this.loading = false;
      this.$nextTick(() => {
        this.initPreviewImg();
      });
    });
  },
  methods: {
    initPreviewImg() {
      if (viewer != null) {
        viewer.destroy();
      }
      const ViewerDom = document.querySelector('#uploadPreviewImages');
      viewer = new Viewer(ViewerDom, {});
    },
    handlePreview(file) {
      if (!this.checkImg(file.name)) {
        return false;
      }
      let index = 0;
      for (let i = 0; i < this.fileList.length; i++) {
        const f = this.fileList[i];
        if (this.checkImg(f.name)) {
          if (file.id == f.id) {
            break;
          }
          index++;
        }
      }
      // this.fileList.forEach((f, i) => {
      //   if (file.uid == f.uid) {
      //     index = i
      //   }
      // })
      // document.querySelector('#uploadPreviewImages').children[0].click()
      viewer.view(index);
    },
    checkImg(name) {
      const suffix = name.substring(name.lastIndexOf('.'), name.length);
      const imgArray = ['.jpg', '.jpeg', '.png', '.bmp'];
      if (imgArray.indexOf(suffix) < 0) {
        return false;
      }
      return true;
    },
    getUrl(path) {
      if (path.substr(0, 7).toLowerCase() == 'http://' || path.substr(0, 8).toLowerCase() == 'https://') {
        return path;
      } else {
        return getDownUrl() + path;
      }
    },
    close() {
      this.$emit('close');
    },