Ver código fonte

添加对讲频道管理

wuyunfeng 3 anos atrás
pai
commit
4724e4be28

+ 0 - 0
.env


+ 83 - 0
src/api/ncs_channel.js

@@ -0,0 +1,83 @@
+import request from '@/utils/request'
+
+/**
+ * 对讲频道相关接口
+ * @param params
+ * @returns {*|Promise|Promise<unknown>}
+ */
+export function getList(params) {
+  return request({
+    url: '/ncs/channel/page',
+    method: 'POST',
+    loading: true,
+    data: params,
+    headers: { 'Content-Type': 'application/x-www-form-urlencoded' }
+  })
+}
+
+/** 新增对讲频道 */
+export function add(params) {
+  return request({
+    url: '/ncs/channel',
+    method: 'POST',
+    loading: true,
+    data: params
+  })
+}
+
+/** 删除对讲频道 */
+export function remove(params) {
+  const ids = params.toString()
+  return request({
+    url: `/ncs/channel/${ids}`,
+    method: 'DELETE',
+    loading: true,
+    data: params
+  })
+}
+
+/** 更新对讲频道 */
+export function update(id, params) {
+  return request({
+    url: `/ncs/channel/${id}`,
+    method: 'put',
+    data: params
+  })
+}
+
+/** 查询对讲频道 */
+export function get(id, params) {
+  return request({
+    url: `/ncs/channel/${id}`,
+    method: 'get',
+    loading: false,
+    params
+  })
+}
+
+/**
+ * 获取频道的订阅者列表 返回List<ClerkDO> 或null
+ * @param id 频道Id
+ * @returns {AxiosPromise | * | Promise | Promise<unknown>}
+ */
+export function getChannelSubscribers(id) {
+  return request({
+    url: `/channelsubscribe/subscribers/${id}`,
+    method: 'get',
+    loading: false
+  })
+}
+
+/**
+ * 批量设置频道订阅者
+ * @param params {channel_id:12,member_ids:[]}
+ * @returns {*|Promise|Promise<unknown>}
+ */
+export function setChannelSubscribers(params) {
+  return request({
+    url: `/channelsubscribe/subscribers`,
+    method: 'post',
+    loading: false,
+    data: params
+  })
+}

+ 1 - 1
src/components/AgGridCustomFilter/ListFilter.vue

@@ -103,6 +103,6 @@ export default {
     }
 
     .el-transfer-panel__body {
-        height: 180px;
+        min-height: 150px;
     }
 </style>

+ 14 - 1
src/router/index.js

@@ -40,7 +40,6 @@ import Layout from '@/layout'
  * a base page that does not have permission requirements
  * all roles can be accessed
  */
