jazz
2022-03-04 5dfa4aae98c53f1f3d5f8b9fa5308f359bfea104
update_202203041923_短信中心列表,短信临时发送
2个文件已添加
9个文件已修改
613 ■■■■■ 已修改文件
src/config/baseConfig.js 9 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/layout/components/Sidebar/Logo.vue 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/layout/components/Sidebar/index.vue 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/pages/dashboard/index.vue 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/pages/index/index.vue 510 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/pages/login/index.vue 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/router/index.js 36 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/router/sms_router.js 22 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/router/system_router.js 22 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/settings.js 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
vue.config.js 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/config/baseConfig.js
@@ -1,6 +1,6 @@
var isCrossDomain = 1 // 是否跨域
var isTest = 0 // 是否测试
var isMock = 1 // 是否使用mock
var isTest = 1 // 是否测试
var isMock = 0 // 是否使用mock
// 线上非跨域
var baseUrl = '//线上请求路径/' // 基础路径(本地非跨域路径)
// 测试非跨域
@@ -8,7 +8,7 @@
// 打包后的环境!!!!!!!!!!!!
if (process.env && process.env.NODE_ENV !== 'development') {
  baseUrl = '/'
  baseUrl = '/sms/'
  isCrossDomain = 0
  isTest = 0
  isMock = 0
@@ -24,7 +24,8 @@
// 测试跨域
var cdTestBaseUrl = {
  name: '/api_test/',
  url: 'http://192.168.31.22:8080/',
  // url: 'http://192.168.2.106:3602/sms', // - 其
  url: 'https://phiskincrm.phiskin.com/sms', // - 线上
  // url: 'http://192.168.1.163:8080/',
  // url: 'http://192.168.31.143:8080/', //  - 和
  // url: 'http://192.168.31.143:8888/', //  - 和
src/layout/components/Sidebar/Logo.vue
@@ -24,7 +24,7 @@
  },
  data() {
    return {
      title: '”项目名称“',
      title: '短信中心',
      logo: ''
    }
  }
src/layout/components/Sidebar/index.vue
@@ -33,7 +33,8 @@
    ]),
    routes() {
      let routes = this.$router.options.routes
      routes = this.jun_filterAuth(routes, this.getAuthDataFN())
      routes = this.jun_filterAuth(routes, () => {})
      // routes = this.jun_filterAuth(routes, this.getAuthDataFN())
      // console.log('this.getAuthDataFN()', this.getAuthDataFN())
      // console.log('$router.options.routes', this.$router.options.routes)
      // console.log('routes', routes)
src/pages/dashboard/index.vue
@@ -1,6 +1,6 @@
<template>
  <div class="app-container">
    <h1 style="text-align: center;margin-top: 5%">欢迎来到”项目名称“</h1>
    <h1 style="text-align: center;margin-top: 5%">欢迎来到短信中心</h1>
  </div>
</template>
src/pages/index/index.vue
New file
@@ -0,0 +1,510 @@
<template>
  <div class="app-container">
    <!-- 返回按钮和标题 -->
    <!-- <el-page-header class="mb20" content="xx" @back="$router.go(-1)" /> -->
    <!-- 搜索区 ↓↓↓↓↓↓↓↓↓↓ -->
    <el-form v-show="showSearch" ref="searchForm" :inline="true">
      <el-form-item label="批次名称">
        <el-input
          v-model="batchName"
          placeholder="搜索批次名称"
          clearable
          size="small"
          style="width: 240px"
          maxlength="50"
          @keyup.enter.native="reGetList"
        />
      </el-form-item>
      <el-form-item label="批次编号">
        <el-input
          v-model="batchCode"
          placeholder="搜索批次编号"
          clearable
          size="small"
          style="width: 240px"
          maxlength="50"
          @keyup.enter.native="reGetList"
        />
      </el-form-item>
      <el-form-item>
        <el-button type="cyan" icon="el-icon-search" size="mini" @click="reGetList">搜索</el-button>
        <el-button icon="el-icon-refresh" size="mini" @click="resetHandle">重置</el-button>
      </el-form-item>
    </el-form>
    <!-- 搜索区 ↑↑↑↑↑↑↑↑↑↑ -->
    <!-- 操作区 ↓↓↓↓↓↓↓↓↓↓ -->
    <el-row :gutter="10" class="mb8">
      <el-col :span="1.5">
        <!-- 权限判断 v-if="getAuthValueFN('xxx_add')" -->
        <el-button
          type="primary"
          icon="el-icon-plus"
          size="mini"
          @click="showAddDialog"
        >临时发送</el-button>
      </el-col>
      <right-toolbar :show-search.sync="showSearch" @queryTable="getList" />
    </el-row>
    <!-- 操作区 ↑↑↑↑↑↑↑↑↑↑ -->
    <!--
      table参数设置:
      stripe 是否为斑马纹
      border 是否带有纵向边框
      max-height 最大高度
    -->
    <el-table :data="list" stripe>
      <el-table-column type="index" label="序号" align="center" width="60" />
      <el-table-column label="创建时间" prop="createTime" align="center" min-width="160" />
      <el-table-column label="批次名称" prop="batchName" align="center" />
      <el-table-column label="批次编号" prop="batchCode" align="center" />
      <el-table-column label="期望发送时间" prop="timingTime" align="center" min-width="160" />
      <el-table-column label="发送短信时间" prop="executionTime" align="center" min-width="160" />
      <el-table-column label="发送成功总数" prop="sendSuccess" align="center" />
      <el-table-column label="发送失败总数" prop="sendFail" align="center" />
      <el-table-column label="发送总数" prop="sendTotal" align="center" />
      <el-table-column label="状态" prop="status" align="center">
        <template slot-scope="scope">
          <span v-if="scope.row.isUp == 0">待执行</span>
          <span v-if="scope.row.isUp == 1">执行中</span>
          <span v-if="scope.row.isUp == 2">完成</span>
          <span v-if="scope.row.isUp == 3">取消</span>
          <span v-if="scope.row.isUp == 4">失败</span>
        </template>
      </el-table-column>
      <el-table-column label="短信模内容" prop="smsTemplate" align="center" min-width="160">
        <template slot-scope="scope">
          <el-popover
            placement="top-start"
            width="400"
            popper-class="el-popover_tableFilter"
            trigger="hover"
            :popper-options="{ removeOnDestroy: true }"
          >
            <div style="max-height: 500px;overflow-y: auto;">{{ scope.row.smsTemplate }}</div>
            <div slot="reference" class="line-clamp-2" style="line-height: 1.2">{{ scope.row.smsTemplate }}</div>
          </el-popover>
        </template>
      </el-table-column>
      <!-- <el-table-column label="是否上架" prop="isUp" align="center" min-width="100">
        <template slot-scope="scope">
          <el-switch
            v-model="scope.row.isUp"
            :active-value="1"
            :inactive-value="0"
            @change="handleUpChange(scope.row)"
          />
        </template>
      </el-table-column> -->
      <!-- <el-table-column label="操作" align="center" class-name="small-padding fixed-width" width="120">
        <template slot-scope="scope">
          <el-button
            size="mini"
            type="text"
            icon="el-icon-edit"
            @click="showEditDialog(scope.row)"
          >编辑</el-button>
          <el-button
            size="mini"
            type="text warn"
            icon="el-icon-delete"
            @click="handleDelete(scope.row)"
          >删除</el-button>
        </template>
      </el-table-column> -->
    </el-table>
    <!-- 新增&编辑 -->
    <el-dialog v-el-drag-dialog :title="'临时发送短信'" width="800px" :visible.sync="dialogVisible" append-to-body :before-close="hideDialog" :close-on-click-modal="false">
      <el-form ref="refDialog" :model="dialogData" label-width="110px" :rules="rules" size="small">
        <el-form-item label="批次名称" prop="batchName">
          <el-input v-model="dialogData.batchName" placeholder="请输入批次名称" maxlength="255" />
        </el-form-item>
        <el-form-item label="批次编号" prop="batchCode">
          <el-input v-model="dialogData.batchCode" placeholder="请输入批次编号" maxlength="255" />
        </el-form-item>
        <el-form-item label="上传文件" prop="uploadFiles">
          <div class="upload_single_file">
            <!-- 上传文件组件(单) -->
            <el-upload
              ref="refUploadFile"
              :auto-upload="false"
              action="#"
              :limit="1"
              :file-list="uploadFiles"
              :on-change="addUploadFile"
              :on-remove="delUploadFile"
              :http-request="uploadFileReq"
              :before-upload="beforeUploadFile"
              size="mini"
            >
              <el-button style="display: block" :disabled="uploadFiles&&uploadFiles.length>0" class="mb8" type="primary" size="small" icon="el-icon-plus">上传文件</el-button>
            </el-upload>
          </div>
        </el-form-item>
        <el-form-item label="短信模内容" prop="smsTemplate">
          <el-input v-model="dialogData.smsTemplate" type="textarea" placeholder="请输入短信模版内容" maxlength="500" rows="5" />
        </el-form-item>
        <!-- <el-form-item label="短信模内容" prop="smsTemplate">
          <WangEnduit :catchdata="catchData" :content="dialogData.smsTemplate" :rangenum="rangenum" />
        </el-form-item> -->
      </el-form>
      <div slot="footer" class="dialog-footer">
        <el-button @click="hideDialog">取消</el-button>
        <el-button type="primary" @click="submitHandle">确定</el-button>
      </div>
    </el-dialog>
    <pagination
      v-show="total>0"
      :total="total"
      :page.sync="pageNum"
      :limit.sync="pageSize"
      @pagination="getList"
    />
    <back-to-top :visibility-height="300" :back-position="50" transition-name="fade" />
  </div>
</template>
<script>
import BackToTop from '@/components/BackToTop'
// import WangEnduit from '@/components/WangEnduit' // 富文本
export default {
  name: 'Index',
  components: {
    BackToTop
    // WangEnduit
  },
  data() {
    return {
      showSearch: true, // 是否显示搜索区
      // keyWord: '', // 搜索区字段,可自行扩展其余字段
      batchName: '',
      batchCode: '',
      objectName: '短信', // 对象名称,用于删除提示、启用提示、弹窗标题等
      // 数据列表
      list: [],
      userList: [], // 用户列表
      uploadFiles: [], // 上传文件
      // 弹窗数据
      dialogVisible: false,
      dialogData: {},
      // 富文本编辑器
      // rangenum: null,
      // 分页 ↓↓↓↓↓↓↓↓↓↓
      total: 0,
      pageNum: 1,
      pageSize: 20,
      // 分页 ↑↑↑↑↑↑↑↑↑↑
      // 表单校验
      rules: {
        batchName: [
          { required: true, message: '批次名称不能为空', trigger: 'change' }
        ],
        batchCode: [
          { required: true, message: '批次编号不能为空', trigger: 'change' }
        ],
        smsTemplate: [
          { required: true, message: '短信模内容不能为空', trigger: 'change' }
        ]
        // isUp: [
        //   { required: true, message: '是否上架不能为空', trigger: 'change' }
        // ]
      }
    }
  },
  mounted() {
    this.init()
  },
  methods: {
    // 初始化
    init() {
      this.getList()
    },
    // ========== 富文本相关
    // 富文本编辑器的内容赋值
    // catchData(content) {
    //   if (content === '<p><br></p>') content = ''
    //   try {
    //     const currentRange = window.getSelection().getRangeAt(0)
    //     this.rangenum = currentRange
    //   } catch (e) {
    //     console.log(e)
    //   }
    //   this.$set(this.dialogData, 'smsTemplate', content)
    //   this.$refs['refDialog'].validateField('smsTemplate')
    // },
    // ========== 富文本相关
    // 获取列表
    getList() {
      var { pageNum, pageSize, batchName, batchCode } = this
      this.postFN({
        url: 'send-general/list',
        header: { 'Content-Type': 'application/json;charset=UTF-8' },
        params: {
          pageNum: pageNum,
          pageSize: pageSize,
          batchName: batchName,
          batchCode: batchCode
        },
        mockData: {
          code: 100,
          msg: '',
          data: {
            list: [{
              id: 'xxx',
              index: 1,
              name: '超级管理员',
              createTime: '2020-08-09 10:10:10'
            }],
            total: 100
          }
        }
      }, (inf) => {
        this.list = inf.list || []
        this.userList = inf.userList || []
        this.total = inf.total
      })
    },
    // 重新获取列表
    reGetList() {
      this.pageNum = 1
      this.getList()
    },
    // 重置
    resetHandle() {
      this.batchCode = ''
      this.batchName = ''
      this.reGetList()
    },
    // 删除
    handleDelete(item) {
      // 打开二次确认弹窗
      this.$confirm('是否确认删除该' + this.objectName + '?', '提示', {
        confirmButtonText: '确定',
        cancelButtonText: '取消',
        type: 'warning'
      }).then(() => {
        // 确定回调
        // TODO url
        this.postFN({
          url: 'xxx',
          params: {
            id: item.id
          },
          mockData: {
            code: 100,
            msg: '',
            data: {}
          }
        }, () => {
          this.getList()
          this.$messageSuc('删除成功')
        })
      }).catch(() => {})
    },
    // 修改是否上架
    handleUpChange(item) {
      const text = item.isUp === 1 ? '上架' : '下架'
      this.$confirm('确认要' + text + '该' + this.objectName + '吗?', '提示', {
        confirmButtonText: '确定',
        cancelButtonText: '取消',
        type: 'warning'
      }).then(() => {
        // TODO url
        this.postFN({
          url: 'xxx',
          params: {
            id: item.id,
            isUp: item.isUp
          },
          mockData: {
            code: 100,
            msg: '',
            data: {}
          }
        }, () => {
          this.$messageSuc(text + '成功')
        }, (res) => {
          item.isUp = item.isUp === 1 ? 0 : 1
          this.$messageError(res.msg)
        })
      }).catch(() => {
        item.isUp = item.isUp === 1 ? 0 : 1
      })
    },
    // 打开新增弹窗
    showAddDialog() {
      var dialogData = {
        batchCode: '',
        batchName: '',
        smsTemplate: ''
      }
      this.uploadFiles = []
      this.dialogVisible = true
      this.$nextTick(() => {
        this.dialogData = dialogData
        this.$refs['refDialog'].resetFields()
      })
    },
    // 打开编辑弹框
    showEditDialog(item) {
      var dialogData = {
        type: 'edit',
        ...item
      }
      console.log('dialogData', dialogData)
      this.dialogVisible = true
      this.$nextTick(() => {
        this.dialogData = dialogData
        this.$refs['refDialog'].resetFields()
      })
    },
    // 关闭编辑弹窗
    hideDialog() {
      this.dialogData = {
      }
      this.dialogVisible = false
      // 清空富文本
      // this.rangenum = null
    },
    // 提交新增&编辑
    submitHandle() {
      this.$refs['refDialog'].validate(valid => {
        if (valid) {
          this.uploadFileReq()
          // this.submitReq()
        }
      })
    },
    // 提交接口
    submitReq() {
      var { dialogData } = this
      var params = {
        name: dialogData.name,
        isUp: dialogData.isUp
        // TODO 参数
      }
      if (dialogData.password) params.password = dialogData.password
      var isAdd = dialogData.type === 'add'
      // TODO url
      var url = isAdd ? 'xxx/add' : 'xxx/edit'
      !isAdd && (params.id = dialogData.id)
      this.postFN({
        url: url,
        params: params,
        mockData: {
          code: 100,
          msg: '',
          data: {}
        }
      }, () => {
        this.$messageSuc('保存成功')
        this.hideDialog()
        isAdd ? this.reGetList() : this.getList()
      })
    },
    // 上传文件 ↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓
    // 上传前确认格式
    beforeUploadFile(file) {
      const isTooLarge = file.size / 1024 / 1024 > 50
      let flag = true
      if (isTooLarge) {
        this.$message.error('请勿上传大于50MB的文件')
        flag = false
      }
      return flag
    },
    // 增加文件
    addUploadFile(file, fileList) {
      this.uploadFiles = fileList
    },
    // 删除文件
    delUploadFile(file, fileList) {
      this.uploadFiles = fileList
    },
    // 执行上传商品图
    runUploadFile(suc_cb) {
      if (this.checkNeedUpload(this.uploadFiles)) {
        this.callback = suc_cb
        this.$refs.refUploadFile.submit()
      } else {
        suc_cb && suc_cb()
      }
    },
    // 上传文件
    uploadFileReq() {
      var { dialogData, uploadFiles } = this
      var file
      uploadFiles[0] && (file = uploadFiles[0].raw)
      const formData = new FormData()
      for (const key in dialogData) {
        formData.append(key, dialogData[key])
      }
      formData.append('file', file)
      if (!file) {
        this.$message.error('请上传文件')
        return
      }
      console.log('/*******************提交数据formData/', dialogData, file)
      this.postFN({
        url: 'send-general/temporary-send',
        header: { 'Content-Type': 'multipart/form-data' },
        params: formData,
        mockData: {
          code: 100,
          msg: '',
          data: {
            imgUrl: '上传文件成功'
          }
        }
      }, (inf) => {
        console.log('上传文件成功且结束', inf)
        this.reGetList()
        this.hideDialog()
        // 提交
        // this.$set(this.dialogData, 'imgUrl', inf.imgUrl)
        // this.callback && this.callback(inf.imgUrl)
      })
    },
    // 获取文件后缀名
    extname(filename) {
      if (!filename || typeof filename !== 'string') {
        return ''
      }
      const a = filename.split('').reverse().join('')
      const b = a.substring(0, a.search(/\./)).split('').reverse().join('')
      return b
    }
    // 上传文件 ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑
  }
}
</script>
<style lang="scss" scoped>
.upload_single_file .el-upload-list__item-name{
  padding: 5px!important;
}
</style>
src/pages/login/index.vue
@@ -3,7 +3,7 @@
    <el-form ref="loginForm" :model="loginForm" :rules="loginRules" class="login-form" autocomplete="on" label-position="left">
      <div class="title-container">
        <h3 class="title">”项目名称“</h3>
        <h3 class="title">短信中心</h3>
      </div>
      <el-form-item prop="username">
src/router/index.js
@@ -7,9 +7,10 @@
import Layout from '@/layout'
import demo_router from './demo_router'
import system_router from './system_router'
import op_router from './op_router'
import agreement_router from './agreement_router'
import sms_router from './sms_router'
// import system_router from './system_router'
// import op_router from './op_router'
// import agreement_router from './agreement_router'
/**
 * 注:子菜单只出现在路线子时。长度> = 1
@@ -60,21 +61,22 @@
    }]
  },
  system_router,
  // system_router,
  sms_router,
  demo_router,
  agreement_router,
  // agreement_router,
  {
    path: 'external-link',
    component: Layout,
    children: [
      {
        path: 'https://panjiachen.github.io/vue-element-admin-site/#/',
        meta: { title: '外链', icon: 'link' },
        auth: 'external_link'
      }
    ]
  },
  // {
  //   path: 'external-link',
  //   component: Layout,
  //   children: [
  //     {
  //       path: 'https://panjiachen.github.io/vue-element-admin-site/#/',
  //       meta: { title: '外链', icon: 'link' },
  //       auth: 'external_link'
  //     }
  //   ]
  // },
  // {
  //   path: '/demo',
@@ -89,7 +91,7 @@
  //   ]
  // },
  op_router,
  // op_router,
  // 404 page must be placed at the end !!!
  { path: '*', redirect: '/404', hidden: true }
src/router/sms_router.js
New file
@@ -0,0 +1,22 @@
// 路由配置文件
import Layout from '@/layout'
export default {
  path: '/index',
  component: Layout,
  redirect: '/index/index',
  name: 'index',
  meta: {
    title: '短信管理',
    icon: 'coupon'
  },
  children: [
    {
      path: 'index',
      component: () => import('@/pages/index/index'), // Parent router-view
      name: 'index',
      meta: { title: '短信列表' }
    }
  ]
}
src/router/system_router.js
@@ -1,3 +1,11 @@
/*
 * @Author: your name
 * @Date: 2022-03-03 17:45:27
 * @LastEditTime: 2022-03-03 18:03:24
 * @LastEditors: your name
 * @Description: 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
 * @FilePath: \sms_center_backstage\src\router\system_router.js
 */
// 路由配置文件
import Layout from '@/layout'
@@ -25,13 +33,13 @@
      meta: { title: '角色管理', keepAlive: true },
      auth: 'sys_admin_role_see'
    },
    {
      path: 'banner',
      component: () => import('@/pages/system/banner'),
      name: 'systemBanner',
      meta: { title: '轮播图管理' },
      auth: 'banner_see'
    },
    // {
    //   path: 'banner',
    //   component: () => import('@/pages/system/banner'),
    //   name: 'systemBanner',
    //   meta: { title: '轮播图管理' },
    //   auth: 'banner_see'
    // },
    {
      path: 'basic',
      component: () => import('@/pages/system/basic'),
src/settings.js
@@ -1,5 +1,5 @@
module.exports = {
  title: '”项目名称“',
  title: '短信中心',
  /**
   * @type {boolean} true | false
vue.config.js
@@ -32,7 +32,8 @@
  devServer: {
    proxy: {
      '/api_test': {
        target: 'http://192.168.31.22:8080/',
        // target: 'http://192.168.2.106:3602/sms', // - 其
        target: 'https://phiskincrm.phiskin.com/sms', // - 线上
        // target: 'http://192.168.1.163:8080/',
        // target: 'http://192.168.31.143:8080/', // 和
        // target: 'http://192.168.31.143:8888/', // 和