Jelajahi Sumber

活动列表相关页面接口联调完成(渠道服和举办方暂无相关页面设计图,活动报名信息等小程序接口联调完成有数据后再优化)

htc 1 Minggu lalu
induk
melakukan
51e5b8523d

+ 2 - 1
node_modules/js-cookie/package.json

@@ -16,12 +16,13 @@
     "fetchSpec": "^2.2.0"
   },
   "_requiredBy": [
+    "#USER",
     "/"
   ],
   "_resolved": "https://registry.npmmirror.com/js-cookie/-/js-cookie-2.2.1.tgz",
   "_shasum": "69e106dc5d5806894562902aa5baec3744e9b2b8",
   "_spec": "js-cookie@^2.2.0",
-  "_where": "D:\\HTC\\program\\善行少年\\security-enterprise-admin",
+  "_where": "D:\\HTC\\program\\善行少年\\SxsnPC",
   "author": {
     "name": "Klaus Hartl"
   },

+ 21 - 0
package-lock.json

@@ -12497,6 +12497,11 @@
         "minimist": "^1.2.6"
       }
     },
+    "moment": {
+      "version": "2.30.1",
+      "resolved": "https://registry.npmmirror.com/moment/-/moment-2.30.1.tgz",
+      "integrity": "sha512-uEmtNhbDOrWPFS+hdjFCBfy9f2YoyzRpwcl+DqpC6taX21FzsTLQVbMV/W7PzNSX6x/bhC1zA3c2UQ5NzH6how=="
+    },
     "move-concurrently": {
       "version": "1.0.1",
       "resolved": "https://registry.npmmirror.com/move-concurrently/-/move-concurrently-1.0.1.tgz",
@@ -18530,6 +18535,22 @@
         "vue-style-loader": "^4.1.0"
       }
     },
+    "vue-quill-editor": {
+      "version": "3.0.6",
+      "resolved": "https://registry.npmmirror.com/vue-quill-editor/-/vue-quill-editor-3.0.6.tgz",
+      "integrity": "sha512-g20oSZNWg8Hbu41Kinjd55e235qVWPLfg4NvsLW6d+DhgBTFbEuMpcWlUdrD6qT3+Noim6DRu18VLM9lVShXOQ==",
+      "requires": {
+        "object-assign": "^4.1.1",
+        "quill": "^1.3.4"
+      },
+      "dependencies": {
+        "object-assign": {
+          "version": "4.1.1",
+          "resolved": "https://registry.npmmirror.com/object-assign/-/object-assign-4.1.1.tgz",
+          "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg=="
+        }
+      }
+    },
     "vue-router": {
       "version": "3.6.5",
       "resolved": "https://registry.npmmirror.com/vue-router/-/vue-router-3.6.5.tgz",

+ 3 - 1
package.json

@@ -24,8 +24,9 @@
     "gulp-load-plugins": "^2.0.0",
     "gulp-rename": "^1.4.0",
     "gulp-sass": "^4.0.2",
-    "js-cookie": "^2.2.0",
+    "js-cookie": "^2.2.1",
     "lodash": "^4.17.15",
+    "moment": "^2.30.1",
     "node-sass": "^4.12.0",
     "qs": "^6.7.0",
     "quill": "^1.3.6",
@@ -36,6 +37,7 @@
     "vue": "^2.6.10",
     "vue-cron": "^1.0.9",
     "vue-i18n": "^8.12.0",
+    "vue-quill-editor": "^3.0.6",
     "vue-router": "^3.0.7",
     "vuex": "^3.1.1"
   },

TEMPAT SAMPAH
src/assets/img/back.png


+ 139 - 0
src/components/editor/index.vue

@@ -0,0 +1,139 @@
+<template>
+<div class="quill-editor">
+    <el-upload class="avatar-uploaderEdi" :action="url" :show-file-list="false" :on-success="uploadSuccess" :before-upload="beforeUpload">
+    </el-upload>
+    <quill-editor v-model="editorContent" class="ql-container sicepot" @change="onEditorChange($event)" :content="editorContent" :options="editorOption" ref="QuillEditor">
+    </quill-editor>
+</div>
+</template>
+
+<script>
+import Cookies from "js-cookie";
+import 'quill/dist/quill.core.css'
+import 'quill/dist/quill.snow.css'
+import 'quill/dist/quill.bubble.css'
+import {
+    quillEditor
+} from 'vue-quill-editor'
+const toolbarOptions = [
+    ['bold', 'italic', 'underline', 'strike'], // 加粗,斜体,下划线,删除线
+    ['blockquote', 'code-block'], //引用,代码块
+    [{
+        'header': 1
+    }, {
+        'header': 2
+    }], // 几级标题
+    [{
+        'list': 'ordered'
+    }, {
+        'list': 'bullet'
+    }], // 有序列表,无序列表
+    [{
+        'script': 'sub'
+    }, {
+        'script': 'super'
+    }], // 下角标,上角标
+    [{
+        'indent': '-1'
+    }, {
+        'indent': '+1'
+    }], // 缩进
+    [{
+        'direction': 'rtl'
+    }], // 文字输入方向
+    [{
+        'size': ['small', false, 'large', 'huge']
+    }], // 字体大小
+    [{
+        'header': [1, 2, 3, 4, 5, 6, false]
+    }], // 标题
+    [{
+        'color': []
+    }, {
+        'background': []
+    }], // 颜色选择
+    [{
+        'font': ['SimSun', 'SimHei', 'Microsoft-YaHei', 'KaiTi', 'FangSong', 'Arial']
+    }], // 字体
+    [{
+        'align': []
+    }], // 居中
+    ['clean'], // 清除样式,
+    ['link', 'image'], // 上传图片、上传视频
+]
+export default {
+    data() {
+        return {
+            editorContent: '',
+            editorOption: {
+                placeholder: '请在这里输入',
+                theme: 'snow', //主题 snow/bubble
+                modules: {
+                    history: {
+                        delay: 1000,
+                        maxStack: 50,
+                        userOnly: false
+                    },
+                    toolbar: {
+                        container: toolbarOptions,
+                        handlers: {
+                            image: function (value) {
+                                if (value) {
+                                    // 调用element的图片上传组件
+                                    document.querySelector('.avatar-uploaderEdi input').click()
+                                } else {
+                                    this.quill.format('image', false)
+                                }
+                            }
+                        }
+                    }
+                }
+            },
+            url: `${
+        window.SITE_CONFIG["apiURL"]
+      }/oss/file/aliyunUpload?access_token=${Cookies.get("access_token")}`,
+        }
+    },
+    props: ['content'],
+    components: {
+        quillEditor
+    },
+    methods: {
+        init() {
+            this.editorContent = this.content || '';
+        },
+        beforeUpload(file) {},
+        // 值发生变化
+        onEditorChange(editor) {
+            this.$emit('EditorChange', this.editorContent);
+        },
+        uploadSuccess(res) {
+            // 获取富文本组件实例
+            let quill = this.$refs.QuillEditor.quill
+            // 如果上传成功
+            if (res) {
+                // 获取光标所在位置
+                let length = quill.getSelection().index;
+                // 插入图片,res为服务器返回的图片链接地址
+                quill.insertEmbed(length, 'image', res.data.url)
+                // 调整光标到最后
+                quill.setSelection(length + 1)
+            } else {
+                // 提示信息,需引入Message
+                this.$message.error('图片插入失败!')
+            }
+        },
+
+    }
+}
+</script>
+
+<style>
+.sicepot {
+    height: auto !important;
+}
+
+.sicepot .ql-container.ql-snow {
+    height: 200px !important;
+}
+</style>

