Forráskód Böngészése

feat: 添加材料详情获取和更新功能,优化材料表单验证

Mcal 2 napja
szülő
commit
e81cf62c06

+ 30 - 0
src/api/material.js

@@ -51,3 +51,33 @@ export function savePurchaseOrderController(data) {
 }
 
 
+// 获取材料表详情
+export function getMaterialInfo(id) {
+  return request({
+    url: `/backendApi/material/info/${id}`,
+    method: 'get'
+  });
+}
+// 获取采购订单表详情
+export function getPurchaseOrderInfo(id) {
+  return request({
+    url: `/backendApi/purchase_order/info/${id}`,
+    method: 'get'
+  });
+}
+// 更新材料表状态
+export function updateMaterialStatus(data) {
+  return request({
+    url: '/backendApi/material/updateStatus',
+    method: 'post',
+    data
+  });
+}
+// 更新材料表
+export function updateMaterial(data) {
+  return request({
+    url: '/backendApi/material/update',
+    method: 'post',
+    data
+  });
+}

+ 50 - 0
src/api/waring.js

@@ -0,0 +1,50 @@
+import request from '@/utils/request'
+// 获取店铺列表
+export function getStoreAlertsList(query) {
+    return request({
+        url: '/backendApi/storeAlerts/list',
+        method: 'get',
+        params: query
+    })
+  }
+  
+  // 获取店铺详情
+  export function getStoreAlertsDetail(shopId) {
+    return request({
+        url: `/backendApi/storeAlerts/${shopId}`,
+        method: 'get'
+    })
+  }
+  
+  // 新增预警
+  export function addStoreAlerts(data) {
+    return request({
+        url: '/backendApi/storeAlerts/add',
+        method: 'post',
+        data
+    })
+  }
+  
+  // 更新预警
+  export function updateStoreAlerts(shopId, data) {
+    return request({
+        url: `/backendApi/storeAlerts/update/${shopId}`,
+        method: 'post',
+        data
+    })
+  }
+  
+  // 清除预警配置信息
+  export function clearStoreAlerts(shopId) {
+    return request({
+        url: `/backendApi/storeAlerts/clear/${shopId}`,
+        method: 'post'
+    })
+  } 
+    // 清除预警配置信息
+    export function getInterval() {
+        return request({
+            url: `/backendApi/storeAlerts/interval`,
+            method: 'get'
+        })
+      } 

+ 36 - 75
src/components/ImageUpload/index.vue

