فهرست منبع

问题修复;增加图片裁剪功能等

htc 13 ساعت پیش
والد
کامیت
954e561ef4

+ 5 - 0
package-lock.json

@@ -18510,6 +18510,11 @@
         "vue": "^2.5.9"
       }
     },
+    "vue-cropper": {
+      "version": "0.6.5",
+      "resolved": "https://registry.npmmirror.com/vue-cropper/-/vue-cropper-0.6.5.tgz",
+      "integrity": "sha512-lSvY6IpeA/Tv/iPZ/FOkMHVRBPSlm7t57nuHEZFBMRNOH8ElvfqVlnHGDOAMlvPhh9gHiddiQoASS+fY0MFX0g=="
+    },
     "vue-eslint-parser": {
       "version": "2.0.3",
       "resolved": "https://registry.npmmirror.com/vue-eslint-parser/-/vue-eslint-parser-2.0.3.tgz",

+ 1 - 0
package.json

@@ -37,6 +37,7 @@
     "svg-sprite-loader": "^4.1.6",
     "vue": "^2.6.10",
     "vue-cron": "^1.0.9",
+    "vue-cropper": "^0.6.5",
     "vue-i18n": "^8.12.0",
     "vue-quill-editor": "^3.0.6",
     "vue-router": "^3.0.7",

+ 297 - 0
src/components/cropperDlg/index.vue

@@ -0,0 +1,297 @@
+<template>
+  <el-dialog
+    title="图片剪裁"
+    :visible="dialogVisible"
+    class="crop-dialog"
+    append-to-body
+    @close="close()"
+  >
+    <div>
+      <div class="cropper-content">
+        <!--  -->
+        <!-- 剪裁框 -->
+        <div
+          class="cropper"
+          :style="{
+            width: option.autoCropWidth + 'px',
+            height: option.autoCropHeight + 'px',
+          }"
+        >
+          <VueCropper
+            ref="cropper"
+            :img="option.img"
+            :outputSize="option.size"
+            :outputType="option.outputType"
+            :info="true"
+            :full="option.full"
+            :canMove="option.canMove"
+            :canMoveBox="option.canMoveBox"
+            :original="option.original"
+            :autoCrop="option.autoCrop"
+            :autoCropWidth="option.autoCropWidth"
+            :autoCropHeight="option.autoCropHeight"
+            :fixedBox="option.fixedBox"
+            @realTime="realTime"
+            :fixed="option.fixed"
+            listType="picture-card"
+            :fixedNumber="fixedNumber"
+          ></VueCropper>
+        </div>
+        <!-- 预览框 -->
+        <div
+          class="show-preview"
+          :style="{
+            width: '50%',
+            height: '428px',
+            overflow: 'hidden',
+            margin: '0 25px',
+            display: 'flex',
+            'align-items': 'center',
+          }"
+        >
+          <div :style="previews.div" class="preview">
+            <img :src="previews.url" :style="previews.img" />
+          </div>
+        </div>
+      </div>
+      <div class="footer-btn">
+        <!-- 缩放旋转按钮 -->
+        <div class="scope-btn">
+          <el-button
+            type="primary"
+            icon="el-icon-zoom-in"
+            @click="changeScale(1)"
+          ></el-button>
+          <el-button
+            type="primary"
+            icon="el-icon-zoom-out"
+            @click="changeScale(-1)"
+          ></el-button>
+          <el-button type="primary" @click="rotateLeft">逆时针旋转</el-button>
+          <el-button type="primary" @click="rotateRight">顺时针旋转</el-button>
+        </div>
+        <!-- 确认上传按钮 -->
+        <div class="upload-btn">
+          <el-button type="primary" @click="uploadImg('blob')">确定</el-button>
+        </div>
+      </div>
+    </div>
+  </el-dialog>
+</template>
+
+<script>
+export default {
+  data() {
+    return {
+      previews: {}, // 预览数据
+      option: {
+        img: "", // 裁剪图片的地址  (默认:空)
+        size: 1, // 裁剪生成图片的质量  (默认:1)
+        full: true, // 是否输出原图比例的截图 选true生成的图片会非常大  (默认:false)
+        outputType: "png", // 裁剪生成图片的格式  (默认:jpg)
+        canMove: true, // 上传图片是否可以移动  (默认:true)
+        original: true, // 上传图片按照原始比例渲染  (默认:false)
+        canMoveBox: true, // 截图框能否拖动  (默认:true)
+        autoCrop: true, // 是否默认生成截图框  (默认:false)
+        autoCropWidth: 316, // 默认生成截图框宽度  (默认:80%)
+        autoCropHeight: 428, // 默认生成截图框高度  (默认:80%)
+        fixedBox: false, // 固定截图框大小 不允许改变  (默认:false)
+        fixed: false, // 是否开启截图框宽高固定比例  (默认:true)
+        fixedNumber: [1, 1], // 截图框比例  (默认:[1:1])
+      },
+      data: "",
+      downImg: "#",
+    };
+  },
+  props: ["imgFile", "fixedNumber", "dialogVisible", "w", "h"],
+  mounted() {},
+  methods: {
+    init() {
+      if (this.w && this.h) {
+        if (this.w > this.h) {
+          this.option.autoCropHeight =
+            this.option.autoCropWidth * ((1 / this.w) * this.h);
+        } else {
+          this.option.autoCropWidth =
+            this.option.autoCropWidth * ((1 / this.h) * this.w);
+        }
+      }else{
+         this.option.autoCropHeight = this.option.autoCropHeight =428;
+      }
+      this.$nextTick(() => {
+        var reader = new FileReader();
+        reader.onload = (e) => {
+          let data;
+          if (typeof e.target.result === "object") {
+            data = window.URL.createObjectURL(new Blob([e.target.result]));
+          } else {
+            data = e.target.result;
+            this.data = data;
+          }
+          this.option.img = data;
+        };
+        // 转化为base64
+        // reader.readAsDataURL(this.imgFile)
+        // 转化为blob
+        reader.readAsArrayBuffer(this.imgFile);
+        setTimeout(() => {
+          let autoCropWidth = this.option.autoCropWidth;
+          let autoCropHeight = this.option.autoCropHeight;
+          this.getImgWidthHeight(this.imgFile, (data) => {
+            if (data.width > autoCropWidth && data.height < autoCropHeight) {
+              let sfbl = autoCropHeight / data.height;
+              this.toChangeScale(sfbl);
+            } else if (data.width < autoCropWidth && data.height > autoCropHeight) {
+              let sfbl = autoCropWidth / data.width;
+              this.toChangeScale(sfbl);
+            } else if (data.width < autoCropWidth && data.height < autoCropHeight) {
+              let sfbl = 1;
+              if (data.width < data.height) sfbl = autoCropWidth / data.width;
+              else sfbl = autoCropHeight / data.height;
+              this.toChangeScale(sfbl);
+            } else {
+              let sfbl = 1;
+              if (data.width < data.height) sfbl = autoCropWidth / data.width;
+              else sfbl = autoCropHeight / data.height;
+              this.toChangeScale(sfbl);
+            }
+          });
+        }, 800);
+      });
+    },
+    toChangeScale(sfbl) {
+      this.$nextTick(() => {
+        this.getImgWidthHeight(this.imgFile, (data) => {});
+        this.$refs.cropper.scale = sfbl;
+      });
+    },
+    getImgWidthHeight(file, callback) {
+      var reader = new FileReader();
+      reader.onload = function (event) {
+        var base64 = event.target.result;
+        var img = document.createElement("img");
+        img.src = base64;
+        img.onload = function () {
+          callback && callback({ width: img.width, height: img.height });
+        };
+      };
+      reader.readAsDataURL(file);
+    },
+    changeScale(num) {
+      this.getImgWidthHeight(this.imgFile, (data) => {
+        console.log(data);
+        console.log(num);
+      });
+      // 图片缩放
+      num = num || 1;
+      console.log(num);
+      this.$refs.cropper.changeScale(num);
+    },
+    rotateLeft() {
+      // 向左旋转
+      this.$refs.cropper.rotateLeft();
+    },
+    rotateRight() {
+      // 向右旋转
+      this.$refs.cropper.rotateRight();
+    },
+    realTime(data) {
+      // 实时预览
+      this.previews = data;
+    },
+    close() {
+      this.$emit("upload", "close");
+    },
+    uploadImg(type) {
+      // 将剪裁好的图片回传给父组件
+      event.preventDefault();
+      let that = this;
+      if (type === "blob") {
+        this.$refs.cropper.getCropBlob((data) => {
+          let formData = new FormData();
+
+          formData.append("file", data, that.imgFile.name);
+          that.$emit("upload", formData);
+        });
+      } else {
+        this.$refs.cropper.getCropData((data) => {
+          that.$emit("upload", formData);
+        });
+      }
+    },
+  },
+};
+</script>
+<style>
+.cropper-content {
+  display: flex;
+  display: -webkit-flex;
+  justify-content: flex-end;
+  -webkit-justify-content: flex-end;
+  width: 100%;
+}
+.cropper-content .cropper {
+  width: 50%;
+  height: 428px;
+}
+.cropper-content .show-preview {
+  width: 50%;
+  height: 428px;
+  display: flex;
+  display: -webkit-flex;
+  justify-content: center;
+  -webkit-justify-content: center;
+  overflow: hidden;
+  border: 1px solid #cccccc;
+  /* background: #cccccc; */
+  margin-left: 40px;
+}
+.preview {
+  overflow: hidden;
+  border: 1px solid #e9ebef;
+  background: #e9ebef;
+}
+.footer-btn {
+  margin-top: 30px;
+  display: flex;
+  display: -webkit-flex;
+  justify-content: flex-end;
+  -webkit-justify-content: flex-end;
+}
+.footer-btn .scope-btn {
+  width: 50%;
+  display: flex;
+  display: -webkit-flex;
+}
+.footer-btn .upload-btn {
+  width: 50%;
+  display: flex;
+  display: -webkit-flex;
+  justify-content: center;
+  -webkit-justify-content: center;
+  padding: 0 14px;
+}
+.footer-btn .btn {
+  outline: none;
+  display: inline-block;
+  line-height: 1;
+  white-space: nowrap;
+  cursor: pointer;
+  -webkit-appearance: none;
+  text-align: center;
+  -webkit-box-sizing: border-box;
+  box-sizing: border-box;
+  outline: 0;
+  margin: 0;
+  -webkit-transition: 0.1s;
+  transition: 0.1s;
+  font-weight: 500;
+  padding: 8px 15px;
+  font-size: 12px;
+  border-radius: 3px;
+  color: #fff;
+  background-color: #67c23a;
+  border-color: #67c23a;
+}
+</style>
+