+ 44 - 0
src/mixins/region-module.js

@@ -0,0 +1,44 @@
+export default {
+    data() {
+        return {
+            provinceOptions: [],
+            cityOptions: [],
+            areaOptions: [],
+            provinceValue: []
+        }
+    },
+    methods: {
+        provincAreaDetailInfoList(val) {
+            this.$http.get('/sys/region/list', { params: { pid: val } }).then((res) => {
+                if (res.msg = 'success') {
+                    this.provinceOptions = res.data.data || []
+                }
+            })
+        },
+        cityAreaDetailInfoList(val) {
+            this.$http.get('/sys/region/list', { params: { pid: val } }).then((res) => {
+                if (res.msg = 'success') {
+                    this.cityOptions = res.data.data || []
+                }
+            })
+
+        },
+        countyAreaDetailInfoList(val) {
+            this.$http.get('/sys/region/list', { params: { pid: val } }).then((res) => {
+                if (res.msg = 'success') {
+                    this.areaOptions = res.data.data || []
+                }
+            })
+
+        },
+        regionChange(val, type) {
+            if (type == 'province') {
+                console.log(type, val);
+                this.cityAreaDetailInfoList(val)
+            } else if (type == 'city') {
+                this.countyAreaDetailInfoList(val)
+            } else if (type == 'area') {
+            }
+        },
+    }
+}

+ 3 - 1
src/router/index.js

@@ -32,7 +32,9 @@ export const moduleRoutes = {
   redirect: { name: 'home' },
   meta: { title: '主入口布局' },
   children: [
-    { path: '/home', component: () => import('@/views/modules/home'), name: 'home', meta: { title: '首页', isTab: true } }
+    { path: '/home', component: () => import('@/views/modules/home'), name: 'home', meta: { title: '首页', isTab: true } },
+    { path: '/activityAdd', component: () => import('@/views/modules/activity/add'), name: 'activityAdd' },
+    { path: '/activityApplyInfo', component: () => import('@/views/modules/activity/info'), name: 'activityApplyInfo' }
   ]
 }
 

+ 685 - 0
src/views/modules/activity/add.vue