-console.log('version', uiVersion === 1)
 export const constantRoutes = [
   {
     path: '/redirect',
@@ -196,6 +195,20 @@ export const partRoutes = [
     ]
   },
   {
+    path: '/ncs-channel',
+    component: Layout,
+    redirect: '/ncs-channel/index',
+    children: [
+      {
+        path: 'index',
+        component: () => import('@/views/ncs-channel/index'),
+        name: 'ncsChannel',
+        meta: { title: '对讲频道', icon: 'el-icon-mobile-phone', noCache: true }
+      }
+    ],
+    hidden: uiVersion === 1
+  },
+  {
     path: '/remark',
     component: Layout,
     redirect: '/remark/index',

+ 527 - 0
src/views/ncs-channel/index.vue

@@ -0,0 +1,527 @@
+<template>
+  <div>
+    <ag-grid-layout
+      toolbar
+      :table-height="tableHeight"
+      theme="ag-theme-alpine"
+      :column-defs="columnDefs"
+      :row-data="rowData"
+      :locale-text="localeText"
+      :grid-options="gridOptions"
+      :default-col-def="defaultColDef"
+      :animate-rows="true"
+      :row-selection="rowSelection"
+      :enable-cell-change-flash="true"
+      @filterChanged="filterModifed"
+      @sortChanged="gridSortChange"
+    >
+      <!--        @rowDoubleClicked="getList"-->
+      <div slot="toolbar" class="inner-toolbar">
+        <div class="toolbar-search">
+          <en-table-search placeholder="请输入搜索关键字" @search="handlerSearch" />
+        </div>
+        <div class="toolbar-btns">
+          <el-button type="primary" size="mini" @click="createChannel">新增频道</el-button>
+        </div>
+      </div>
+      <el-pagination
+        v-if="pageData"
+        slot="pagination"
+        :current-page="pageData.page_no"
+        :page-sizes="[10, 20, 50, 100]"
+        :page-size="pageData.page_size"
+        layout="total, sizes, prev, pager, next, jumper"
+        :total="pageData.data_total"
+        @size-change="handlePageSizeChange"
+        @current-change="handlePageCurrentChange"
+      />
+    </ag-grid-layout>
+    <el-dialog :title.sync="formtitle" :visible.sync="formshow" width="35%">
+      <div>
+        <el-form ref="editform" :rules="rules" label-width="120px" :model="formmodel">
+
+          <el-row>
+            <el-col :span="24">
+              <el-form-item label="频道名称" prop="channel_name">
+                <el-input
+                  v-model="formmodel.channel_name"
+                  clearable
+                  :maxlength="100"
+                  placeholder="请输入频道名称"
+                />
+              </el-form-item>
+            </el-col>
+          </el-row>
+        </el-form>
+
+      </div>
+      <div slot="footer" class="dialog-footer">
+        <el-button @click="formshow = false">取 消</el-button>
+        <el-button type="primary" @click="handlerFormSubmit('editform')">确 定</el-button>
+      </div>
+    </el-dialog>
+    <el-dialog :title.sync="subscribeTitle" :visible.sync="formSubscribe" width="50%">
+
+      <div>
+        <fieldset v-for="(item,index) in channelSubscribers" v-if="item.roleName!=='管理员'" :key="index" style="margin-top: 10px">
+          <legend><span style="margin-right: 10px">{{ item.roleName }} </span><el-checkbox v-model="item.allCkeck" style="float: right;" :indeterminate="item.indeterminate" @change="(checked)=>{handleCheckAll(checked,item)}">全选</el-checkbox></legend>
+          <el-row :gutter="20" type="flex" style="padding: 10px">
+            <el-col :span="24">
+              <el-checkbox v-for="(clerk,_index) in item.clerks" :key="_index" v-model="clerk.checked" @change="handleCheckboxChanged(item)">{{ clerk.clerk_name }}</el-checkbox>
+            </el-col>
+          </el-row>
+        </fieldset>
+      </div>
+      <div slot="footer" class="dialog-footer">
+        <el-button @click="formSubscribe = false">取 消</el-button>
+        <el-button type="primary" @click="handlerSubscribeSubmit">确 定</el-button>
+      </div>
+    </el-dialog>
+  </div>
+
+</template>
+
+<script>
+import { AG_GRID_LOCALE_CN } from '@/utils/AgGridVueLocaleCn'
+import ButtonCellRender from '../../components/AgGridCellRender/ButtonCellRender'
+import * as API_Channel from '@/api/ncs_channel'
+import { unix2Date } from '@/utils/Foundation'
+import * as API_Clerk from '@/api/ncs_clerk'
+import ListFilter from '@/components/AgGridCustomFilter/ListFilter'
+import RadioFilter from '@/components/AgGridCustomFilter/RadioFilter'
+
+export default {
+  name: 'Index',
+  components: { ButtonCellRender, ListFilter, RadioFilter },
+  data() {
+    return {
+      tableData: [],
+      /** 列表参数 */
+      params: {
+        page_size: 20,
+        page_no: 1,
+        fixedCondition: ' part_id = ' + this.$store.getters.partId
+      },
+      /** 新建组织弹出参数 **/
+      formtitle: '新增频道',
+      formshow: false,
+      /** 频道订阅设置 */
+      formSubscribe: false,
+      formmodel: {},
+      frameGroups: [],
+      rules: {
+        channel_name: [
+          { required: true, message: '频道名称不能为空', trigger: 'blur' }
+        ]
+      },
+      timeRange: [new Date(2020, 11, 11, 7, 0), new Date(2020, 11, 11, 8, 0)],
+      checkWeek: [],
+      /** ag-grid参数 **/
+      pageData: [],
+      loading: false,
+      errorId: null,
+      shopVisible: false,
+      columnDefs: null,
+      rowData: null,
+      defaultColDef: null,
+      gridOptions: null,
+      gridApi: null,
+      columnApi: null,
+      localeText: AG_GRID_LOCALE_CN,
+      filterState: null,
+      rowSelection: null,
+      frameworkComponents: null,
+      /** 频道订阅者情况数组 */
+      channelSubscribers: [],
+      subscribeTitle: ''
+    }
+  },
+  computed: {
+    tableHeight() {
+      return this.mainAreaHeight - 130
+    }
+
+  },
+  beforeMount() {
+    this.gridOptions = {}
+    this.columnDefs = [
+      {
+        headerName: '#',
+        headerCheckboxSelection: true,
+        headerCheckboxSelectionFilteredOnly: true,
+        checkboxSelection: true,
+        sortable: false, filter: false,
+        width: 100,
+        resizable: false,
+        valueGetter: this.hashValueGetter
+      },
+      { headerName: 'ID', field: 'id', sortable: true, filter: 'agNumberColumnFilter', width: 130 },
+      {
+        headerName: '频道名称', field: 'channel_name', sortable: true, filter: 'agTextColumnFilter', flex: 1
+      },
+      // lockPosition 锁定位置,会在第一列
+      // lockPinned = true 不能拖动然后固定
+      // resizeable 单元个大小是否可以调整
+      {
+        headerName: '创建时间',
+        field: 'create_time',
+        sortable: true,
+        filter: 'agNumberColumnFilter',
+        width: 200,
+        valueFormatter: this.unixDateFormatter
+      },
+      {
+        headerName: '编辑', field: 'id',
+        cellRendererFramework: 'ButtonCellRender',
+        cellRendererParams: {
+          onClick: this.handEdit,
+          label: '编辑',
+          buttonType: 'primary',
+          buttonSize: 'mini'
+        },
+        filter: false,
+        pinned: 'right',
+        lockPinned: true,
+        width: 100,
+        resizable: false,
+        sortable: false
+      },
+
+      {
+        headerName: '订阅管理', field: 'id',
+        cellRendererFramework: 'ButtonCellRender',
+        cellRendererParams: {
+          onClick: this.manageSubscribe,
+          label: '订阅管理',
+          buttonType: 'success',
+          buttonSize: 'mini'
+        },
+        filter: false,
+        pinned: 'right',
+        lockPinned: true,
+        width: 100,
+        resizable: false,
+        sortable: false
+      },
+
+      {
+        headerName: '删除', field: 'id',
+        cellRendererFramework: 'ButtonCellRender',
+        cellRendererParams: param => {
+          return {
+            onClick: this.deleteSingle,
+            label: '删除',
+            buttonType: 'danger',
+            buttonSize: 'mini'
+          }
+        },
+        pinned: 'right',
+        lockPinned: true,
+        width: 100,
+        resizable: false,
+        filter: false,
+        sortable: false
+      }
+    ]
+    this.defaultColDef = {
+      sortable: true,
+      resizable: true,
+      comparator: this.dateCustomComparator,
+      filterParams: {
+        debounceMs: 200,
+        newRowsAction: 'keep',
+        textCustomComparator: this.textCustomComparator,
+        comparator: this.dateCustomComparator
+      }
+    }
+    this.rowSelection = 'multiple'
+  },
+  mounted() {
+    window.onresize = this.windowResize
+    this.gridApi = this.gridOptions.api
+    this.gridColumnApi = this.gridOptions.columnApi
+    // 设置默认排序字段,应用列状态之后会触发 gridSortChange 函数,会调用getlist,后面不需要再调用this.getlist
+    this.gridColumnApi.applyColumnState({
+      state: [
+        {
+          colId: 'id',
+          sort: 'asc'
+        }
+      ]
+    })
+    this.getEmployees()
+  },
+  methods: {
+    windowResize() {
+      this.$set(this, 'mainAreaHeight', Number(document.documentElement.clientHeight) - 84)
+    },
+    handlerDelete(ids) {
+      this.$confirm('删除操作后数据不可复原,您确定要删除此数据?', '警告', {
+        confirmButtonText: '确定',
+        cancelButtonText: '取消',
+        type: 'warning'
+      }).then(() => {
+        API_Channel.remove(ids).then(
+          response => {
+            this.getList()
+            this.$message({
+              type: 'success',
+              message: '删除成功!'
+            })
+          }
+        ).catch(response => {
+          this.$message({
+            type: 'info',
+            message: response.message
+          })
+        })
+      }).catch(() => {
+        this.$message({
+          type: 'info',
+          message: '已取消删除'
+        })
+      })
+    },
+    deleteSingle(row) {
+      this.handlerDelete(row.id)
+    },
+
+    /**
+             * 创建频道
+             */
+    createChannel() {
+      this.formshow = true
+      this.formmodel = {
+        channel_name: '',
+        part_id: this.$store.getters.partId
+      }
+    },
+    /** 分页大小发生改变 */
+    handlePageSizeChange(size) {
+      this.params.page_size = size
+      this.getList()
+    },
+
+    /** 分页页数发生改变 */
+    handlePageCurrentChange(page) {
+      this.params.page_no = page
+      this.getList()
+    },
+    /** 加载列表数据 */
+    getList() {
+      this.loading = true
+      const param = this.MixinClone(this.params)
+      this.gridApi.showLoadingOverlay()
+      API_Channel.getList(param).then(response => {
+        this.loading = false
+        // this.tableData = [...response.data]
+        this.pageData = {
+          page_no: response.page_no,
+          page_size: response.page_size,
+          data_total: response.data_total
+        }
+        this.$nextTick(() => {
+          const node = this.gridApi.getDisplayedRowAtIndex(0)
+          if (node !== null && node !== undefined) {
+            node.setSelected(true)
+          }
+        })
+        this.rowData = [...response.data]
+        this.refreshPlayStatus()
+      }).catch(() => {
+        this.loading = false
+      })
+    },
+    /** 处理搜索 */
+    handlerSearch(keywords) {
+      this.params.query = keywords
+      this.getList()
+    },
+    /** 处理字段排序 */
+    tableSort(column) {
+      if (column.order !== null) {
+        this.params.sort = column.prop
+        this.params.dir = column.order === 'ascending' ? 'asc' : 'desc'
+      } else {
+        this.params.sort = null
+        this.params.dir = null
+      }
+      this.getList()
+    },
+    /**
+             * 格式化unix时间戳
+             **/
+    unixDateFormatter(param) {
+      if (!param.value) return ''
+      return unix2Date(param.value * 1000)
+    },
+
+    gridSortChange(param) {
+      const columnState = param.columnApi.getColumnState()
+      // 排序状态
+      const sortState = columnState.filter(function(s) {
+        return s.sort != null
+      }).map(function(s) {
+        return {
+          colId: s.colId,
+          sort: s.sort,
+          sortIndex: s.sortIndex
+        }
+      }).sort(function(a, b) {
+        return a.sortIndex - b.sortIndex
+      })
+      if (sortState.length > 0) {
+        if (sortState.length === 1) {
+          this.params.sort = sortState[0].colId
+          this.params.dir = sortState[0].sort
+        } else {
+          let sortstring = ''
+          sortState.forEach(function(item) {
+            sortstring += item.colId + ' ' + item.sort + ','
+          })
+          this.params.sort = sortstring.substring(0, sortstring.length - 1)
+          this.params.dir = ' '
+        }
+      } else {
+        delete this.params.sort
+        delete this.params.dir
+      }
+      this.getList()
+    },
+
+    filterModifed(param) { // todo 通过转换后的数值过滤,需要转回原始数值
+      var model = param.api.getFilterModel()
+      this.params.filter = JSON.stringify(model)
+      this.getList()
+    },
+
+    handEdit(row) {
+      this.formmodel = {
+        ...row
+      }
+      this.formshow = true
+    },
+    /**
+             * 提交新增表单
+             * @param formname
+             */
+    handlerFormSubmit(formName) {
+      this.$refs[formName].validate((valid) => {
+        if (valid) {
+          if (!this.formmodel.id) {
+            /** 新增 */
+            this.formmodel.part_id = this.$store.getters.partId
+
+            API_Channel.add(this.formmodel).then(() => {
+              this.formshow = false
+              this.$message.success('新增成功!')
+              this.getList()
+            })
+          } else {
+            API_Channel.update(this.formmodel.id, this.formmodel).then(() => {
+              this.formshow = false
+              this.$message.success('修改成功!')
+              this.getList()
+            })
+          }
+        } else {
+          this.$message.error('表单填写错误,请检查!')
+        }
+      })
+    },
+
+    handlerSubscribeSubmit() {
+      let subscribeIds = []
+      this.channelSubscribers.forEach(item => {
+        subscribeIds = [...item.clerks.filter(p => p.checked).map(p => p.member_id), ...subscribeIds]
+      })
+      API_Channel.setChannelSubscribers({ channel_id: this.formmodel.id, member_ids: subscribeIds.length === 0 ? null : [...subscribeIds] }).then(() => {
+        this.$message.success('修改成功!')
+      })
+    },
+    manageSubscribe(row) {
+      this.formmodel = { ...row }
+      API_Channel.getChannelSubscribers(row.id).then(res => {
+        this.channelSubscribers.forEach(item => {
+          item.clerks.map(k => {
+            k.checked = res.map(p => p.member_id).includes(k.member_id)
+            return k
+          })
+          const checkedLength = item.clerks.filter(p => p.checked).length
+          this.$set(item, 'allCkeck', item.clerks.length === checkedLength)
+          this.$set(item, 'indeterminate', (checkedLength !== 0) && (item.clerks.length !== checkedLength))
+        })
+      })
+      this.subscribeTitle = row.channel_name + '订阅管理'
+      this.formSubscribe = true
+    },
+    getEmployees() {
+      const _this = this
+      _this.nurses = []
+      API_Clerk.listByPartRoleId({ partId: this.$store.getters.partId }).then(res => {
+        _this.clerks = res
+        const groupBy = (arr, func) =>
+          arr.map(typeof func === 'function' ? func : val => val[func]).reduce((acc, val, i) => {
+            acc[val] = (acc[val] || []).concat(arr[i])
+            return acc
+          }, {})
+        const groupData = groupBy(res, item => item.role_name)
+        _this.nurses = Object.entries(groupData)
+
+        _this.nurses.forEach(item => {
+          this.channelSubscribers.push({ 'roleName': item[0], 'clerks': item[1].map(i => { return { ...i, 'checked': false } }), 'allCheck': false, 'indeterminate': false })
+        })
+      })
+    },
+    handleCheckboxChanged(item) {
+      this.countAllRole(item)
+    },
+    /** 计算传入角色组的选择情况 */
+    countAllRole(role) {
+      const _list = []
+      if (!Array.isArray(role)) {
+        if (role.clerks) _list.push(...this.countAllRole(role.clerks))
+      } else {
+        role.forEach(item => {
+          _list.push(item)
+        })
+      }
+      const length = _list.length
+      const length_checked = _list.filter(_item => _item.checked).length
+      this.$set(role, 'allCkeck', length === _list.filter(_item => _item.checked).length)
+      this.$set(role, 'indeterminate', (length_checked !== 0) && (length !== length_checked))
+      return _list
+    },
+    handleCheckAll(checked, item) {
+      this.$set(item, 'indeterminate', false)
+      this.setFrameCheck(item, checked)
+    },
+    /** 设置选择状态 */
+    setFrameCheck(item, checked) {
+      const perm = this.MixinClone(item)
+      if (!Array.isArray(perm)) {
+        this.$set(item, 'checked', checked)
+        if (item.clerks && item.clerks.length) {
+          this.$set(item, 'clerks', this.setFrameCheck(item.clerks, checked))
+        }
+      } else {
+        perm.map(item => {
+          item.checked = checked
+          this.$set(item, 'checked', checked)
+          if (item.clerks && item.clerks.length) {
+            this.$set(item, 'clerks', this.setFrameCheck(item.clerks, checked))
+          }
+        })
+      }
+      return perm
+    }
+  }
+}
+</script>
+
+<style scoped>
+    fieldset{
+        border:1px solid #DCDFE6;
+        border-radius: 5px;
+    }
+</style>