+ 297 - 0
src/components/cropperDlg/index2.vue

@@ -0,0 +1,297 @@
+<template>
+  <el-dialog
+    title="图片剪裁"
+    :visible="dialogVisible"
+    class="crop-dialog"
+    append-to-body
+    @close="close()"
+  >
+    <div>
+      <div class="cropper-content">
+        <!--  -->
+        <!-- 剪裁框 -->
+        <div
+          class="cropper"
+          :style="{
+            width: option.autoCropWidth + 'px',
+            height: option.autoCropHeight + 'px',
+          }"
+        >
+          <VueCropper
+            ref="cropper"
+            :img="option.img"
+            :outputSize="option.size"
+            :outputType="option.outputType"
+            :info="true"
+            :full="option.full"
+            :canMove="option.canMove"
+            :canMoveBox="option.canMoveBox"
+            :original="option.original"
+            :autoCrop="option.autoCrop"
+            :autoCropWidth="option.autoCropWidth"
+            :autoCropHeight="option.autoCropHeight"
+            :fixedBox="option.fixedBox"
+            @realTime="realTime"
+            :fixed="option.fixed"
+            listType="picture-card"
+            :fixedNumber="fixedNumber"
+          ></VueCropper>
+        </div>
+        <!-- 预览框 -->
+        <div
+          class="show-preview"
+          :style="{
+            width: '50%',
+            height: '220px',
+            overflow: 'hidden',
+            margin: '0 25px',
+            display: 'flex',
+            'align-items': 'center',
+          }"
+        >
+          <div :style="previews.div" class="preview">
+            <img :src="previews.url" :style="previews.img" />
+          </div>
+        </div>
+      </div>
+      <div class="footer-btn">
+        <!-- 缩放旋转按钮 -->
+        <div class="scope-btn">
+          <el-button
+            type="primary"
+            icon="el-icon-zoom-in"
+            @click="changeScale(1)"
+          ></el-button>
+          <el-button
+            type="primary"
+            icon="el-icon-zoom-out"
+            @click="changeScale(-1)"
+          ></el-button>
+          <el-button type="primary" @click="rotateLeft">逆时针旋转</el-button>
+          <el-button type="primary" @click="rotateRight">顺时针旋转</el-button>
+        </div>
+        <!-- 确认上传按钮 -->
+        <div class="upload-btn">
+          <el-button type="primary" @click="uploadImg('blob')">确定</el-button>
+        </div>
+      </div>
+    </div>
+  </el-dialog>
+</template>
+
+<script>
+export default {
+  data() {
+    return {
+      previews: {}, // 预览数据
+      option: {
+        img: "", // 裁剪图片的地址  (默认:空)
+        size: 1, // 裁剪生成图片的质量  (默认:1)
+        full: true, // 是否输出原图比例的截图 选true生成的图片会非常大  (默认:false)
+        outputType: "png", // 裁剪生成图片的格式  (默认:jpg)
+        canMove: true, // 上传图片是否可以移动  (默认:true)
+        original: true, // 上传图片按照原始比例渲染  (默认:false)
+        canMoveBox: true, // 截图框能否拖动  (默认:true)
+        autoCrop: true, // 是否默认生成截图框  (默认:false)
+        autoCropWidth: 351, // 默认生成截图框宽度  (默认:80%)
+        autoCropHeight: 220, // 默认生成截图框高度  (默认:80%)
+        fixedBox: false, // 固定截图框大小 不允许改变  (默认:false)
+        fixed: false, // 是否开启截图框宽高固定比例  (默认:true)
+        fixedNumber: [1, 1], // 截图框比例  (默认:[1:1])
+      },
+      data: "",
+      downImg: "#",
+    };
+  },
+  props: ["imgFile", "fixedNumber", "dialogVisible", "w", "h"],
+  mounted() {},
+  methods: {
+    init() {
+      if (this.w && this.h) {
+        if (this.w > this.h) {
+          this.option.autoCropHeight =
+            this.option.autoCropWidth * ((1 / this.w) * this.h);
+        } else {
+          this.option.autoCropWidth =
+            this.option.autoCropWidth * ((1 / this.h) * this.w);
+        }
+      }else{
+         this.option.autoCropHeight = this.option.autoCropHeight =220;
+      }
+      this.$nextTick(() => {
+        var reader = new FileReader();
+        reader.onload = (e) => {
+          let data;
+          if (typeof e.target.result === "object") {
+            data = window.URL.createObjectURL(new Blob([e.target.result]));
+          } else {
+            data = e.target.result;
+            this.data = data;
+          }
+          this.option.img = data;
+        };
+        // 转化为base64
+        // reader.readAsDataURL(this.imgFile)
+        // 转化为blob
+        reader.readAsArrayBuffer(this.imgFile);
+        setTimeout(() => {
+          let autoCropWidth = this.option.autoCropWidth;
+          let autoCropHeight = this.option.autoCropHeight;
+          this.getImgWidthHeight(this.imgFile, (data) => {
+            if (data.width > autoCropWidth && data.height < autoCropHeight) {
+              let sfbl = autoCropHeight / data.height;
+              this.toChangeScale(sfbl);
+            } else if (data.width < autoCropWidth && data.height > autoCropHeight) {
+              let sfbl = autoCropWidth / data.width;
+              this.toChangeScale(sfbl);
+            } else if (data.width < autoCropWidth && data.height < autoCropHeight) {
+              let sfbl = 1;
+              if (data.width < data.height) sfbl = autoCropWidth / data.width;
+              else sfbl = autoCropHeight / data.height;
+              this.toChangeScale(sfbl);
+            } else {
+              let sfbl = 1;
+              if (data.width < data.height) sfbl = autoCropWidth / data.width;
+              else sfbl = autoCropHeight / data.height;
+              this.toChangeScale(sfbl);
+            }
+          });
+        }, 800);
+      });
+    },
+    toChangeScale(sfbl) {
+      this.$nextTick(() => {
+        this.getImgWidthHeight(this.imgFile, (data) => {});
+        this.$refs.cropper.scale = sfbl;
+      });
+    },
+    getImgWidthHeight(file, callback) {
+      var reader = new FileReader();
+      reader.onload = function (event) {
+        var base64 = event.target.result;
+        var img = document.createElement("img");
+        img.src = base64;
+        img.onload = function () {
+          callback && callback({ width: img.width, height: img.height });
+        };
+      };
+      reader.readAsDataURL(file);
+    },
+    changeScale(num) {
+      this.getImgWidthHeight(this.imgFile, (data) => {
+        console.log(data);
+        console.log(num);
+      });
+      // 图片缩放
+      num = num || 1;
+      console.log(num);
+      this.$refs.cropper.changeScale(num);
+    },
+    rotateLeft() {
+      // 向左旋转
+      this.$refs.cropper.rotateLeft();
+    },
+    rotateRight() {
+      // 向右旋转
+      this.$refs.cropper.rotateRight();
+    },
+    realTime(data) {
+      // 实时预览
+      this.previews = data;
+    },
+    close() {
+      this.$emit("upload", "close");
+    },
+    uploadImg(type) {
+      // 将剪裁好的图片回传给父组件
+      event.preventDefault();
+      let that = this;
+      if (type === "blob") {
+        this.$refs.cropper.getCropBlob((data) => {
+          let formData = new FormData();
+
+          formData.append("file", data, that.imgFile.name);
+          that.$emit("upload", formData);
+        });
+      } else {
+        this.$refs.cropper.getCropData((data) => {
+          that.$emit("upload", formData);
+        });
+      }
+    },
+  },
+};
+</script>
+<style>
+.cropper-content {
+  display: flex;
+  display: -webkit-flex;
+  justify-content: flex-end;
+  -webkit-justify-content: flex-end;
+  width: 100%;
+}
+.cropper-content .cropper {
+  width: 50%;
+  height: 220px;
+}
+.cropper-content .show-preview {
+  width: 50%;
+  height: 220px;
+  display: flex;
+  display: -webkit-flex;
+  justify-content: center;
+  -webkit-justify-content: center;
+  overflow: hidden;
+  border: 1px solid #cccccc;
+  /* background: #cccccc; */
+  margin-left: 40px;
+}
+.preview {
+  overflow: hidden;
+  border: 1px solid #e9ebef;
+  background: #e9ebef;
+}
+.footer-btn {
+  margin-top: 30px;
+  display: flex;
+  display: -webkit-flex;
+  justify-content: flex-end;
+  -webkit-justify-content: flex-end;
+}
+.footer-btn .scope-btn {
+  width: 50%;
+  display: flex;
+  display: -webkit-flex;
+}
+.footer-btn .upload-btn {
+  width: 50%;
+  display: flex;
+  display: -webkit-flex;
+  justify-content: center;
+  -webkit-justify-content: center;
+  padding: 0 14px;
+}
+.footer-btn .btn {
+  outline: none;
+  display: inline-block;
+  line-height: 1;
+  white-space: nowrap;
+  cursor: pointer;
+  -webkit-appearance: none;
+  text-align: center;
+  -webkit-box-sizing: border-box;
+  box-sizing: border-box;
+  outline: 0;
+  margin: 0;
+  -webkit-transition: 0.1s;
+  transition: 0.1s;
+  font-weight: 500;
+  padding: 8px 15px;
+  font-size: 12px;
+  border-radius: 3px;
+  color: #fff;
+  background-color: #67c23a;
+  border-color: #67c23a;
+}
+</style>
+