@@ -0,0 +1,685 @@
+<template>
+    <el-card shadow="never" class="aui-card--fill">
+        <div class="mod-home">
+            <div class="top adfac">
+                <div class="back adfac" @click="handleBack">
+                    <img src="@/assets/img/back.png">
+                    <span>返回</span>
+                </div>
+                <div class="line"></div>
+                <div class="text">{{ basicForm.id?'编辑':'新增' }}活动</div>
+            </div>
+            <div class="tab adfac">
+                <div class="tab-pre" :class="{'active':tidx==1}" @click="changeTab(1)">基础资料</div>
+                <div class="tab-pre" :class="{'active':tidx==2}" @click="changeTab(2)">活动参与</div>
+            </div>
+            <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-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-option v-for="item in categoryOptions" :key="item.id" :label="item.categoryName" :value="item.id"></el-option>
+                        </el-select>
+                    </el-form-item>
+                    <el-form-item label="活动名称" prop="activityName">
+                        <el-input v-model="basicForm.activityName" placeholder="请输入活动名称"></el-input>
+                    </el-form-item>
+                    <el-form-item label="报名时间" prop="signupStartEnd">
+                        <el-date-picker v-model="basicForm.signupStartEnd" @change="handleSignupDateChange" type="datetimerange" format="yyyy-MM-dd HH:mm" range-separator="至" start-placeholder="年/月/日 - -:- -" end-placeholder="年/月/日 - -:- -" style="width: 390px;"></el-date-picker>
+                    </el-form-item>
+                    <el-form-item label="活动时间" prop="activityStartEnd">
+                        <el-date-picker v-model="basicForm.activityStartEnd" @change="handleActivityDateChange" type="datetimerange" format="yyyy-MM-dd HH:mm" range-separator="至" start-placeholder="年/月/日 - -:- -" end-placeholder="年/月/日 - -:- -" style="width: 390px;"></el-date-picker>
+                    </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-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-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-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-form-item>
+                    <el-form-item label="渠道方" prop="channelId">
+                        <el-select v-model="basicForm.channelId" placeholder="请选择渠道方" class="select-box" style="width: 390px;">
+                            <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-option v-for="item in organizerOptions" :key="item.id" :label="item.organizerName" :value="item.id"></el-option>
+                        </el-select>
+                    </el-form-item>
+                    <el-form-item label="活动列表图片" prop="coverFile" class="redLabel">
+                        <el-upload
+                            :action="url"
+                            :file-list="fileListCover"
+                            :limit="1"
+                            :before-upload="file => beforeUploadHandle(file, 1, [158, 214])"
+                            list-type="picture-card"
+                            :on-success="successHandleCover"
+                            :on-remove="handleRemoveCover"
+                            class="upload-demo"
+                            >
+                            <i class="el-icon-plus"></i>
+                        </el-upload>
+                        <div class="upload_tip">尺寸:158*214px,上传1张,支持图片格式:jpg、png、jpeg</div>
+                    </el-form-item>
+                    <el-form-item label="活动详情banner" prop="imageFiles" class="redLabel">
+                        <el-upload
+                            :action="url"
+                            :file-list="fileListBanner"
+                            :limit="6"
+                            :before-upload="file => beforeUploadHandle(file, 2, [702, 440])"
+                            list-type="picture-card"
+                            :on-success="successHandleBanner"
+                            :on-remove="handleRemoveBanner"
+                            class="upload-demo"
+                            >
+                            <i class="el-icon-plus"></i>
+                        </el-upload>
+                        <div class="upload_tip">尺寸:702*440px,最多上传6张,图片格式:jpg、png、jpeg</div>
+                    </el-form-item>
+                    <el-form-item label="活动详情" prop="activityDetails" class="redLabel">
+                        <editor-vue style="margin-top: -30px;" :content="basicForm.activityDetails"  @EditorChange="getEditor" ref="infoIntroduceRef"></editor-vue>
+                    </el-form-item>
+                </el-form>
+                <div class="btns adfac">
+                    <el-button type="primary" @click="handleNext">下一步</el-button>
+                    <el-button type="default" @click="handleBack" style="margin-left: 16px;">返回</el-button>
+                </div>
+            </div>
+            <div class="form" v-else-if="tidx===2">
+                <el-form ref="moreRef" :model="moreForm" :rules="moreRules" label-width="125px">
+                  <el-form-item label="参与方式" prop="joinMode">
+                    <ren-select
+                      v-model="moreForm.joinMode"
+                      dict-type="join_mode"
+                      placeholder="请选择参与方式"
+                      style="width: 820px"
+                    ></ren-select>
+                  </el-form-item>
+                  <el-form-item label="报名人数" class="redLabel">
+                    <div class="adfac">
+                      <el-radio-group v-model="moreForm.recruitmentFlag">
+                        <el-radio :label="1" :value="1">限制</el-radio>
+                        <el-radio :label="2" :value="2">不限</el-radio>
+                      </el-radio-group>
+                      <div class="f-text">最多报名人数</div>
+                      <el-input type="number" v-model="moreForm.recruitmentMax" style="width: 157px;" :disabled="moreForm.recruitmentFlag==2" placeholder="请输入"></el-input>
+                      <div class="f-text">最少报名人数</div>
+                      <el-input type="number" v-model="moreForm.recruitmentMin" style="width: 157px;" :disabled="moreForm.recruitmentFlag==2" placeholder="请输入"></el-input>
+                      <div class="f-tip">活动报名人数超出报名人数后,将不能继续报名。活动报名人数低于最少报名人数时,将会取消活动</div>
+                    </div>
+                  </el-form-item>
+                  <el-form-item label="会员等级" class="redLabel">
+                    <div class="adfac">
+                      <el-radio-group v-model="moreForm.userLevelFlag">
+                        <el-radio :label="1" :value="1">限制</el-radio>
+                        <el-radio :label="0" :value="0">不限</el-radio>
+                      </el-radio-group>
+                      <el-input type="number" v-model="moreForm.userLevel" style="width: 157px;margin-left: 30px;" :disabled="moreForm.userLevelFlag==0"></el-input>
+                      <div class="f-text2">及以上等级</div>
+                    </div>
+                  </el-form-item>
+                  <el-form-item label="会员年龄" class="redLabel">
+                    <div class="adfac">
+                      <el-radio-group v-model="moreForm.userAgeFlag">
+                        <el-radio :label="1" :value="1">限制</el-radio>
+                        <el-radio :label="2" :value="2">不限</el-radio>
+                      </el-radio-group>
+                      <div class="f-text">最小参加年龄</div>
+                      <el-input type="number" v-model="moreForm.userAgeMin" style="width: 157px;" :disabled="moreForm.userAgeFlag==2" placeholder="请输入"></el-input>
+                      <div class="f-text">最大参加年龄</div>
+                      <el-input type="number" v-model="moreForm.userAgeMax" style="width: 157px;" :disabled="moreForm.userAgeFlag==2" placeholder="请输入"></el-input>
+                    </div>
+                  </el-form-item>
+                  <el-form-item label="公益支持" class="redLabel">
+                    <div class="adfac">
+                      <el-select v-model="moreForm.activityLimit" placeholder="请选择" style="width: 123px;" class="select-box">
+                        <el-option label="需要爱心值" :value="1"></el-option>
+                        <el-option label="专享券" :value="2"></el-option>
+                        <el-option label="免费" :value="3"></el-option>
+                      </el-select>
+                      <div v-if="moreForm.activityLimit==1" class="adfac">
+                        <el-input type="number" v-model="moreForm.valueLimit" style="width: 252px;margin-left: 17px;" placeholder="请输入"></el-input>
+                        <div class="f-text2">爱心值</div>
+                      </div>
+                      <div v-if="moreForm.activityLimit==2" class="adfac">
+                        <el-input type="number" v-model="moreForm.valueLimit" style="width: 252px;margin-left: 17px;" placeholder="请输入"></el-input>
+                        <div class="f-text2">专享券</div>
+                      </div>
+                    </div>
+                  </el-form-item>
+                  <el-form-item label="爱心值对应内容" v-if="moreForm.activityLimit==1">
+                    <el-input v-model="moreForm.loveValueContent" style="width: 820px;" placeholder="请输入"></el-input>
+                  </el-form-item>
+                  <el-form-item label="报名次数限制">
+                    <div class="adfac">
+                      <el-input type="number" v-model="moreForm.timesLimit" style="width: 391px;" placeholder="请输入"></el-input>
+                      <div class="f-tip">不填默认不限制</div>
+                    </div>
+                  </el-form-item>
+                  <el-form-item label="负责人" prop="contact">
+                    <el-input v-model="moreForm.contact" style="width: 820px;" placeholder="请输入"></el-input>
+                  </el-form-item>
+                  <el-form-item label="负责人电话" prop="contactPhone">
+                    <el-input v-model="moreForm.contactPhone" style="width: 820px;" placeholder="请输入"></el-input>
+                  </el-form-item>
+                  <el-form-item label="上架活动" prop="state">
+                    <el-switch v-model="moreForm.state" active-color="#13ce66" inactive-color="#a4a4a4"></el-switch>
+                  </el-form-item>
+                </el-form>
+                <div class="btns adfac">
+                    <el-button type="default" @click="handlePrevious">上一步</el-button>
+                    <el-button type="primary" @click="handleSave" style="margin-left: 16px;">保存</el-button>
+                </div>
+            </div>
+        </div>
+    </el-card>
+</template>
+
+<script>
+import moment from 'moment'
+import Cookies from 'js-cookie'
+import editorVue from '@/components/editor'
+import mixinRegionModule from '@/mixins/region-module.js'
+export default {
+  components: { editorVue },
+  mixins: [mixinRegionModule],
+  data () {
+    return {
+      typeOptions: [],
+      categoryOptions: [],
+      channelOptions: [
+        { id: 1, channelName: '渠道方1' }
+      ],
+      organizerOptions: [
+        { id: 1, organizerName: '举办方1' }
+      ],
+      tidx: 1,
+      basicForm: {
+        id: '',
+        typeId: '',
+        categoryId: '',
+        activityName: '',
+        signupStartEnd: [],
+        signupStartTime: '',
+        signupEndTime: '',
+        activityStartEnd: [],
+        activityStartTime: '',
+        activityEndTime: '',
+        provinceId: '',
+        cityId: '',
+        districtId: '',
+        address: '',
+        channelId: '',
+        organizerId: '',
+        coverFile: '',
+        imageFiles: '',
+        activityDetails: ''
+      },
+      activityDetailsTemp: '',
+      basicRules: {
+        typeId: [
+          { required: true, message: '请选择活动类型', trigger: 'change' }
+        ],
+        categoryId: [
+          { required: true, message: '请选择活动分类', trigger: 'change' }
+        ],
+        activityName: [
+          { required: true, message: '请输入活动名称', trigger: 'blur' }
+        ],
+        signupStartEnd: [
+          { required: true, message: '请选择报名时间', trigger: 'change' }
+        ],
+        activityStartEnd: [
+          { required: true, message: '请选择活动时间', trigger: 'change' }
+        ],
+        provinceId: [
+          { required: true, message: '请选择省市区', trigger: 'change' }
+        ],
+        cityId: [
+          { required: true, message: '请选择省市区', trigger: 'change' }
+        ],
+        districtId: [
+          { required: true, message: '请选择省市区', trigger: 'change' }
+        ],
+        channelId: [
+          { required: true, message: '请选择渠道方', trigger: 'change' }
+        ],
+        organizerId: [
+          { required: true, message: '请选择举办方', trigger: 'change' }
+        ]
+      },
+      url: `${window.SITE_CONFIG['apiURL']}/sys/oss/uploadFile?token=${Cookies.get('token')}`,
+      fileListCover: [],
+      fileListBanner: [],
+      moreForm: {
+        joinMode: '',
+        recruitmentFlag: 1,
+        recruitmentMax: '',
+        recruitmentMin: '',
+        userLevelFlag: 1,
+        userLevel: '',
+        userAgeFlag: 1,
+        userAgeMin: '',
+        userAgeMax: '',
+        activityLimit: 1,
+        valueLimit: '',
+        loveValueContent: '',
+        timesLimit: '',
+        contact: '',
+        contactPhone: '',
+        state: false
+      },
+      moreForm2: {
+        joinMode: ''
+      },
+      moreRules: {
+        joinMode: [
+          { required: true, message: '请选择参与方式', trigger: 'change' }
+        ],
+        contact: [
+          { required: true, message: '请输入负责人', trigger: 'blur' }
+        ],
+        contactPhone: [
+          { required: true, message: '请输入负责人电话', trigger: 'blur' },
+          { pattern: /^1[3456789]\d{9}$/, message: '请输入正确的电话号码', trigger: 'blur' }
+        ],
+        state: [
+          { required: true, message: '请选择上架活动', trigger: 'change' }
+        ]
+      }
+    }
+  },
+  created () {
+    this.getTypeOptions()
+    this.getCategoryOptions()
+  },
+  mounted () {
+    this.provincAreaDetailInfoList()
+
+    this.$nextTick(() => {
+      setTimeout(() => {
+        this.$refs.infoIntroduceRef.init()
+      }, 500)
+      if (this.$route.query.id) {
+        this.getDetail(this.$route.query.id)
+      }
+    })
+  },
+  methods: {
+    regionChange (val, type) {
+      if (type === 'province') {
+        this.basicForm.cityId = ''
+        this.basicForm.districtId = ''
+        this.cityAreaDetailInfoList(val)
+      } else if (type === 'city') {
+        this.basicForm.districtId = ''
+        this.countyAreaDetailInfoList(val)
+      }
+    },
+    getDetail (id) {
+      this.$http.get('/core/activity/' + id).then(({ data: res }) => {
+        if (res.code !== 0) return this.$message.error(res.msg)
+        // this.basicForm = { ...this.basicForm, ...res.data }
+        this.updateObjectFromSource(this.basicForm, res.data)
+        this.activityDetailsTemp = res.data.activityDetails
+        this.basicForm.signupStartEnd = [this.basicForm.signupStartTime, this.basicForm.signupEndTime]
+        this.basicForm.activityStartEnd = [this.basicForm.activityStartTime, this.basicForm.activityEndTime]
+        this.basicForm.channelId = +this.basicForm.channelId
+        this.basicForm.organizerId = +this.basicForm.organizerId
+        this.fileListCover = [{ name: '', url: res.data.coverFile }]
+        this.fileListBanner = res.data.imageFiles.split(',').map(item => ({ name: '', url: item }))
+        if (this.basicForm.cityId) {
+          this.cityAreaDetailInfoList(this.basicForm.provinceId)
+        }
+        if (this.basicForm.districtId) {
+          this.countyAreaDetailInfoList(this.basicForm.cityId)
+        }
+        this.updateObjectFromSource(this.moreForm, res.data)
+        this.moreForm.recruitmentFlag = +this.moreForm.recruitmentMax === 0 ? 2 : 1
+        this.moreForm.userLevelFlag = +this.moreForm.userLevel === 0 ? 0 : 1
+        this.moreForm.userAgeFlag = +this.moreForm.userAgeMax === 0 ? 2 : 1
+      })
+    },
+    updateObjectFromSource (target, source) {
+      for (const key of Object.keys(target)) {
+        if (Object.prototype.hasOwnProperty.call(source, key)) {
+          target[key] = source[key]
+        }
+      }
+    },
+    getEditor (val) {
+      this.basicForm.activityDetails = val
+    },
+    getTypeOptions () {
+      this.$http.get('/core/activity/type/page', { params: { page: 1, limit: -1 } }).then(res => {
+        this.typeOptions = res.data.data.list || []
+      })
+    },
+    getCategoryOptions () {
+      this.$http.get('/core/activity/category/page', { params: { page: 1, limit: -1 } }).then(res => {
+        this.categoryOptions = res.data.data.list || []
+      })
+    },
+    handleSignupDateChange (val) {
+      this.basicForm.signupStartTime = moment(val[0]).format('YYYY-MM-DD HH:mm')
+      this.basicForm.signupEndTime = moment(val[1]).format('YYYY-MM-DD HH:mm')
+    },
+    handleActivityDateChange (val) {
+      this.basicForm.activityStartTime = moment(val[0]).format('YYYY-MM-DD HH:mm')
+      this.basicForm.activityEndTime = moment(val[1]).format('YYYY-MM-DD HH:mm')
+    },
+    beforeUploadHandle (file, index, fixedNumber) {
+      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
+      }
+    },
+    handleRemoveCover (file, fileList) {
+      this.fileListCover = fileList.map((item) => item) || []
+      this.basicForm.coverFile = ''
+    },
+    successHandleCover (res, file, fileList) {
+      if (res.code !== 0) {
+        return this.$message.error(res.msg)
+      }
+      this.fileListCover.unshift({
+        name: '',
+        url: res.data
+      })
+      this.basicForm.coverFile = this.fileListCover[0].url
+    },
+    handleRemoveBanner (file, fileList) {
+      this.fileListBanner = fileList.map((item) => item)
+      this.basicForm.imageFiles = this.fileListBanner.map(item => item.url).join(',')
+    },
+    successHandleBanner (res, file, fileList) {
+      if (res.code !== 0) {
+        return this.$message.error(res.msg)
+      }
+      this.fileListBanner.unshift({
+        name: '',
+        url: res.data
+      })
+      this.basicForm.imageFiles = this.fileListBanner.map(item => item.url).join(',')
+    },
+    handleBack () {
+      this.basicForm = {
+        id: '',
+        typeId: '',
+        categoryId: '',
+        activityName: '',
+        signupStartEnd: [],
+        signupStartTime: '',
+        signupEndTime: '',
+        activityStartEnd: [],
+        activityStartTime: '',
+        activityEndTime: '',
+        provinceId: '',
+        cityId: '',
+        districtId: '',
+        address: '',
+        channelId: '',
+        organizerId: '',
+        coverFile: '',
+        imageFiles: '',
+        activityDetails: ''
+      }
+      if (this.$refs.basicRef) this.$refs.basicRef.resetFields()
+      this.moreForm = {
+        joinMode: '',
+        recruitmentFlag: 1,
+        recruitmentMax: '',
+        recruitmentMin: '',
+        userLevelFlag: 1,
+        userLevel: '',
+        userAgeFlag: 1,
+        userAgeMin: '',
+        userAgeMax: '',
+        activityLimit: 1,
+        valueLimit: '',
+        loveValueContent: '',
+        timesLimit: '',
+        contact: '',
+        contactPhone: '',
+        state: false
+      }
+      if (this.$refs.moreRef) this.$refs.moreRef.resetFields()
+      this.tidx = 1
+      this.$router.push('/activity-list')
+    },
+    changeTab (idx) {
+      // this.tidx = idx
+    },
+    handleNext () {
+      this.$refs.basicRef.validate(valid => {
+        if (valid) {
+          if (!this.basicForm.coverFile) return this.$message.error('请上传活动列表图片')
+          if (!this.basicForm.imageFiles) return this.$message.error('请上传活动详情Banner')
+          if (!this.basicForm.activityDetails) return this.$message.error('请输入活动详情')
+          this.tidx = 2
+        } else {
+          return false
+        }
+      })
+    },
+    handlePrevious () {
+      this.tidx = 1
+      this.$nextTick(() => {
+        setTimeout(() => {
+          this.$refs.infoIntroduceRef.init()
+          this.basicForm.activityDetails = this.activityDetails
+        }, 500)
+      })
+    },
+    handleSave () {
+      this.$refs.moreRef.validate(valid => {
+        if (valid) {
+          if (this.moreForm.recruitmentFlag === 1) {
+            if (!this.moreForm.recruitmentMax) return this.$message.error('请输入最多报名人数')
+            if (!this.moreForm.recruitmentMin) return this.$message.error('请输入最少报名人数')
+            if (+this.moreForm.recruitmentMin > +this.moreForm.recruitmentMax) return this.$message.error('最少报名人数不能大于最多报名人数')
+          } else {
+            this.moreForm.recruitmentMax = 0
+            this.moreForm.recruitmentMin = 0
+          }
+          if (this.moreForm.userLevelFlag === 1) {
+            if (!this.moreForm.userLevel) return this.$message.error('请输入会员最小限制等级')
+          } else {
+            this.moreForm.userLevel = 0
+          }
+          if (this.moreForm.userAgeFlag === 1) {
+            if (!this.moreForm.userAgeMin) return this.$message.error('请输入最小参加年龄')
+            if (!this.moreForm.userAgeMax) return this.$message.error('请输入最大参加年龄')
+            if (+this.moreForm.userAgeMin > +this.moreForm.userAgeMax) return this.$message.error('最小参加年龄不能大于最大参加年龄')
+          } else {
+            this.moreForm.userAgeMin = 0
+            this.moreForm.userAgeMax = 0
+          }
+          if (this.moreForm.activityLimit === 1) {
+            if (!this.moreForm.valueLimit) return this.$message.error('请输入爱心值数量')
+          } else if (this.moreForm.activityLimit === 2) {
+            if (!this.moreForm.valueLimit) return this.$message.error('请输入专享券数量')
+          }
+
+          let { signupStartEnd, activityStartEnd, ...newBasic } = JSON.parse(JSON.stringify(this.basicForm))
+          let { recruitmentFlag, userAgeFlag, userLevelFlag, ...newMore } = JSON.parse(JSON.stringify(this.moreForm))
+          let dto = { ...newBasic, ...newMore }
+          dto.state = dto.state ? 1 : 0
+
+          this.$http[dto.id ? 'put' : 'post']('/core/activity', dto).then(res => {
+            if (res.data.code !== 0) return this.$message.error(res.data.msg)
+            this.$message.success(res.data.msg)
+            this.$router.push('/activity-list')
+          })
+        } else {
+          return false
+        }
+      })
+    }
+  }
+}
+</script>
+
+<style scoped lang="scss">
+  .top {
+    padding-bottom: 13px;
+    box-shadow: inset 0px -1px 0px 0px #F0F1F7;
+    .back {
+        cursor: pointer;
+        img {
+          width: 22px;
+          height: 22px;
+        }
+        span {
+            font-family: PingFang-SC, PingFang-SC;
+            font-weight: bold;
+            font-size: 14px;
+            color: #00AE57;
+            line-height: 20px;
+            margin-left: 6px;
+        }
+    }
+    .line {
+        width: 1px;
+        height: 16px;
+        background: #F0F1F7;
+        margin-left: 14px;
+    }
+    .text {
+        font-family: PingFangSC, PingFang SC;
+        font-weight: 400;
+        font-size: 14px;
+        color: #657588;
+        line-height: 20px;
+        margin-left: 10px;
+    }
+  }
+
+  .tab{
+    height: 48px;
+    box-shadow: inset 0px -1px 0px 0px #F0F1F7;
+    &-pre{
+        width: 120px;
+        height: 48px;
+        font-family: PingFangSC, PingFang SC;
+        font-weight: 400;
+        font-size: 14px;
+        color: #393939;
+        line-height: 20px;
+        // cursor: pointer;
+        position: relative;
+        padding-left: 7px;
+        box-sizing: border-box;
+        display: flex;
+        flex-direction: column;
+        justify-content: center;
+        &.active{
+            font-weight: bold;
+            &::after{
+                content: '';
+                position: absolute;
+                left: 7px;
+                bottom: 2px;
+                width: 55px;
+                height: 2px;
+                background: #00AE57;
+            }
+        }
+    }
+  }
+
+  .form{
+    padding: 20px 0 1px;
+  }
+
+  .btns{
+    border-top: 1px solid #F0F1F7;
+    padding: 24px 0 0 126px;
+  }
+
+  .f-text{
+    font-family: PingFangSC, PingFang SC;
+    font-weight: 400;
+    font-size: 14px;
+    color: #393939;
+    line-height: 20px;
+    margin: 0 10px 0 56px;
+  }
+  .f-text2{
+    font-family: PingFangSC, PingFang SC;
+    font-weight: 400;
+    font-size: 14px;
+    color: #393939;
+    line-height: 20px;
+    margin-left: 6px;
+  }
+  .f-tip{
+    font-family: PingFangSC, PingFang SC;
+    font-weight: 400;
+    font-size: 12px;
+    color: #A4A4A4;
+    line-height: 17px;
+    margin-left: 20px;
+  }
+
+  ::v-deep .el-radio__label{
+    line-height: 20px;
+  }
+
+  .avatar-uploader-icon {
+    font-size: 28px;
+    color: #8c939d;
+    width: 84px;
+    height: 84px;
+    line-height: 84px;
+    text-align: center;
+  }
+  ::v-deep .el-upload--picture-card{
+    width: 84px !important;
+    height: 84px !important;
+    display: flex;
+    align-items: center;
+    justify-content: center;
+  }
+  .avatar {
+    width: 84px;
+    height: 84px;
+    display: block;
+  }
+  .upload-demo{
+    display: flex !important;
+    flex-wrap: wrap;
+  }
+  ::v-deep .el-upload-list--picture-card .el-upload-list__item{
+    width: 84px !important;
+    height: 84px !important;
+  }
+  .upload_tip{
+    font-family: PingFangSC, PingFang SC;
+    font-weight: 400;
+    font-size: 12px;
+    color: #A4A4A4;
+    line-height: 17px;
+    margin-top: 2px;
+  }
+
+  ::v-deep .redLabel>.el-form-item__label{
+    &::before{
+        content: "*";
+        color: #F56C6C;
+        margin-right: 4px;
+    }
+  }
+</style>