@@ -74,11 +74,8 @@ export default {
   },
   data() {
     return {
-      number: 0,
-      uploadList: [],
       dialogImageUrl: '',
       dialogVisible: false,
-      hideUpload: false,
       baseUrl: process.env.VUE_APP_BASE_API,
       uploadImgUrl: process.env.VUE_APP_SERVER_URL + '/backendApi/file/upload', // 上传的图片服务器地址
       headers: {
@@ -90,23 +87,15 @@ export default {
   watch: {
     value: {
       handler(val) {
+        console.log(val,'val')
         if (val) {
-          // 首先将值转为数组
-          const list = Array.isArray(val) ? val : this.value.split(',')
-          // 然后将数组转为对象数组
-          this.fileList = list.map((item) => {
-            if (typeof item === 'string') {
-              if (item.indexOf(this.baseUrl) === -1) {
-                item = { name: this.baseUrl + item, url: this.baseUrl + item }
-              } else {
-                item = { name: item, url: item }
-              }
-            }
-            return item
-          })
+          const list = Array.isArray(val) ? val : String(val).split(',');
+          this.fileList = list.map(item => {
+            const url = typeof item === 'string' ? (item.indexOf(this.baseUrl) === -1 ? this.baseUrl + item : item) : item.url;
+            return { name: url, url };
+          });
         } else {
-          this.fileList = []
-          return []
+          this.fileList = [];
         }
       },
       deep: true,
@@ -122,90 +111,62 @@ export default {
   methods: {
     // 删除图片
     handleRemove(file) {
-      const findex = this.fileList.map((f) => f.name).indexOf(file.name)
-      if (findex > -1) {
-        this.fileList.splice(findex, 1)
-        this.$emit('input', this.listToString(this.fileList))
+      const index = this.fileList.findIndex(f => f.name === file.name);
+      if (index > -1) {
+        this.fileList.splice(index, 1);
+        this.$emit('input', this.listToString(this.fileList));
       }
     },
     // 上传成功回调
     handleUploadSuccess(res) {
-
-      if (res && res?.data) {
-        // this.uploadList.push({ name: res.data.fileName, url: res.data.url })
-        this.uploadList.push(res.data.url)
-
-        if (this.uploadList.length === this.number) {
-          this.fileList = this.fileList.concat(this.uploadList)
-          console.log(this.fileList,this.uploadList)
-          this.uploadList = []
-          this.number = 0
-          //原 this.listToString(this.fileList)
-          this.$emit('input', this.fileList.toString())
-          this.$modal.closeLoading()
-        }
+      if (res && res.data) {
+        const newFile = { name: res.data.url, url: res.data.url };
+        this.fileList.push(newFile);
+        this.$emit('input', this.listToString(this.fileList));
+        this.$modal.closeLoading();
       }
     },
     // 上传前loading加载
     handleBeforeUpload(file) {
-      let isImg = false
-      if (this.fileType.length) {
-        let fileExtension = ''
-        if (file.name.lastIndexOf('.') > -1) {
-          fileExtension = file.name.slice(file.name.lastIndexOf('.') + 1)
-        }
-        isImg = this.fileType.some((type) => {
-          if (file.type.indexOf(type) > -1) return true
-          if (fileExtension && fileExtension.indexOf(type) > -1) return true
-          return false
-        })
-      } else {
-        isImg = file.type.indexOf('image') > -1
-      }
+      const fileExtension = file.name.slice(file.name.lastIndexOf('.') + 1);
+      const isAllowedType = this.fileType.some(type => file.type.includes(type) || fileExtension === type);
 
-      if (!isImg) {
+      if (!isAllowedType) {
         this.$modal.msgError(
           `${this.$t('ImageUpload.fileFormatError')}${this.fileType.join('/')}${this.$t(
             'ImageUpload.imageFormatFile'
           )}`
-        )
-        return false
+        );
+        return false;
       }
-      if (this.fileSize) {
-        const isLt = file.size / 1024 / 1024 < this.fileSize
-        if (!isLt){
-          this.$modal.msgError(
-            `${this.$t('ImageUpload.fileSizeExceed')}${this.fileSize} ${this.$t('ImageUpload.mb')}`
-          )
-          return false
-        }
 
+      if (this.fileSize && file.size / 1024 / 1024 >= this.fileSize) {
+        this.$modal.msgError(
+          `${this.$t('ImageUpload.fileSizeExceed')}${this.fileSize} ${this.$t('ImageUpload.mb')}`
+        );
+        return false;
       }
 
-      this.$modal.loading(`${this.$t('ImageUpload.uploadingImage')}`)
-      this.number++
+      this.$modal.loading(`${this.$t('ImageUpload.uploadingImage')}`);
+      return true;
     },
     // 文件个数超出
     handleExceed() {
-      this.$modal.msgError(this.$t('ImageUpload.fileNumberExceed', { limit: this.limit }))
+      this.$modal.msgError(this.$t('ImageUpload.fileNumberExceed', { limit: this.limit }));
     },
     // 上传失败
     handleUploadError() {
-      this.$modal.msgError(this.$t('ImageUpload.uploadImageFailed'))
-      this.$modal.closeLoading()
+      this.$modal.msgError(this.$t('ImageUpload.uploadImageFailed'));
+      this.$modal.closeLoading();
     },
     // 预览
     handlePictureCardPreview(file) {
-      this.dialogImageUrl = file.url
-      this.dialogVisible = true
+      this.dialogImageUrl = file.url;
+      this.dialogVisible = true;
     },
     // 对象转成指定字符串分隔
-    listToString(list, separator) {
-      const sep = separator || ',';
-      return list.map(item => {
-        const url = item.url?.replace(this.baseUrl, '') || '';
-        return url;
-      }).join(sep);
+    listToString(list, separator = ',') {
+      return list.length ? list.map(item => item.url.replace(this.baseUrl, '')).join(separator) : '';
     }
   }
 }
@@ -226,4 +187,4 @@ export default {
   opacity: 0;
   transform: translateY(0);
 }
-</style>
+</style>

+ 0 - 1
src/components/Page/index.vue

@@ -6,7 +6,6 @@
       size="small"
       inline
       v-show="showSearch"
-      
       v-bind="formProps"
     >
       <slot

+ 76 - 0
src/views/material/list/edit.vue

@@ -0,0 +1,76 @@
+<template>
+  <div class="app-container">
+    <Paragraph title="基础信息">
+      <template>
+        <FormUI ref="formUI" :materialTypeList="materialTypeList" :imgList="defaultImages" :form="form"/>
+        <el-row type="flex" class="row-bg" justify="center">
+          <el-col :span="8">
+            <el-button size="mini" @click="handleCancel">取消修改</el-button>
+            <el-button type="primary" size="mini" @click="handleSubmit"
+            >确认保存
+            </el-button
+            >
+          </el-col>
+        </el-row>
+      </template>
+    </Paragraph>
+  </div>
+</template>
+<script>
+  import FormUI from "./formUI.vue";
+  import Paragraph from "@/components/Paragraph";
+  import {getAllMaterialType, updateMaterial} from "../../../api/material";
+  import {getMaterialInfo} from "@/api/material";
+
+  export default {
+    name: "Add",
+    components: {FormUI, Paragraph},
+    props: {},
+    data() {
+      return {
+        materialTypeList: [],
+        form:{},
+        defaultImages:[]
+      };
+    },
+    mounted() {
+      this.getAllMaterialType()
+      this.getInfo()
+    },
+    methods: {
+      getInfo(){
+        getMaterialInfo(this.$route.query.id).then(res => {
+          console.log(res,'res')
+          this.form = res.data.materialInfo
+          this.defaultImages = [{name: this.form.fileId, url: this.form.fileId }]
+
+        })
+      },
+      handleCancel() {
+        this.$store.dispatch("tagsView/delView", this.$route);
+        this.$router.push({path: "/material/list"});
+      },
+      async handleSubmit() {
+        var submitData = await this.$refs.formUI.validate()
+        console.log(submitData)
+        updateMaterial(submitData).then(res => {
+          if (res.code === 200) {
+            const successMsg = this.$t('merchant.statusChangeSuccess', { action: "原材料修改" });
+            this.$modal.msgSuccess(successMsg);
+            this.$router.push({path: "/material/list"});
+          }
+        })
+      },
+      getAllMaterialType() {
+        getAllMaterialType().then(res => {
+          this.materialTypeList = res.data
+        })
+      }
+    },
+  };
+</script>
+<style lang="scss" scoped>
+  .container {
+    width: 60%;
+  }
+</style>

+ 64 - 29
src/views/material/list/formUI.vue

@@ -4,7 +4,9 @@
     :model="form"
     :disabled="disabled"
     size="mini"
-    label-width="100px">
+    label-width="100px"
+    :rules="rules"
+  >
     <el-row :gutter="24">
       <el-col :span="10">
         <el-form-item label="材料名称" prop="name" required>
@@ -12,57 +14,53 @@
         </el-form-item>
       </el-col>
       <el-col :span="10">
-        <el-form-item label="原材料编号" required>
+        <el-form-item label="原材料编号" prop="materialNo" required>
           <el-input v-model="form.materialNo"></el-input>
         </el-form-item>
       </el-col>
       <el-col :span="10">
-        <el-form-item label="规格" required>
+        <el-form-item label="规格" prop="specification" required>
           <el-input v-model="form.specification"></el-input>
         </el-form-item>
       </el-col>
       <el-col :span="10">
-        <el-form-item label="入库数量" required>
-          <el-input v-model="form.inventory"></el-input>
+        <el-form-item label="入库数量" prop="inventory" required>
+          <el-input-number v-model="form.inventory"></el-input-number>
         </el-form-item>
       </el-col>
       <el-col :span="10">
-        <el-form-item label="保质期" required>
-          <el-input v-model="form.shelfLife"></el-input>
+        <el-form-item label="保质期" prop="shelfLife" required>
+          <el-input-number v-model="form.shelfLife"></el-input-number>
         </el-form-item>
       </el-col>
       <el-col :span="10">
-        <el-form-item label="单位" required>
+        <el-form-item label="单位" prop="unit" required>
           <el-input v-model="form.unit"></el-input>
         </el-form-item>
       </el-col>
       <el-col :span="10">
-        <el-form-item label="采购期数" required>
-          <el-input v-model="form.purchasePeriod"></el-input>
+        <el-form-item label="采购期数" prop="purchasePeriod" required>
+          <el-input-number v-model="form.purchasePeriod"></el-input-number>
         </el-form-item>
       </el-col>
       <el-col :span="10">
-        <el-form-item label="材料类别" required>
-          <el-select v-model="form.materialTypeId" placeholder="请选择材料类别">
-            <el-option
-              v-for="item in materialTypeList"
-              :key="item.value"
-              :label="item.label"
-              :value="item.value">
-            </el-option>
-          </el-select>
+        <el-form-item label="材料类别" prop="materialTypeId" required>
+          <el-input v-model="form.materialTypeId"></el-input>
+
         </el-form-item>
       </el-col>
       <el-col :span="10">
-        <el-form-item label="材料图片" required>
-          <ImageUpload @input="input" :isShowTip="false" :limit="1" />
+        <el-form-item label="材料图片" prop="fileId" required>
+          <ImageUpload @input="input" :value="imgList" :isShowTip="false" :limit="1" />
         </el-form-item>
       </el-col>
     </el-row>
   </el-form>
 </template>
+
 <script>
 import ImageUpload from "@/components/ImageUpload";
+
 export default {
   name: "FormUI",
   props: {
@@ -70,18 +68,55 @@ export default {
       type: Object,
       default: () => ({}),
     },
-    materialTypeList:{
-      type:Array,
-      default:()=>([])
+    materialTypeList: {
+      type: Array,
+      default: () => [],
     },
     disabled: {
       type: Boolean,
       default: false,
     },
+    imgList: {
+      type: Array,
+      default: () => [],
+    },
   },
   components: { ImageUpload },
   data() {
-    return {};
+    return {
+      rules: {
+        name: [
+          { required: true, message: "请输入材料名称", trigger: "blur" },
+        ],
+        materialNo: [
+          { required: true, message: "请输入原材料编号", trigger: "blur" },
+        ],
+        specification: [
+          { required: true, message: "请输入规格", trigger: "blur" },
+        ],
+        inventory: [
+          { required: true, message: "请输入入库数量", trigger: "blur" },
+          { type: "number", message: "入库数量必须为数字", trigger: "blur" },
+        ],
+        shelfLife: [
+          { required: true, message: "请输入保质期", trigger: "blur" },
+          { type: "number", message: "保质期必须为数字", trigger: "blur" },
+        ],
+        unit: [
+          { required: true, message: "请输入单位", trigger: "blur" },
+        ],
+        purchasePeriod: [
+          { required: true, message: "请输入采购期数", trigger: "blur" },
+          { type: "number", message: "采购期数必须为数字", trigger: "blur" },
+        ],
+        materialTypeId: [
+          { required: true, message: "请选择材料类别", trigger: "change" },
+        ],
+        fileId: [
+          { required: true, message: "请上传材料图片", trigger: "change" },
+        ],
+      },
+    };
   },
   methods: {
     validate() {
@@ -95,9 +130,9 @@ export default {
         });
       });
     },
-    input(url){
-      this.form.fileId = url
-    }
+    input(url) {
+      this.form.fileId = url;
+    },
   },
 };
-</script>
+</script>

+ 146 - 7
src/views/material/list/index.vue

@@ -57,6 +57,7 @@
 
           <el-switch
             v-model="scope.row.status"
+            @change="changeStatus(scope.row)"
             :active-value="1"
             :inactive-value="0"
             active-color="#13ce66"
@@ -65,13 +66,13 @@
         </template>
       </el-table-column>
       <el-table-column label="操作" align="left" width="160" fixed="right">
-        <template slot-scope="scope">
-          <el-button size="mini" type="text">详情</el-button>
-          <el-button size="mini" type="text" icon="el-icon-edit"
+        <template #default="{row}">
+          <el-button size="mini" type="text" @click="showDetail(row)">详情</el-button>
+          <el-button size="mini" type="text" @click="handleEdit(row)" icon="el-icon-edit"
           >修改
           </el-button
           >
-          <el-button size="mini" type="text" icon="el-icon-delete" @click="deleteMaterial(scope.row)">删除
+          <el-button size="mini" type="text" icon="el-icon-delete" @click="deleteMaterial(row)">删除
           </el-button
           >
         </template>
@@ -83,18 +84,95 @@
       :limit.sync="queryParams.pageSize"
       @pagination="getList"
     />
-
+    <!-- 详情 -->
+    <el-dialog
+      :title="$t('goodList.categoryName')"
+      :visible.sync="open"
+      class="common-dialog"
+      width="700px"
+      append-to-body
+    >
+    <el-form
+    ref="form"
+    :model="form"
+    :disabled="disabled"
+    size="mini"
+    label-width="100px">
+    <el-row :gutter="24">
+      <el-col :span="10">
+        <el-form-item label="材料名称" prop="name" required>
+          <el-input v-model="form.name"></el-input>
+        </el-form-item>
+      </el-col>
+      <el-col :span="10">
+        <el-form-item label="原材料编号" required>
+          <el-input v-model="form.materialNo"></el-input>
+        </el-form-item>
+      </el-col>
+      <el-col :span="10">
+        <el-form-item label="规格" required>
+          <el-input v-model="form.specification"></el-input>
+        </el-form-item>
+      </el-col>
+      <el-col :span="10">
+        <el-form-item label="入库数量" required>
+          <el-input v-model="form.inventory"></el-input>
+        </el-form-item>
+      </el-col>
+      <el-col :span="10">
+        <el-form-item label="保质期" required>
+          <el-input v-model="form.shelfLife"></el-input>
+        </el-form-item>
+      </el-col>
+      <el-col :span="10">
+        <el-form-item label="单位" required>
+          <el-input v-model="form.unit"></el-input>
+        </el-form-item>
+      </el-col>
+      <el-col :span="10">
+        <el-form-item label="采购期数" required>
+          <el-input v-model="form.purchasePeriod"></el-input>
+        </el-form-item>
+      </el-col>
+      <el-col :span="10">
+        <el-form-item label="材料类别" required>
+          <el-select v-model="form.materialTypeId" placeholder="请选择材料类别">
+            <el-option
+              v-for="item in materialTypeList"
+              :key="item.value"
+              :label="item.label"
+              :value="item.value">
+            </el-option>
+          </el-select>
+        </el-form-item>
+      </el-col>
+      <el-col :span="10">
+        <el-form-item label="材料图片" required>
+          <ImageUpload :value="defaultImages" :isShowTip="false" :limit="1" />
+        </el-form-item>
+      </el-col>
+    </el-row>
+  </el-form>
+      <div slot="footer" class="dialog-footer">
+        <el-button type="primary" @click="submitForm">{{ $t('goodList.confirm') }}</el-button>
+        <el-button @click="cancel">{{ $t('goodList.cancel') }}</el-button>
+      </div>
+    </el-dialog>
   </div>
 </template>
 <script>
   import Page from "@/components/Page";
-  import {getMaterialList,deleteMaterialById} from "@/api/material";
+  import {getMaterialList,deleteMaterialById, getMaterialInfo,updateMaterial,updateMaterialStatus} from "@/api/material";
   export default {
     name: "MaterialList",
     components: {Page},
 
     data() {
       return {
+        form:{},
+        materialTypeList:[],
+        open: false,
+        disabled:true,
         list:[], //列表数据
         queryParams: {
           name: '',  //材料名称
@@ -111,7 +189,8 @@
         // 显示搜索条件
         showSearch: true,
         //总数
-        total:0
+        total:0,
+        defaultImages: [],
       };
     }, mounted() {
       this.getList()
@@ -120,8 +199,64 @@
       console.log(111)
     },
     methods: {
+      changeStatus(row){
+        // row.status = row.status == 1 ? 0 : 1
+        console.log(row)
+        const query={
+          id:row.id,
+          status:row.status
+        }
+        console.log(query)
+        updateMaterialStatus(query).then(res => {
+          this.$modal.msgSuccess('修改成功')
+        // this.getList()
+
+        })
+      },
+      showDetail(row) {
+        console.log(row)
+        getMaterialInfo(row.id).then(res => {
+          console.log(res,'res')
+          this.form = res.data.materialInfo
+          this.defaultImages = [{name: this.form.fileId, url: this.form.fileId }]
+          this.open = true
+        })
+      },
+      getAllMaterialType() {
+        getAllMaterialType().then(res => {
+          this.materialTypeList = res.data
+        })
+      },
+          // 取消按钮
+    cancel() {
+      this.open = false
+    },
+    // 提交按钮
+    submitForm: function () {
+      this.$refs['form'].validate((valid) => {
+        if (valid) {
+          if (this.form.logo.length < 1) {
+            this.form.logo = '/static/defaultImage/none.png'
+          }
+          if (this.form.id) {
+            saveGoodsCate(this.form).then((response) => {
+              this.$modal.msgSuccess(this.$t('goodList.modificationSuccess'))
+              this.open = false
+              this.getList()
+            })
+          } else {
+            saveGoodsCate(this.form).then((response) => {
+              this.$modal.msgSuccess(this.$t('goodList.addSuccess'))
+              this.open = false
+              this.getList()
+            })
+          }
+        }
+      })
+    },
       getList() {
         this.loading = true
+        console.log(this.queryParams)
         getMaterialList(this.queryParams).then(res => {
           this.loading = false
           this.list = res.data.data;
@@ -145,6 +280,10 @@
       handleAdd() {
         this.$router.push({path: "/material/list/add"});
       },
+      handleEdit(row) {
+        console.log(row)
+        this.$router.push({path: "/material/list/edit",query: {id: row.id}});
+      },
       // 多选框选中数据
       handleSelectionChange(selection) {
         this.ids = selection.map(item => item.id);

+ 22 - 3
src/views/material/order/detail.vue

@@ -1,17 +1,36 @@
 <template>
   <div>
-    <FormUI mode="detail" />
+    <FormUI mode="detail" :form="form" :imgList="imageList" :detailSelectedItems="detailSelectedItems"/>
   </div>
 </template>
 <script>
 import FormUI from "./formUI.vue";
-
+import {getPurchaseOrderInfo} from "@/api/material";
 export default {
   name: "OrderDetail",
   components: { FormUI },
   props: {},
   data() {
-    return {};
+    return {
+      form: {},
+      imageList: [],
+      detailSelectedItems: [],
+    };
+  },
+  mounted() {
+    this.getInfo();
+  },
+  methods: {
+    getInfo() {
+      getPurchaseOrderInfo(this.$route.query.id).then((res) => {
+        console.log(res, "res");
+        this.form = res.data;
+        this.detailSelectedItems = res.data.orderItemList;
+        this.imageList = this.form.fileList.map((item) => {
+          return { name: item, url: item };
+        });
+      });
+    },
   },
 };
 </script>

+ 103 - 15
src/views/material/order/formUI.vue

@@ -2,7 +2,8 @@
   <div>
     <Paragraph title="基础信息">
       <template>
-        <el-form ref="form" size="mini"  :model="form">
+        <!-- 添加 :rules="rules" 绑定验证规则 -->
+        <el-form ref="form" size="mini" :model="form" :disabled="mode === 'detail'" :rules="rules">
           <el-row :gutter="20">
             <el-col :span="6">
               <el-form-item label="采购订单号" prop="orderNo" required>
@@ -62,14 +63,14 @@
             </el-col>
             <el-col :span="24">
               <el-form-item label="发票截图" prop="fileId">
-                <ImageUpload @input="input" :isShowTip="false" />
+                <ImageUpload @input="input" :value="imgList" :isShowTip="false" />
               </el-form-item>
             </el-col>
           </el-row>
         </el-form>
       </template>
     </Paragraph>
-    <Paragraph title="商品信息">
+    <Paragraph title="商品信息" v-if="mode == 'add'">
       <template>
         <div style="display: flex;align-items: center">
           <el-button type="primary" @click="handleAddGoods">增加商品</el-button>
@@ -156,6 +157,43 @@
         </el-table>
       </template>
     </Paragraph>
+    <Paragraph title="商品信息" v-if="mode === 'detail'">
+      <template>
+        <div style="display: flex;align-items: center">
+          <!-- <el-button type="primary" @click="handleAddGoods">增加商品</el-button> -->
+          <div style="display: flex;margin-left: auto">总价:<span style="font-size: 20px;color: #ff0000">¥{{detailTotalAmount}}</span></div>
+        </div>
+
+        <el-table :data="detailSelectedItems" style="width: 100%">
+          <!-- 商品名称 -->
+          <el-table-column label="商品名称" prop="materialName" min-width="120"></el-table-column>
+          <!-- 单价(数字输入) -->
+          <el-table-column label="单价(元)" min-width="120">
+            <template v-slot="scope">
+              <div>
+                <span >¥ {{ scope.row.unitPrice.toFixed(2) }}</span>
+              </div>
+            </template>
+          </el-table-column>
+
+          <!-- 总数(数字输入) -->
+          <el-table-column label="总数" min-width="100">
+            <template v-slot="scope">
+              <div>
+
+                <span >{{ scope.row.totalQuantity }}</span>
+              </div>
+            </template>
+          </el-table-column>
+          <!-- 总价(自动计算) -->
+          <el-table-column label="总价" min-width="120">
+            <template v-slot="scope">
+              ¥ {{ (scope.row.totalQuantity * scope.row.unitPrice).toFixed(2) }}
+            </template>
+          </el-table-column>
+        </el-table>
+      </template>
+    </Paragraph>
     <!-- 材料列表弹出层 -->
     <el-dialog
       title="材料列表"
@@ -185,7 +223,7 @@
 <script>
 import Paragraph from "@/components/Paragraph";
 import PagingTable from "@/components/PagingTable";
-import {getMaterialList} from "@/api/material";
+import { getMaterialList } from "@/api/material";
 
 export default {
   name: "FormUI",
@@ -199,19 +237,69 @@ export default {
       type: String,
       default: "add",
     },
+    detailSelectedItems:{
+      type: Array,
+      default: () => []
+    },
+    imgList: {
+      type: Array,
+      default: () => [],
+    }
   },
   data() {
     return {
       materialDialog: false,
       // 目标集合(存放被选中的数据)
       selectedItems: [],
+      // 定义表单验证规则
+      rules: {
+        orderNo: [
+          { required: true, message: '请输入采购订单号', trigger: 'blur' }
+        ],
+        puchaseSource: [
+          { required: true, message: '请输入采购方', trigger: 'blur' }
+        ],
+        contactWay: [
+          { required: true, message: '请输入联系电话', trigger: 'blur' },
+          { pattern: /^[0-9]{11}$/, message: '请输入有效的11位手机号码', trigger: 'blur' }
+        ],
+        responsible: [
+          { required: true, message: '请输入负责人', trigger: 'blur' }
+        ],
+        totalQuantity: [
+          { required: true, message: '请输入商品采购总数', trigger: 'blur' },
+          { pattern: /^\d+$/, message: '商品采购总数必须为整数', trigger: 'blur' }
+        ],
+        totalWeight: [
+          { required: true, message: '请输入采购总KG数', trigger: 'blur' },
+          { pattern: /^\d+(\.\d+)?$/, message: '采购总KG数必须为数字', trigger: 'blur' }
+        ],
+        totalPrice: [
+          { required: true, message: '请输入总价', trigger: 'blur' },
+          { pattern: /^\d+(\.\d+)?$/, message: '总价必须为数字', trigger: 'blur' }
+        ],
+        actualPrice: [
+          { required: true, message: '请输入支付金额', trigger: 'blur' },
+          { pattern: /^\d+(\.\d+)?$/, message: '支付金额必须为数字', trigger: 'blur' }
+        ],
+        purchaseType: [
+          { required: true, message: '请输入支付方式', trigger: 'blur' }
+        ],
+        purchaseTime: [
+          { required: true, message: '请选择采购时间', trigger: 'change' }
+        ]
+      }
     };
   },
   computed: {
     totalAmount() {
       var amount = this.selectedItems.reduce((sum, item) => sum + (item.totalQuantity * item.unitPrice), 0);
       return amount.toFixed(2)
-    }
+    },
+    detailTotalAmount() {
+      var amount = this.detailSelectedItems.reduce((sum, item) => sum + (item.totalQuantity * item.unitPrice), 0);
+      return amount.toFixed(2)
+    } 
   },
   methods: {
     handleAddGoods() {
@@ -223,9 +311,9 @@ export default {
     async getList(queryParams) {
       queryParams.pageNo = queryParams.page
       var data = await getMaterialList(queryParams)
-      return {list:data.data.data,total:data.data.total}
+      return { list: data.data.data, total: data.data.total }
     },
-    addMaterial(item){
+    addMaterial(item) {
       console.log(item)
       // 检查是否已存在(根据唯一ID判断)
       const isExist = this.selectedItems.some(
@@ -236,10 +324,10 @@ export default {
         return;
       }
       var materialItem = {
-        materialId:item.id,
-        materialName:item.name,
-        totalQuantity:0,
-        unitPrice:0,
+        materialId: item.id,
+        materialName: item.name,
+        totalQuantity: 0,
+        unitPrice: 0,
         editing: {
           status: false,
           field: null,
@@ -254,12 +342,12 @@ export default {
       const clonedItem = JSON.parse(JSON.stringify(materialItem));
       this.selectedItems.push(clonedItem);
     },
-    deleteSelectedItems(item){
+    deleteSelectedItems(item) {
       this.selectedItems = this.selectedItems.filter(
         s => s.materialId !== item.materialId
       );
     },
-    submit(){
+    submit() {
       return new Promise((resolve, reject) => {
         this.$refs.form.validate((valid) => {
           if (valid) {
@@ -271,7 +359,7 @@ export default {
         });
       });
     },
-    input(urls){
+    input(urls) {
       this.form.fileId = urls
     },
     // 初始化行编辑状态
@@ -313,4 +401,4 @@ export default {
     },
   },
 };
-</script>
+</script>

+ 14 - 8
src/views/material/order/index.vue

@@ -1,7 +1,7 @@
 <template>
   <div>
-    <Page :fetch="getList">
-      <template #search="{ form, search }">
+    <Page :fetch="getList" >
+      <template #search="{ form, search }" >
         <el-form-item label="订单编号" prop="orderNo">
           <el-input
             v-model="form.orderNo"
@@ -17,7 +17,7 @@
             type="date"
             placeholder="选择日期"
             value-format="yyyy-MM-dd"
-            format="yyyy - MM - dd">
+            format="yyyy-MM-dd">
           </el-date-picker>
         </el-form-item>
       </template>
@@ -40,11 +40,9 @@
         <el-table-column label="采购时间" prop="purchaseTime" min-width="100" />
         <el-table-column label="录入时间" prop="createTime" min-width="100" />
         <el-table-column label="操作" align="left" width="130" fixed="right">
-          <template slot-scope="scope">
-            <el-button size="mini" type="text">详情</el-button>
-            <el-button size="mini" type="text" icon="el-icon-edit"
-              >修改</el-button
-            >
+          <template #default="{ row }">
+            <el-button size="mini" type="text" @click="handleDetail(row)">详情</el-button>
+
           </template>
         </el-table-column>
       </template>
@@ -70,6 +68,14 @@ export default {
         path: "/material/order/add",
       });
     },
+    handleDetail(row) {
+      this.$router.push({
+        path: "/material/order/detail",
+        query: {
+          id: row.id,
+        },
+      });
+    },
    async getList(params){
      var res = await getPurchaseOrderList(params)
      return {list:res.data.data,total:res.data.total}

+ 242 - 0
src/views/store/alerts/list.vue

@@ -0,0 +1,242 @@
+<template>
+    <div style="height: 100%; padding: 20px;">
+        <el-row>
+            <el-col :span="6">
+                <el-input placeholder="请输入店铺名称" v-model="shopName"></el-input>
+            </el-col>
+            <el-col :span="6">
+                <el-date-picker v-model="date" type="date" value-format="yyyy-MM-dd" placeholder="选择日期"></el-date-picker>
+            </el-col>
+            <el-col :span="6">
+                <el-button @click="getList">搜索</el-button>
+                <el-button @click="reset">重置</el-button>
+            </el-col>
+            <el-col :span="6">
+                <el-button type="primary" @click="addWarning">新增预警</el-button>
+            </el-col>
+        </el-row>
+        <el-table :data="tableData" height="400" style="margin-top:30px; ">
+            <el-table-column prop="id" label="店铺ID"></el-table-column>
+            <el-table-column prop="name" label="店铺名称"></el-table-column>
+            <el-table-column prop="contact" label="店铺负责人"></el-table-column>
+            <el-table-column prop="phone" label="联系电话"></el-table-column>
+            <el-table-column prop="mail" label="收件邮箱"></el-table-column>
+            <el-table-column prop="threshold" label="预警阈值"></el-table-column>
+            <el-table-column prop="updateTime" label="更新时间"></el-table-column>
+            <el-table-column label="操作" width="250">
+                <template slot-scope="scope">
+                    <el-button size="mini" @click="viewDetail(scope.row)">详情</el-button>
+                    <el-button size="mini" type="primary" @click="edit(scope.row)">修改</el-button>
+                    <el-button size="mini" type="danger" @click="del(scope.row)">删除</el-button>
+                </template>
+            </el-table-column>
+        </el-table>
+        <el-pagination @current-change="handleCurrentChange" style="margin-top: 20px;" :page-size="pageSize"
+            :current-page="currentPage" :total="total"></el-pagination>
+        <el-dialog title="预警信息" :visible.sync="dialogVisible">
+            <el-form label-width="120px" :model="form" :rules="rules" ref="form">
+                <el-form-item label="选择预警店铺" prop="id" required>
+                    <el-select v-model="form.id">
+                        <template v-for="(item, index) in tableData">
+                            <el-option :label="item.name" :value="item.id"></el-option>
+                        </template>
+                    </el-select>
+                </el-form-item>
+                <el-form-item label="设置预警值" prop="threshold" required>
+                    <el-input v-model="form.threshold" placeholder="请输入初始预警值"></el-input>
+                </el-form-item>
+                <el-form-item label="设置预警区间" prop="alertId" required>
+                    <el-select v-model="form.alertId">
+                        <template v-for="(item, index) in interValList">
+                            <el-option :label="item.desc" :value="item.alertId" />
+                        </template>
+                    </el-select>
+                </el-form-item>
+                <el-form-item label="收件邮箱" prop="mail" required>
+                    <el-input v-model="form.mail" placeholder="请输入收件预警信息邮箱"></el-input>
+                </el-form-item>
+            </el-form>
+            <div slot="footer" class="dialog-footer">
+                <el-button @click="dialogVisible = false">取消设置</el-button>
+                <el-button type="primary" @click="saveSettings">保存设置</el-button>
+            </div>
+        </el-dialog>
+        <!-- 详情查看弹窗 -->
+        <el-dialog title="店铺详情" :visible.sync="detailDialogVisible">
+            <el-form label-width="120px">
+                <el-form-item label="店铺ID">
+                    <span>{{ detailData.id }}</span>
+                </el-form-item>
+                <el-form-item label="店铺名称">
+                    <span>{{ detailData.name }}</span>
+                </el-form-item>
+                <el-form-item label="店铺负责人">
+                    <span>{{ detailData.contact }}</span>
+                </el-form-item>
+                <el-form-item label="联系电话">
+                    <span>{{ detailData.phone }}</span>
+                </el-form-item>
+                <el-form-item label="收件邮箱">
+                    <span>{{ detailData.mail }}</span>
+                </el-form-item>
+                <el-form-item label="预警阈值">
+                    <span>{{ detailData.threshold }}</span>
+                </el-form-item>
+                <el-form-item label="更新时间">
+                    <span>{{ detailData.updateTime }}</span>
+                </el-form-item>
+            </el-form>
+            <div slot="footer" class="dialog-footer">
+                <el-button @click="detailDialogVisible = false">关闭</el-button>
+            </div>
+        </el-dialog>
+    </div>
+</template>
+
+<script>
+import { getStoreAlertsList, addStoreAlerts, updateStoreAlerts, clearStoreAlerts, getInterval } from '@/api/waring';
+export default {
+    data() {
+        return {
+            shopName: '',
+            date: '',
+            tableData: [],
+            pageSize: 10,
+            total: 0,
+            currentPage: 1,
+            dialogVisible: false,
+            form: {},
+            rules: {
+                id: [
+                    { required: true, message: '请选择预警店铺', trigger: 'change' }
+                ],
+                threshold: [
+                    { required: true, message: '请输入初始预警值', trigger: 'blur' },
+                    { validator: this.validateThreshold, trigger: 'blur' }
+                ],
+                warningInterval: [
+                    { required: true, message: '请选择预警区间', trigger: 'change' }
+                ],
+                email: [
+                    { required: true, message: '请输入收件预警信息邮箱', trigger: 'blur' },
+                    { validator: this.validateEmail, trigger: 'blur' }
+                ]
+            },
+            detailDialogVisible: false, // 详情弹窗显示状态
+            detailData: {}, // 存储详情信息
+            interValList: [],
+            actions:'',
+        };
+    },
+    mounted() {
+        // 初始化表格数据
+        this.getList();
+        this.getIntervalsList();
+    },
+    methods: {
+        getIntervalsList() {
+            getInterval().then(res => {
+                console.log(res);
+                this.interValList = res.data;
+            });
+        },
+        async getList() {
+            // 模拟搜索逻辑,实际中应向后台发送请求并更新tableData
+            console.log(`搜索条件:店铺名称 ${this.shopName},日期 ${this.date}`);
+            const query = {
+                page: this.currentPage,
+                size: this.pageSize,
+                name: this.shopName,
+                nextReminderDay:this.date
+            }
+            const { total, records } = await getStoreAlertsList(query);
+            console.log(records);
+            // 这里简单模拟更新数据,实际需要根据后端返回结果更新
+            this.tableData = records;
+            this.total = Number(total);
+        },
+        reset() {
+            // 重置输入框和查询条件
+            this.shopName = '';
+            this.date = '';
+            // 重置表格数据,可根据实际情况恢复默认数据
+            this.getList();
+        },
+        addWarning() {
+            // 模拟新增预警逻辑,实际中应弹出表单让用户输入信息并发送到后端
+            console.log('点击了新增预警');
+            this.form = {};
+            this.dialogVisible = true;
+        },
+        saveSettings() {
+            this.$refs.form.validate((valid) => {
+                if (valid) {
+                    if(this.actions=='edit'){
+                        updateStoreAlerts(this.form.id,this.form).then(res=>{
+                            this.getList();
+                            this.dialogVisible = false;
+                        })
+                        return
+                    }
+                    addStoreAlerts(this.form).then(res => {
+                        console.log('保存成功');
+                        this.getList();
+                        this.dialogVisible = false;
+                    });
+                }
+            });
+        },
+        viewDetail(row) {
+            // 点击详情按钮,将当前行数据赋值给详情数据对象,并显示详情弹窗
+            this.detailData = row;
+            this.detailDialogVisible = true;
+        },
+        edit(row) {
+            // 点击修改按钮,将当前行数据赋值给表单对象,并显示弹窗
+            this.form = {
+                id: row.id,
+                threshold: row.threshold,
+                warningInterval: row.warningInterval,
+                mail: row.mail,
+                alertId:row.alertId,
+            };
+            this.actions = 'edit'
+            this.dialogVisible = true;
+        },
+        del(row) {
+            //弹窗确认
+            this.$modal.confirm('是否确认删除' + row.name + '"吗?').then( ()=>{
+                clearStoreAlerts(row.id).then(res => {
+                    this.$modal.msgSuccess("删除成功");
+                    this.getList();
+                });
+            }).catch(function (e) {
+                console.log(e)
+            });
+
+        },
+        handleCurrentChange(page) {
+            // 分页切换逻辑,向后台请求对应页码数据
+            console.log(`切换到第 ${page} 页`);
+            this.currentPage = page;
+            this.getList();
+            // 这里可根据页码向后台请求数据并更新tableData
+        },
+        validateThreshold(rule, value, callback) {
+            if (isNaN(parseFloat(value)) || parseFloat(value) <= 0) {
+                callback(new Error('预警值必须是大于0的数字'));
+            } else {
+                callback();
+            }
+        },
+        validateEmail(rule, value, callback) {
+            const emailReg = /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/;
+            if (!emailReg.test(value)) {
+                callback(new Error('请输入有效的邮箱地址'));
+            } else {
+                callback();
+            }
+        }
+    }
+};
+</script>