+ 1 - 1
src/components/editor/index.vue

@@ -142,6 +142,6 @@ export default {
 }
 
 .sicepot .ql-container.ql-snow {
-    height: 200px !important;
+    height: 600px !important;
 }
 </style>

+ 7 - 0
src/main.js

@@ -16,9 +16,16 @@ import renProcessRunning from '@/components/ren-process-running'
 import renProcessDetail from '@/components/ren-process-detail'
 import renDeptTree from '@/components/ren-dept-tree'
 import renRegionTree from '@/components/ren-region-tree'
+import cropperDlg from '@/components/cropperDlg'
+import cropperDlg2 from '@/components/cropperDlg/index2.vue'
 import { hasPermission, getDictLabel } from '@/utils'
 import cloneDeep from 'lodash/cloneDeep'
 
+import VueCropper from 'vue-cropper'
+Vue.use(VueCropper)
+Vue.component('cropperDlg', cropperDlg)
+Vue.component('cropperDlg2', cropperDlg2)
+
 Vue.config.productionTip = false
 
 Vue.use(Element, {

+ 82 - 16
src/views/modules/activity/add.vue

@@ -16,12 +16,12 @@
             <div class="form" v-if="tidx===1">
                 <el-form ref="basicRef" :model="basicForm" :rules="basicRules" label-width="125px">
                     <el-form-item label="活动类型" prop="typeId">
-                        <el-select v-model="basicForm.typeId" placeholder="请选择活动类型" class="select-box" style="width: 390px;">
+                        <el-select v-model="basicForm.typeId" placeholder="请选择活动类型" class="select-box" style="width: 440px;">
                             <el-option v-for="item in typeOptions" :key="item.id" :label="item.typeName" :value="item.id"></el-option>
                         </el-select>
                     </el-form-item>
                     <el-form-item label="活动分类" prop="categoryId">
-                        <el-select v-model="basicForm.categoryId" placeholder="请选择活动分类" class="select-box" style="width: 390px;">
+                        <el-select v-model="basicForm.categoryId" placeholder="请选择活动分类" class="select-box" style="width: 440px;">
                             <el-option v-for="item in categoryOptions" :key="item.id" :label="item.categoryName" :value="item.id"></el-option>
                         </el-select>
                     </el-form-item>
@@ -30,37 +30,37 @@
                     </el-form-item>
                     <el-form-item label="报名时间" prop="signupEndTime">
                       <div class="adfac">
-                        <el-date-picker v-model="basicForm.signupStartTime" @change="e=>handleSignupDateChange(e,'signupStartTime')" type="datetime" format="yyyy-MM-dd HH:mm" placeholder="年/月/日 - -:- -" style="width: 180px;"></el-date-picker>
+                        <el-date-picker v-model="basicForm.signupStartTime" @change="e=>handleSignupDateChange(e,'signupStartTime')" type="datetime" format="yyyy-MM-dd HH:mm" placeholder="年/月/日 - -:- -" style="width: 205px;"></el-date-picker>
                         <span style="margin: 0 10px;">至</span>
-                        <el-date-picker v-model="basicForm.signupEndTime" @change="e=>handleSignupDateChange(e,'signupEndTime')" type="datetime" format="yyyy-MM-dd HH:mm" placeholder="年/月/日 - -:- -" style="width: 180px;"></el-date-picker>
+                        <el-date-picker v-model="basicForm.signupEndTime" @change="e=>handleSignupDateChange(e,'signupEndTime')" type="datetime" format="yyyy-MM-dd HH:mm" placeholder="年/月/日 - -:- -" style="width: 205px;"></el-date-picker>
                       </div>
                     </el-form-item>
                     <el-form-item label="活动时间" prop="activityEndTime">
                       <div class="adfac">
-                        <el-date-picker v-model="basicForm.activityStartTime" @change="e=>handleActivityDateChange(e,'activityStartTime')" type="datetime" format="yyyy-MM-dd HH:mm" placeholder="年/月/日 - -:- -" style="width: 180px;"></el-date-picker>
+                        <el-date-picker v-model="basicForm.activityStartTime" @change="e=>handleActivityDateChange(e,'activityStartTime')" type="datetime" format="yyyy-MM-dd HH:mm" placeholder="年/月/日 - -:- -" style="width: 205px;"></el-date-picker>
                         <span style="margin: 0 10px;">至</span>
-                        <el-date-picker v-model="basicForm.activityEndTime" @change="e=>handleActivityDateChange(e,'activityEndTime')" type="datetime" format="yyyy-MM-dd HH:mm" placeholder="年/月/日 - -:- -" style="width: 180px;"></el-date-picker>
+                        <el-date-picker v-model="basicForm.activityEndTime" @change="e=>handleActivityDateChange(e,'activityEndTime')" type="datetime" format="yyyy-MM-dd HH:mm" placeholder="年/月/日 - -:- -" style="width: 205px;"></el-date-picker>
                       </div>
                     </el-form-item>
                     <el-form-item label="活动地点" prop="districtId">
-                        <el-select v-model="basicForm.provinceId" placeholder="省" clearable  style="width: 14%" @change="val=>regionChange(val, 'province')">
+                        <el-select v-model="basicForm.provinceId" placeholder="省" clearable  style="width: 14.5%" @change="val=>regionChange(val, 'province')">
                             <el-option v-for="item in provinceOptions" :key="item.id" :label="item.name" :value="item.id"></el-option>
                         </el-select>
-                        <el-select v-model="basicForm.cityId" placeholder="市" clearable  style="width: 14%; margin: 0 1%" @change="val=>regionChange(val, 'city')">
+                        <el-select v-model="basicForm.cityId" placeholder="市" clearable  style="width: 14.5%; margin: 0 1%" @change="val=>regionChange(val, 'city')">
                             <el-option v-for="item in cityOptions" :key="item.id" :label="item.name" :value="item.id"></el-option>
                         </el-select>
-                        <el-select v-model="basicForm.districtId" placeholder="区" clearable  style="width: 14%; margin: 0 1%" @change="val=>regionChange(val, 'area')">
+                        <el-select v-model="basicForm.districtId" placeholder="区" clearable  style="width: 14.5%; margin: 0 1% 0 0" @change="val=>regionChange(val, 'area')">
                             <el-option v-for="item in areaOptions" :key="item.id" :label="item.name" :value="item.id"></el-option>
                         </el-select>
-                        <el-input v-model="basicForm.address" placeholder="详细地址" style="width: 40%"></el-input>
+                        <el-input v-model="basicForm.address" placeholder="详细地址" style="width: 53.5%"></el-input>
                     </el-form-item>
                     <el-form-item label="渠道方" prop="channelId">
-                        <el-select v-model="basicForm.channelId" placeholder="请选择渠道方" class="select-box" style="width: 390px;">
+                        <el-select v-model="basicForm.channelId" placeholder="请选择渠道方" class="select-box" style="width: 440px;">
                             <el-option v-for="item in channelOptions" :key="item.id" :label="item.channelName" :value="item.id"></el-option>
                         </el-select>
                     </el-form-item>
                     <el-form-item label="举办方" prop="organizerId">
-                        <el-select v-model="basicForm.organizerId" placeholder="请选择举办方" class="select-box" style="width: 390px;">
+                        <el-select v-model="basicForm.organizerId" placeholder="请选择举办方" class="select-box" style="width: 440px;">
                             <el-option v-for="item in organizerOptions" :key="item.id" :label="item.channelName" :value="item.id"></el-option>
                         </el-select>
                     </el-form-item>
@@ -69,7 +69,7 @@
                             :action="url"
                             :file-list="fileListCover"
                             :limit="1"
-                            :before-upload="file => beforeUploadHandle(file, 1, [158, 214])"
+                            :before-upload="file => beforeUploadHandle(file, 1, [158, 214], 'coverFile')"
                             list-type="picture-card"
                             :on-success="successHandleCover"
                             :on-remove="handleRemoveCover"
@@ -84,7 +84,7 @@
                             :action="url"
                             :file-list="fileListBanner"
                             :limit="6"
-                            :before-upload="file => beforeUploadHandle(file, 2, [702, 440])"
+                            :before-upload="file => beforeUploadHandle(file, 2, [702, 440], 'banner')"
                             list-type="picture-card"
                             :on-success="successHandleBanner"
                             :on-remove="handleRemoveBanner"
@@ -194,6 +194,21 @@
                 </div>
             </div>
         </div>
+        <!-- 裁剪框 -->
+        <cropper-dlg
+          v-if="showCropper"
+          :dialogVisible.sync="showCropper"
+          :img-file="currentFile"
+          ref="vueCropper"
+          @upload="cropperUpload"
+        ></cropper-dlg>
+        <cropper-dlg2
+          v-if="showCropper2"
+          :dialogVisible.sync="showCropper2"
+          :img-file="currentFile2"
+          ref="vueCropper2"
+          @upload="cropperUpload2"
+        ></cropper-dlg2>
     </el-card>
 </template>
 
@@ -207,6 +222,15 @@ export default {
   mixins: [mixinRegionModule],
   data () {
     return {
+      currentFile: '',
+      cropperIndex: null,
+      showCropper: false,
+      isCropper: true,
+      currentFile2: '',
+      cropperIndex2: null,
+      showCropper2: false,
+      isCropper2: true,
+      updType: 1,
       typeOptions: [],
       categoryOptions: [],
       channelOptions: [],
@@ -414,13 +438,55 @@ export default {
     handleActivityDateChange (val, key) {
       this.basicForm[key] = moment(val).format('YYYY-MM-DD HH:mm')
     },
-    beforeUploadHandle (file, index, fixedNumber) {
+    beforeUploadHandle (file, index, fixedNumber, name) {
+      this.updType = index
       if (file.type !== 'image/jpg' && file.type !== 'image/jpeg' && file.type !== 'image/png') {
         this.$message.error(
           this.$t('upload.tip', { format: 'jpg、png、gif' })
         )
         return false
       }
+      if (this.updType === 1) {
+        if (this.isCropper) {
+          this.currentFile = file
+          this.cropperIndex = name
+          this.showCropper = true
+          this.$nextTick(() => {
+            this.$refs.vueCropper.init()
+          })
+          return false
+        }
+      } else if (this.updType === 2) {
+        if (this.isCropper2) {
+          this.currentFile2 = file
+          this.cropperIndex2 = name
+          this.showCropper2 = true
+          this.$nextTick(() => {
+            this.$refs.vueCropper2.init()
+          })
+          return false
+        }
+      }
+    },
+    cropperUpload (data) {
+      this.showCropper = false
+      if (data !== 'close') {
+        this.$http.post('/sys/oss/upload', data).then((res) => {
+          if (res.data.code === 0) {
+            this.successHandleCover(res.data)
+          }
+        })
+      }
+    },
+    cropperUpload2 (data) {
+      this.showCropper2 = false
+      if (data !== 'close') {
+        this.$http.post('/sys/oss/upload', data).then((res) => {
+          if (res.data.code === 0) {
+            this.successHandleBanner(res.data)
+          }
+        })
+      }
     },
     handleRemoveCover (file, fileList) {
       this.fileListCover = fileList.map((item) => item) || []
@@ -673,7 +739,7 @@ export default {
     font-family: PingFangSC, PingFang SC;
     font-weight: 400;
     font-size: 12px;
-    color: #A4A4A4;
+    color: #F4657A;
     line-height: 17px;
     margin-left: 20px;
   }

+ 2 - 2
src/views/modules/activity/info.vue

@@ -59,8 +59,8 @@
                 <el-table-column prop="contactPhoneJM" label="手机号码" width="150"></el-table-column>
                 <el-table-column prop="channelName" label="渠道方" width="200"></el-table-column>
                 <el-table-column prop="name" label="姓名" width="150"></el-table-column>
-                <el-table-column prop="idCardJM" label="身份证号" width="300"></el-table-column>
-                <el-table-column prop="volunteerNo" label="义工号" width="100"></el-table-column>
+                <el-table-column prop="idCardJM" label="身份证号" width="200"></el-table-column>
+                <el-table-column prop="volunteerNo" label="义工号" width="180"></el-table-column>
                 <el-table-column prop="gender" label="性别" width="100">
                     <template slot-scope="scope">{{ genderDict[scope.row.gender] || '' }}</template>
                 </el-table-column>

+ 3 - 2
src/views/modules/activity/list.vue

@@ -60,11 +60,12 @@
               </el-table-column>
               <el-table-column prop="channelName" label="渠道方" width="120"></el-table-column>
               <el-table-column prop="organizerName" label="举办方" width="120"></el-table-column>
+              <el-table-column prop="createDate" label="创建时间" width="180"></el-table-column>
               <el-table-column label="操作" width="270" fixed="right">
                   <template #default="scope">
                       <!-- <el-button link type="text" @click="handleEdit(scope.row)" v-if="scope.row.activeState!=3&&$hasPermission('core:activity:update')">编辑</el-button> -->
                       <el-button link type="text" @click="handleEdit(scope.row)" v-if="scope.row.activeState<2&&$hasPermission('core:activity:update')">编辑</el-button>
-                      <el-button link type="text" @click="handleInfo(scope.row)" v-if="scope.row.activeState!=0&&$hasPermission('core:activity:info')">报名信息</el-button>
+                      <el-button link type="text" @click="handleInfo(scope.row)" v-if="$hasPermission('core:activity:info')">报名信息</el-button>
                       <el-button link type="text" @click="handleCode(scope.row)" v-if="!scope.row.signCode&&scope.row.activeState==2&&$hasPermission('core:activity:code')">生成签到码</el-button>
                       <el-button link type="text" @click="handleReviewCode(scope.row)" v-if="scope.row.signCode&&scope.row.activeState==2&&$hasPermission('core:activity:code')">查看签到码</el-button>
                       <!-- <el-button link type="text" @click="handleUpDown(scope.row,0)" v-if="scope.row.state==1&&(scope.row.activeState==0||scope.row.activeState==3)&&$hasPermission('core:activity:updown')">下架</el-button> -->
@@ -215,7 +216,7 @@ export default {
       this.show = false
     },
     handleUpDown (row, state) {
-      if ([1, 2].includes(row.activeState) && row.recruitmentNow > 0) return this.$message.error('当前活动已存在报名人数,无法下架')
+      if ([0, 1, 2].includes(row.activeState) && row.recruitmentNow > 0) return this.$message.error(`当前活动已存在报名人数,无法${state ? '上架' : '下架'}`)
       this.$confirm(`是否确认${state ? '上架' : '下架'}活动【${row.activityName}】?`, '提示', {
         confirmButtonText: '确定',
         cancelButtonText: '取消',