+ 5 - 5
src/views/modules/activity/classify.vue

@@ -105,7 +105,7 @@ export default {
     },
     handleEdit (row) {
       this.$http.get('/core/activity/category/' + row.id).then(res => {
-        if (res.data.code !== 0) return this.$message.error(res.msg)
+        if (res.data.code !== 0) return this.$message.error(res.data.msg)
         this.form = { ...this.form, ...res.data.data }
         this.$nextTick(() => {
           this.title = '编辑活动分类'
@@ -127,7 +127,7 @@ export default {
     getList () {
       this.loading = true
       this.$http.get('/core/activity/category/page', { params: this.queryParams }).then(res => {
-        if (res.data.code !== 0) return this.$message.error(res.msg)
+        if (res.data.code !== 0) return this.$message.error(res.data.msg)
         this.dataList = res.data.data.list
         this.loading = false
       })
@@ -137,7 +137,7 @@ export default {
         if (valid) {
           this.$http[this.form.id ? 'put' : 'post']('/core/activity/category', this.form).then(res => {
             if (res.data.code !== 0) {
-              return this.$message.error(res.msg)
+              return this.$message.error(res.data.msg)
             }
             this.$message.success('保存成功')
             this.cancel()
@@ -152,7 +152,7 @@ export default {
       let dto = JSON.parse(JSON.stringify(row))
       dto.enable = enable
       this.$http.put('/core/activity/category', dto).then(res => {
-        if (res.data.code !== 0) return this.$message.error(res.msg)
+        if (res.data.code !== 0) return this.$message.error(res.data.msg)
         this.$message.success('操作成功')
         this.getList()
       })
@@ -164,7 +164,7 @@ export default {
         type: 'warning'
       }).then(() => {
         this.$http.delete('/core/activity/category', { 'data': [row.id] }).then(res => {
-          if (res.data.code !== 0) return this.$message.error(res.msg)
+          if (res.data.code !== 0) return this.$message.error(res.data.msg)
           this.$message.success('删除成功')
           this.getList()
         })

+ 252 - 0
src/views/modules/activity/info.vue

@@ -0,0 +1,252 @@
+<template>
+    <el-card shadow="never" class="aui-card--fill">
+        <div class="mod-home">
+            <div class="top adfac">
+                <div class="back adfac" @click="handleBack">
+                    <img src="@/assets/img/back.png">
+                    <span>返回</span>
+                </div>
+                <div class="line"></div>
+                <div class="text">报名信息</div>
+            </div>
+            <div class="title">活动信息</div>
+            <div class="info">
+                <div class="info-pre adf">
+                    <div class="info-pre-title adf"><span>*</span>活动名称:</div>
+                    <div class="info-pre-content">{{ activityInfo.activityName || '--' }}</div>
+                </div>
+                <div class="info-pre adf">
+                    <div class="info-pre-title adf"><span>*</span>活动时间:</div>
+                    <div class="info-pre-content">{{ activityInfo.activityStartTime || '--' }} - {{ activityInfo.activityEndTime || '--' }}</div>
+                </div>
+                <div class="info-pre adf">
+                    <div class="info-pre-title adf"><span>*</span>渠道方:</div>
+                    <div class="info-pre-content">{{ activityInfo.channelName || '--' }}</div>
+                </div>
+                <div class="info-pre adf">
+                    <div class="info-pre-title adf"><span>*</span>活动地址:</div>
+                    <div class="info-pre-content">{{ provinceName || '' }}{{ cityName || '' }}{{ districtName || '' }}{{ activityInfo.address || '--' }}</div>
+                </div>
+                <div class="info-pre adf">
+                    <div class="info-pre-title adf"><span>*</span>会员等级:</div>
+                    <div class="info-pre-content">{{ activityInfo.userLevel?`Lv.${activityInfo.userLevel} 级以上`:'无限制' }}</div>
+                </div>
+                <div class="info-pre adf">
+                    <div class="info-pre-title adf"><span>*</span>举办方:</div>
+                    <div class="info-pre-content">{{ activityInfo.organizerName || '--' }}</div>
+                </div>
+                <div class="info-pre adf">
+                    <div class="info-pre-title adf"><span>*</span>报名人数:</div>
+                    <div class="info-pre-content">{{ activityInfo.signedNumber || 0 }}/{{ activityInfo.recruitmentMax || '无限制' }}</div>
+                </div>
+                <div class="info-pre adf">
+                    <div class="info-pre-title adf"><span>*</span>公益支持:</div>
+                    <div class="info-pre-content" v-if="activityInfo.activityLimit!=3">{{ (activityInfo.valueLimit||'-') }} {{ activityLimitCfg[activityInfo.activityLimit]||'-' }}</div>
+                    <div class="info-pre-content" v-else>免费</div>
+                </div>
+                <div class="info-pre adf">
+                    <div class="info-pre-title adf"><span>*</span>公益支持内容:</div>
+                    <div class="info-pre-content">{{ activityInfo.loveValueContent || '--' }}</div>
+                </div>
+            </div>
+            <div class="title adfacjb">
+                活动报名信息
+                <el-button type="primary" @click="handleExcel">导出Excel</el-button>
+            </div>
+            <el-table :data="dataList" border cell-class-name="vertical-top-cell" v-loading="loading" empty-text="暂无活动报名信息" style="margin-top: 16px;">
+                <el-table-column prop="id" label="善行少年编号" width="200"></el-table-column>
+                <el-table-column prop="welfareName" label="家庭名称" width="150"></el-table-column>
+                <el-table-column prop="contactPhone" label="手机号码" width="150"></el-table-column>
+                <el-table-column prop="xxx" label="渠道方" width="200"></el-table-column>
+                <el-table-column prop="name" label="姓名" width="150"></el-table-column>
+                <el-table-column prop="idCard" label="身份证号" width="300"></el-table-column>
+                <el-table-column prop="volunteerNo" label="义工号" width="100"></el-table-column>
+                <el-table-column prop="gender" label="性别" width="100"></el-table-column>
+                <el-table-column prop="xxx" label="年龄" width="100"></el-table-column>
+                <el-table-column prop="xxx" label="参会情况" width="120"></el-table-column>
+                <el-table-column prop="currentSchool" label="就读学校" width="200"></el-table-column>
+                <el-table-column prop="createDate" label="报名时间" width="240"></el-table-column>
+                <el-table-column prop="signupState" label="状态" width="150" fixed="right">
+                    <template slot-scope="scope">{{ statusCfg[scope.row.signupState] || '--' }}</template>
+                </el-table-column>
+            </el-table>
+            <el-pagination
+              :current-page="queryParams.page"
+              :page-sizes="[10, 20, 50, 100]"
+              :page-size="queryParams.limit"
+              :total="total"
+              layout="total, sizes, prev, pager, next, jumper"
+              @size-change="pageSizeChangeHandle"
+              @current-change="pageCurrentChangeHandle">
+            </el-pagination>
+        </div>
+    </el-card>
+</template>
+
+<script>
+import Cookies from 'js-cookie'
+import qs from 'qs'
+export default {
+  data () {
+    return {
+      provinceName: '',
+      cityName: '',
+      districtName: '',
+      activityInfo: null,
+      activityLimitCfg: {
+        1: '爱心值',
+        2: '专享券',
+        3: '免费'
+      },
+      loading: false,
+      queryParams: {
+        activityId: this.$route.query.id,
+        page: 1,
+        limit: 10
+      },
+      statusCfg: {
+        '-1': '已取消',
+        1: '已报名',
+        2: '已签到',
+        3: '已填档案'
+      }
+    }
+  },
+  mounted () {
+    this.getDetail(this.$route.query.id)
+    this.getList()
+  },
+  methods: {
+    handleBack () {
+      this.$router.push({ name: 'activity-list' })
+    },
+    getSSQ (code, key) {
+      this.$http.get('/sys/region/' + code).then(({ data: res }) => {
+        if (res.code !== 0) return this.$message.error(res.msg)
+        this[key] = res.data.name
+      })
+    },
+    getDetail (id) {
+      this.$http.get('/core/activity/' + id).then(({ data: res }) => {
+        if (res.code !== 0) return this.$message.error(res.msg)
+        this.activityInfo = res.data
+        this.getSSQ(res.data.provinceId, 'provinceName')
+        this.getSSQ(res.data.cityId, 'cityName')
+        this.getSSQ(res.data.districtId, 'districtName')
+      })
+    },
+    getList () {
+      this.loading = true
+      this.$http.get('/core/activity/signup/getSignupList', { params: this.queryParams }).then(({ data: res }) => {
+        if (res.code !== 0) return this.$message.error(res.msg)
+        this.dataList = res.data.list
+        this.total = res.data.total
+        this.loading = false
+      })
+    },
+    pageSizeChangeHandle (val) {
+      this.queryParams.limit = val
+      this.getList()
+    },
+    pageCurrentChangeHandle (val) {
+      this.queryParams.page = val
+      this.getList()
+    },
+    handleExcel () {
+      let newDataForm = Object.assign({}, this.queryParams)
+      var params = qs.stringify({
+        'token': Cookies.get('token'),
+        ...newDataForm
+      })
+      window.location.href = `${window.SITE_CONFIG['apiURL']}/core/activity/signup/export?${params}`
+    }
+  }
+}
+</script>
+
+<style scoped lang="scss">
+.top {
+    padding-bottom: 13px;
+    box-shadow: inset 0px -1px 0px 0px #F0F1F7;
+    .back {
+        cursor: pointer;
+        img {
+          width: 22px;
+          height: 22px;
+        }
+        span {
+            font-family: PingFang-SC, PingFang-SC;
+            font-weight: bold;
+            font-size: 14px;
+            color: #00AE57;
+            line-height: 20px;
+            margin-left: 6px;
+        }
+    }
+    .line {
+        width: 1px;
+        height: 16px;
+        background: #F0F1F7;
+        margin-left: 14px;
+    }
+    .text {
+        font-family: PingFangSC, PingFang SC;
+        font-weight: 400;
+        font-size: 14px;
+        color: #657588;
+        line-height: 20px;
+        margin-left: 10px;
+    }
+}
+
+.title{
+    font-family: PingFang-SC, PingFang-SC;
+    font-weight: bold;
+    font-size: 16px;
+    color: #393939;
+    line-height: 22px;
+    margin-top: 20px;
+}
+
+.info{
+    background: #F5F8FC;
+    border-radius: 8px;
+    margin-top: 10px;
+    padding: 0 16px 20px;
+    display: flex;
+    flex-wrap: wrap;
+    &-pre{
+        width: calc(100% / 3);
+        margin-top: 20px;
+        &-title{
+            width: 130px;
+            font-family: PingFangSC, PingFang SC;
+            font-weight: 400;
+            font-size: 14px;
+            color: #646464;
+            line-height: 20px;
+            text-align: right;
+            letter-spacing: 1px;
+            justify-content: flex-end;
+            padding-right: 4px;
+            box-sizing: border-box;
+            span{
+                font-family: PingFangSC, PingFang SC;
+                font-weight: 400;
+                font-size: 14px;
+                color: #FB5454;
+                line-height: 20px;
+                margin-right: 6px;
+            }
+        }
+        &-content{
+            width: calc(100% - 130px);
+            font-family: PingFang-SC, PingFang-SC;
+            font-weight: bold;
+            font-size: 14px;
+            color: #252525;
+            line-height: 20px;
+        }
+    }
+}
+</style>

+ 291 - 0
src/views/modules/activity/list.vue

@@ -0,0 +1,291 @@
+<template>
+    <el-card shadow="never" class="aui-card--fill">
+        <div class="mod-home">
+          <div class="title">活动列表</div>
+          <el-row :gutter="20" style="margin-top: 20px;">
+            <el-col :span="6" class="adfac">
+              <div class="query_text">活动类型</div>
+              <el-select v-model="queryParams.typeId" placeholder="请选择活动类型" class="select-box" style="width: 100%;">
+                <el-option v-for="item in typeOptions" :key="item.id" :label="item.typeName" :value="item.id"></el-option>
+              </el-select>
+            </el-col>
+            <el-col :span="6" class="adfac">
+              <div class="query_text">活动分类</div>
+              <el-select v-model="queryParams.categoryId" placeholder="请选择活动分类" class="select-box" style="width: 100%;">
+                <el-option v-for="item in categoryOptions" :key="item.id" :label="item.categoryName" :value="item.id"></el-option>
+              </el-select>
+            </el-col>
+          </el-row>
+          <el-row :gutter="20" style="margin-top: 20px;">
+            <el-col :span="6" class="adfac">
+              <div class="query_text">活动名称</div>
+              <el-input v-model="queryParams.activityName" placeholder="请输入活动名称" class="input-box"></el-input>
+            </el-col>
+            <el-col :span="6" class="adfac">
+              <div class="query_text">活动时间</div>
+              <el-date-picker v-model="queryParams.startEndDate" @change="handleDateChange" type="daterange" range-separator="至" start-placeholder="开始日期" end-placeholder="结束日期" style="width: 100%;"></el-date-picker>
+            </el-col>
+            <el-col :span="12" class="adfac">
+                <el-button type="default" @click="handleReset">重置</el-button>
+                <el-button type="primary" @click="getList">查询</el-button>
+                <el-button type="primary" @click="handleAdd" v-if="$hasPermission('core:activity:save')">新增活动</el-button>
+            </el-col>
+          </el-row>
+          <el-table :data="dataList" border cell-class-name="vertical-top-cell" v-loading="loading" empty-text="暂无活动" style="margin-top: 24px;">
+              <el-table-column prop="id" label="活动ID" width="200"></el-table-column>
+              <el-table-column prop="activityName" label="活动名称" width="200"></el-table-column>
+              <el-table-column prop="typeName" label="活动类型" width="100"></el-table-column>
+              <el-table-column prop="categoryName" label="活动分类" width="100"></el-table-column>
+              <el-table-column prop="channelName" label="渠道方" width="100"></el-table-column>
+              <el-table-column prop="organizerName" label="举办方" width="100"></el-table-column>
+              <el-table-column prop="" label="报名时间" width="320">
+                <template #default="scope">{{ scope.row.signupStartTime }} - {{ scope.row.signupEndTime }}</template>
+              </el-table-column>
+              <el-table-column prop="" label="活动时间" width="320">
+                <template #default="scope">{{ scope.row.activityStartTime }} - {{ scope.row.activityEndTime }}</template>
+              </el-table-column>
+              <el-table-column prop="" label="报名人数" width="100">
+                <template #default="scope">
+                  <div class="adfac"><span style="color: #00AE57;">{{ scope.row.signedNumber||0 }}</span>/{{ scope.row.recruitmentMax||'无限制' }}</div>
+                </template>
+              </el-table-column>
+              <el-table-column prop="" label="上下架" width="100">
+                <template #default="scope">
+                  <span v-if="scope.row.state==1" style="color: #00AE57;">已上架</span>
+                  <span v-if="scope.row.state==0">已下架</span>
+                </template>
+              </el-table-column>
+              <el-table-column prop="activeState" label="活动状态" width="150">
+                <template #default="scope">
+                  <div class="as" :class="{'jxz':scope.row.activeState==2}">{{ activeStateCfg[scope.row.activeState] || '未知' }}</div>
+                </template>
+              </el-table-column>
+              <el-table-column label="操作" width="250" 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="handleInfo(scope.row)" v-if="scope.row.activeState!=0&&$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&&$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>
+                      <el-button link type="text" @click="handleUpDown(scope.row,1)" v-if="scope.row.state==0&&scope.row.activeState==0&&$hasPermission('core:activity:updown')">上架</el-button>
+                      <el-button link type="text" @click="handleDelete(scope.row)" v-if="$hasPermission('core:activity:delete')&&scope.row.activeState==0">删除</el-button>
+                  </template>
+              </el-table-column>
+            </el-table>
+            <el-pagination
+              :current-page="queryParams.page"
+              :page-sizes="[10, 20, 50, 100]"
+              :page-size="queryParams.limit"
+              :total="total"
+              layout="total, sizes, prev, pager, next, jumper"
+              @size-change="pageSizeChangeHandle"
+              @current-change="pageCurrentChangeHandle">
+            </el-pagination>
+        </div>
+        <el-dialog width="600px" :visible.sync="show" title="签到码" @close="cancel">
+          <div class="code-img adffcacjc">
+            <img :src="signCodeUrl">
+          </div>
+          <div class="demo-drawer__footer" style="display: flex;justify-content: end;margin-top: 50px;">
+            <el-button type="primary" @click="downloadImg">下 载</el-button>
+            <el-button @click="cancel" style="margin-right: 5%;">取 消</el-button>
+          </div>
+        </el-dialog>
+    </el-card>
+</template>
+
+<script>
+import moment from 'moment'
+export default {
+  data () {
+    return {
+      activeStateCfg: {
+        0: '未开始',
+        1: '报名中',
+        2: '进行中',
+        3: '已结束'
+      },
+      typeOptions: [],
+      categoryOptions: [],
+      queryParams: {
+        page: 1,
+        limit: 10,
+        typeId: '',
+        categoryId: '',
+        activityName: '',
+        startEndDate: '',
+        startDate: '',
+        endDate: ''
+      },
+      total: 0,
+      dataList: [],
+      loading: false,
+      show: false,
+      signCodeUrl: ''
+    }
+  },
+  created () {
+    this.getTypeOptions()
+    this.getCategoryOptions()
+  },
+  mounted () {
+    this.getList()
+  },
+  methods: {
+    getList () {
+      this.loading = true
+      let { startEndDate, ...newParams } = JSON.parse(JSON.stringify(this.queryParams))
+      this.$http.get('/core/activity/page', { params: newParams }).then(res => {
+        if (res.data.code !== 0) return this.$message.error(res.data.msg)
+        this.dataList = res.data.data.list || []
+        this.total = res.data.data.total || 0
+        this.loading = false
+      })
+    },
+    handleReset () {
+      this.queryParams = {
+        page: 1,
+        limit: 10,
+        typeId: '',
+        categoryId: '',
+        activityName: '',
+        startEndDate: '',
+        startDate: '',
+        endDate: ''
+      }
+      this.getList()
+    },
+    pageSizeChangeHandle (val) {
+      this.queryParams.limit = val
+      this.getList()
+    },
+    pageCurrentChangeHandle (val) {
+      this.queryParams.page = val
+      this.getList()
+    },
+    handleDateChange (val) {
+      this.queryParams.startDate = moment(val[0]).format('YYYY-MM-DD')
+      this.queryParams.endDate = moment(val[1]).format('YYYY-MM-DD')
+    },
+    getTypeOptions () {
+      this.$http.get('/core/activity/type/page', { params: { page: 1, limit: -1 } }).then(res => {
+        this.typeOptions = res.data.data.list || []
+      })
+    },
+    getCategoryOptions () {
+      this.$http.get('/core/activity/category/page', { params: { page: 1, limit: -1 } }).then(res => {
+        this.categoryOptions = res.data.data.list || []
+      })
+    },
+    handleAdd () {
+      this.$router.push({ name: 'activityAdd' })
+    },
+    handleEdit (row) {
+      this.$router.push({ name: 'activityAdd', query: { id: row.id } })
+    },
+    handleInfo (row) {
+      this.$router.push({ name: 'activityApplyInfo', query: { id: row.id } })
+    },
+    handleCode (row) {
+      this.$http.get('/core/activity/genSignCode/' + row.id).then(res => {
+        if (res.data.code !== 0) return this.$message.error(res.data.msg)
+        this.$message.success('生成成功')
+        this.getList()
+      })
+    },
+    handleReviewCode (row) {
+      this.show = true
+      this.signCodeUrl = row.signCode
+    },
+    cancel () {
+      this.show = false
+    },
+    downloadImg () {
+      const link = document.createElement('a')
+      link.style.display = 'none'
+      link.href = this.signCodeUrl
+      link.setAttribute('download', '签到码')
+      document.body.appendChild(link)
+      link.click()
+      document.body.removeChild(link)
+      this.show = false
+    },
+    handleUpDown (row, state) {
+      this.$confirm(`是否确认${state ? '上架' : '下架'}活动【${row.activityName}】?`, '提示', {
+        confirmButtonText: '确定',
+        cancelButtonText: '取消',
+        type: 'warning'
+      }).then(() => {
+        this.$http.post('/core/activity/updState', { id: row.id, state }).then(res => {
+          if (res.data.code !== 0) return this.$message.error(res.data.msg)
+          this.$message.success((state ? '上架' : '下架') + '成功')
+          this.getList()
+        })
+      })
+    },
+    handleDelete (row) {
+      this.$confirm(`是否确认删除活动【${row.activityName}】?`, '提示', {
+        confirmButtonText: '确定',
+        cancelButtonText: '取消',
+        type: 'warning'
+      }).then(() => {
+        this.$http.delete('/core/activity', { 'data': [row.id] }).then(res => {
+          if (res.data.code !== 0) return this.$message.error(res.data.msg)
+          this.$message.success('删除成功')
+          this.getList()
+        })
+      }).catch(() => {
+        this.$message({
+          type: 'info',
+          message: '已取消删除'
+        })
+      })
+    }
+  }
+}
+</script>
+
+<style scoped lang="scss">
+  .title{
+    font-family: PingFang-SC, PingFang-SC;
+    font-weight: bold;
+    font-size: 16px;
+    color: #252525;
+    line-height: 22px;
+  }
+
+  .query_text{
+    font-family: PingFangSC, PingFang SC;
+    font-weight: 400;
+    font-size: 14px;
+    color: #393939;
+    line-height: 20px;
+    width: 80px;
+    margin-right: 16px;
+  }
+
+  .as{
+    font-family: PingFangSC, PingFang SC;
+    font-weight: 400;
+    font-size: 14px;
+    color: #646464;
+    line-height: 16px;
+    padding: 5px 10px;
+    background: #F7F7F7;
+    border-radius: 6px;
+    display: inline-block;
+    &.jxz{
+      background: #FFF5E8;
+      color: #FF980A;
+    }
+  }
+
+  .code-img{
+    width: 100%;
+    height: 500px;
+    img{
+      width: 100%;
+      height: auto;
+    }
+  }
+</style>

+ 0 - 24
src/views/modules/activity/manager.vue

@@ -1,24 +0,0 @@
-<template>
-    <el-card shadow="never" class="aui-card--fill">
-        <div class="mod-home">
-            <h3>活动管理</h3>
-        </div>
-    </el-card>
-</template>
-
-<script>
-export default {
-  data () {
-    return {
-
-    }
-  },
-  methods: {
-
-  }
-}
-</script>
-
-<style scoped lang="scss">
-
-</style>

+ 5 - 5
src/views/modules/activity/type.vue

@@ -105,7 +105,7 @@ export default {
     },
     handleEdit (row) {
       this.$http.get('/core/activity/type/' + row.id).then(res => {
-        if (res.data.code !== 0) return this.$message.error(res.msg)
+        if (res.data.code !== 0) return this.$message.error(res.data.msg)
         this.form = { ...this.form, ...res.data.data }
         this.$nextTick(() => {
           this.title = '编辑活动类型'
@@ -127,7 +127,7 @@ export default {
     getList () {
       this.loading = true
       this.$http.get('/core/activity/type/page', { params: this.queryParams }).then(res => {
-        if (res.data.code !== 0) return this.$message.error(res.msg)
+        if (res.data.code !== 0) return this.$message.error(res.data.msg)
         this.dataList = res.data.data.list
         this.loading = false
       })
@@ -137,7 +137,7 @@ export default {
         if (valid) {
           this.$http[this.form.id ? 'put' : 'post']('/core/activity/type', this.form).then(res => {
             if (res.data.code !== 0) {
-              return this.$message.error(res.msg)
+              return this.$message.error(res.data.msg)
             }
             this.$message.success('保存成功')
             this.cancel()
@@ -152,7 +152,7 @@ export default {
       let dto = JSON.parse(JSON.stringify(row))
       dto.enable = enable
       this.$http.put('/core/activity/type', dto).then(res => {
-        if (res.data.code !== 0) return this.$message.error(res.msg)
+        if (res.data.code !== 0) return this.$message.error(res.data.msg)
         this.$message.success('操作成功')
         this.getList()
       })
@@ -164,7 +164,7 @@ export default {
         type: 'warning'
       }).then(() => {
         this.$http.delete('/core/activity/type', { 'data': [row.id] }).then(res => {
-          if (res.data.code !== 0) return this.$message.error(res.msg)
+          if (res.data.code !== 0) return this.$message.error(res.data.msg)
           this.$message.success('删除成功')
           this.getList()
         })