浏览代码

自定义看板屏幕设计

wuyunfeng 2 年之前
父节点
当前提交
8c186deb2b

+ 13 - 1
languages/en.js

@@ -991,7 +991,9 @@ module.exports = {
     debugging485: '485 debugging',
     deviceFrame: 'Device space',
     ledDevice: 'LED devices',
-    entraceguardUser:'Passage setting'
+    entraceguardUser:'Passage setting',
+    customBoardManage: 'Custom Board Screen',
+    customBoardDesigner:'Designer Board Screen'
   },
   deviceType: {
     NURSE_HOST: 'Nurse Host',
@@ -1151,5 +1153,15 @@ module.exports = {
     refreshUser:'Refresh Users',
     yes:'YES',
     nop:'NO'
+  },
+  boardTitle:{
+    add:'Add information board screen',
+    screenTitle:'Screen Title',
+    showIndex:'Display order',
+    partId:'Department ID',
+    design:'Design content',
+    titleRequire:'Screen title cannot be empty',
+    createTitle:'New information board custom screen',
+    editTitle:'Edit information board custom screen'
   }
 }

+ 13 - 1
languages/es.js

@@ -991,7 +991,9 @@ module.exports = {
     debugging485: '485 depurando',
     deviceFrame: 'Espacio del dispositivo',
     ledDevice: 'Dispositivos LED',
-    entraceguardUser:'Configuración de paso'
+    entraceguardUser:'Configuración de paso',
+    customBoardManage: 'Pantalla de tablero personalizada',
+    customBoardDesigner:'Pantalla del tablero de diseño'
   },
   deviceType: {
     NURSE_HOST: 'Enfermera anfitriona',
@@ -1150,5 +1152,15 @@ module.exports = {
     refreshUser:'Actualizar usuarios',
     yes:'Sí.',
     nop:'No.'
+  },
+  boardTitle:{
+    add:'Añadir pantalla de visualización de información',
+    screenTitle:'Título de la pantalla',
+    showIndex:'Orden de visualización',
+    partId:'Departamento ID',
+    design:'Contenido del diseño',
+    titleRequire:'El título de la pantalla no puede estar vacío',
+    createTitle:'Nueva pantalla personalizada de la Junta de información',
+    editTitle:'Editar la pantalla personalizada del tablero de información'
   }
 }

+ 13 - 1
languages/ru-RU.js

@@ -968,7 +968,9 @@ module.exports = {
     debugging485: '485 отладка',
     deviceFrame: 'Пространство устройства',
     ledDevice: 'Светодиодные устройства',
-    entraceguardUser:'Параметры прохода'
+    entraceguardUser:'Параметры прохода',
+    customBoardManage: 'Настройка экрана панели',
+    customBoardDesigner:'Экран панели'
   },
   deviceType: {
     NURSE_HOST: 'Устройство медсестры',
@@ -1127,5 +1129,15 @@ module.exports = {
     refreshUser:'Actualizar usuarios',
     yes:'Да.',
     nop:'Нет'
+  },
+  boardTitle:{
+    add:'Добавить информационный экран',
+    screenTitle:'Заголовок экрана',
+    showIndex:'Показать последовательность',
+    partId:'Сектор ID',
+    design:'Содержание проекта',
+    titleRequire:'Заголовок экрана не может быть пустым',
+    createTitle:'Дополнительный экран панели',
+    editTitle:'Изменить панель сообщений'
   }
 }

+ 13 - 1
languages/zh-CN.js

@@ -992,7 +992,9 @@ module.exports = {
     debugging485: '485调试',
     deviceFrame: '设备空间',
     ledDevice: 'LED点阵屏',
-    entraceguardUser:'用户通行设置'
+    entraceguardUser:'用户通行设置',
+    customBoardManage: '自定义信息看板屏',
+    customBoardDesigner:'看板屏设计'
   },
   deviceType: {
     NURSE_HOST: '护士主机',
@@ -1152,5 +1154,15 @@ module.exports = {
     refreshUser:'刷新可用用户',
     yes:'是',
     nop:'否'
+  },
+  boardTitle:{
+    add:'添加看板屏幕',
+    screenTitle:'屏幕标题',
+    showIndex:'显示顺序',
+    partId:'科室ID',
+    design:'设计内容',
+    titleRequire:'屏幕标题不能为空',
+    createTitle:'新增看板自定义屏',
+    editTitle:'编辑自定义看板屏'
   }
 }

+ 1 - 0
package.json

@@ -59,6 +59,7 @@
     "vue-seamless-scroll": "^1.1.23",
     "vue-splitpane": "1.0.4",
     "vuedraggable": "^2.20.0",
+    "vue-lazyload": "^1.2.6",
     "vuex": "3.1.0",
     "xlsx": "0.14.1"
   },

+ 69 - 0
src/api/ncs_board_item.js

@@ -0,0 +1,69 @@
+import request from '@/utils/request'
+
+/**
+ * 自定义看板项相关接口
+ * @param params
+ * @returns {*|Promise|Promise<unknown>}
+ */
+export function getList(params) {
+    return request({
+        url: '/ncs/boarditem/page',
+        method: 'POST',
+        loading: true,
+        data: params,
+        headers: { 'Content-Type': 'application/x-www-form-urlencoded' }
+    })
+}
+
+/** 新增自定义看板项 */
+export function add(params) {
+    return request({
+        url: '/ncs/boarditem',
+        method: 'POST',
+        loading: true,
+        data: params
+    })
+}
+
+/** 删除自定义看板项 */
+export function remove(params) {
+    const ids = params.toString()
+    return request({
+        url: `/ncs/boarditem/${ids}`,
+        method: 'DELETE',
+        loading: true,
+        data: params
+    })
+}
+
+/** 更新自定义看板项 */
+export function update(id, params) {
+    return request({
+        url: `/ncs/boarditem/${id}`,
+        method: 'put',
+        data: params
+    })
+}
+
+/** 查询自定义看板项 */
+export function get(id, params) {
+    return request({
+        url: `/ncs/boarditem/${id}`,
+        method: 'get',
+        loading: false,
+        params
+    })
+}
+
+
+/** 获取某科室下的所有看板项 */
+export function getPartList(part_id) {
+    return request({
+        url: `/ncs/boarditem/partboarditem/${part_id}`,
+        method: 'get',
+        loading: false
+    })
+}
+
+
+

+ 83 - 0
src/api/ncs_board_title.js

@@ -0,0 +1,83 @@
+import request from '@/utils/request'
+
+/**
+ * 自定义看板屏幕相关接口
+ * @param params
+ * @returns {*|Promise|Promise<unknown>}
+ */
+export function getList(params) {
+    return request({
+        url: '/ncs/boardtitle/page',
+        method: 'POST',
+        loading: true,
+        data: params,
+        headers: { 'Content-Type': 'application/x-www-form-urlencoded' }
+    })
+}
+
+/** 新增自定义看板屏幕 */
+export function add(params) {
+    return request({
+        url: '/ncs/boardtitle',
+        method: 'POST',
+        loading: true,
+        data: params
+    })
+}
+
+/** 删除自定义看板屏幕 */
+export function remove(params) {
+    const ids = params.toString()
+    return request({
+        url: `/ncs/boardtitle/${ids}`,
+        method: 'DELETE',
+        loading: true,
+        data: params
+    })
+}
+
+/** 更新自定义看板屏幕 */
+export function update(id, params) {
+    return request({
+        url: `/ncs/boardtitle/${id}`,
+        method: 'put',
+        data: params
+    })
+}
+
+/** 查询自定义看板屏幕 */
+export function get(id, params) {
+    return request({
+        url: `/ncs/boardtitle/${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 - 0
src/icons/svg/delete.svg


文件差异内容过多而无法显示
+ 1 - 0
src/icons/svg/designer.svg


文件差异内容过多而无法显示
+ 1 - 0
src/icons/svg/list-move.svg


文件差异内容过多而无法显示
+ 1 - 0
src/icons/svg/pen-leather.svg


文件差异内容过多而无法显示
+ 1 - 0
src/icons/svg/setting.svg


+ 1 - 0
src/layout/components/Navbar.vue

@@ -157,6 +157,7 @@ export default {
     switchLanguage(value) {
       if (value === 'zh') {
         this.$i18n.locale = 'zh'
+
       } else if (value === 'en') {
         this.$i18n.locale = 'en'
       } else if (value === 'es') {

+ 31 - 0
src/router/index.js

@@ -408,6 +408,37 @@ export const partRoutes = [
     ],
     hidden: uiVersion === 2
   },
+
+  {
+    path: '/board-title',
+    component: Layout,
+    redirect: '/custom-infoboard/board-title',
+    children: [
+      {
+        path: 'index',
+        component: () => import('@/views/custom-infoboard/board-title'),
+        name: 'BoardTitle',
+        meta: { title: i18n.t('tab.customBoardManage'), icon: 'designer', noCache: true }
+      }
+    ],
+    hidden: uiVersion === 2
+  },
+  {
+    path: '/calling-board-designer',
+    component: Layout,
+    redirect: '/custom-infoboard/screen-designer',
+    children: [
+      {
+        path: 'index/:id?',
+        component: () => import('@/views/custom-infoboard/screen-designer'),
+        name: 'BoardDesigner',
+        meta: { title: i18n.t('tab.customBoardDesigner'), icon: 'el-icon-data-board', noCache: true }
+      }
+    ],
+    hidden: true
+  },
+
+
   {
     path: '/ncs-event',
     component: Layout,

+ 102 - 0
src/styles/element-ui.scss

@@ -82,3 +82,105 @@
 .el-range-separator {
   box-sizing: content-box;
 }
+
+/*  -- flex弹性布局 -- */
+
+.flex {
+  display: flex;
+}
+
+.basis-xs {
+  flex-basis: 20%;
+}
+
+.basis-sm {
+  flex-basis: 40%;
+}
+
+.basis-df {
+  flex-basis: 50%;
+}
+
+.basis-lg {
+  flex-basis: 60%;
+}
+
+.basis-xl {
+  flex-basis: 80%;
+}
+
+.flex-sub {
+  flex: 1;
+}
+
+.flex-twice {
+  flex: 2;
+}
+
+.flex-treble {
+  flex: 3;
+}
+
+.flex-direction {
+  flex-direction: column;
+}
+
+.flex-wrap {
+  flex-wrap: wrap;
+}
+
+.align-start {
+  align-items: flex-start;
+}
+
+.align-end {
+  align-items: flex-end;
+}
+
+.align-center {
+  align-items: center;
+}
+
+.align-stretch {
+  align-items: stretch;
+}
+
+.self-start {
+  align-self: flex-start;
+}
+
+.self-center {
+  align-self: flex-center;
+}
+
+.self-end {
+  align-self: flex-end;
+}
+
+.self-stretch {
+  align-self: stretch;
+}
+
+.align-stretch {
+  align-items: stretch;
+}
+
+.justify-start {
+  justify-content: flex-start;
+}
+
+.justify-end {
+  justify-content: flex-end;
+}
+
+.justify-center {
+  justify-content: center;
+}
+
+.justify-between {
+  justify-content: space-between;
+}
+
+.justify-around {
+  justify-content: space-around;
+}

+ 426 - 0
src/views/custom-infoboard/board-title.vue

@@ -0,0 +1,426 @@
+<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="this.$t('action.keywords')" @search="handlerSearch" />
+                </div>
+                <div class="toolbar-btns">
+                    <el-button type="primary" size="mini" @click="createChannel">{{ this.$t('boardTitle.add') }}</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="this.$t('boardTitle.screenTitle')" prop="board_title">
+                                <el-input
+                                        v-model="formmodel.board_title"
+                                        clearable
+                                        :maxlength="100"
+                                        :placeholder="this.$t('boardTitle.screenTitle')"
+                                />
+                            </el-form-item>
+                        </el-col>
+                        <el-col :span="12">
+                            <el-form-item :label="this.$t('boardTitle.showIndex')" prop="board_index">
+                                <el-input-number v-model="formmodel.board_index" :min="3" :max="100" :label="this.$t('boardTitle.showIndex')" />
+                            </el-form-item>
+                        </el-col>
+                    </el-row>
+                </el-form>
+
+            </div>
+            <div slot="footer" class="dialog-footer">
+                <el-button @click="formshow = false">{{ this.$t('action.cancel') }}</el-button>
+                <el-button type="primary" @click="handlerFormSubmit('editform')">{{ this.$t('action.yes') }}</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_BoardTitle from '@/api/ncs_board_title'
+    import { unix2Date } from '@/utils/Foundation'
+    import ListFilter from '@/components/AgGridCustomFilter/ListFilter'
+    import RadioFilter from '@/components/AgGridCustomFilter/RadioFilter'
+    import ButtonCellRenderList from "@/components/AgGridCellRender/ButtonCellRenderList";
+
+    export default {
+        name: "board-title",
+        components: { ButtonCellRenderList, ButtonCellRender, ListFilter, RadioFilter },
+        data() {
+            return {
+                tableData: [],
+                /** 列表参数 */
+                params: {
+                    page_size: 20,
+                    page_no: 1,
+                    fixedCondition: ' part_id = ' + this.$store.getters.partId
+                },
+                /** 新建组织弹出参数 **/
+                formtitle: this.$t('boardTitle.createTitle'),
+                formshow: false,
+                /** 频道订阅设置 */
+                formSubscribe: false,
+                formmodel: {},
+                frameGroups: [],
+                rules: {
+                    board_title: [
+                        { required: true, message: this.$t('boardTitle.titleRequire'), trigger: 'blur' }
+                    ]
+                },
+                /** 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: '',
+                choiceAll: this.$t('action.choiceAll')
+            }
+        },
+        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: this.$t('boardTitle.screenTitle'), field: 'board_title', sortable: true, filter: 'agTextColumnFilter', flex: 1
+                },
+                {
+                    headerName: this.$t('boardTitle.showIndex'), field: 'board_index', sortable: true, filter: 'agNumberColumnFilter', flex: 1
+                },
+                {
+                    headerName: this.$t('boardTitle.partId'), field: 'part_id', sortable: true, filter: 'agNumberColumnFilter', flex: 1
+                },
+
+                // lockPosition 锁定位置,会在第一列
+                // lockPinned = true 不能拖动然后固定
+                // resizeable 单元个大小是否可以调整
+                { headerName: this.$t('action.handle'), field: 'id',
+                    cellRendererFramework: 'ButtonCellRenderList',
+                    cellRendererParams: param => {
+                        return {
+                            list: [
+                                {
+                                    onClick: this.handEdit,
+                                    label: this.$t('action.edit'),
+                                    buttonType: 'primary',
+                                    buttonSize: 'mini'
+                                },
+                                {
+                                    onClick: this.deleteSingle,
+                                    label: this.$t('action.delete'),
+                                    buttonType: 'danger',
+                                    buttonSize: 'mini',
+                                },
+                                {
+                                    onClick: this.toDesigner,
+                                    label: this.$t('boardTitle.design'),
+                                    buttonType: 'warning',
+                                    buttonSize: 'mini',
+                                }
+
+                            ]}
+                    },
+                    filter: false,
+                    pinned: 'right',
+                    lockPinned: true,
+                    minWidth: this.$i18n.locale === 'zh' ? 310 : 350,
+                    resizable: 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'
+                    }
+                ]
+            })
+
+        },
+        methods: {
+            windowResize() {
+                this.$set(this, 'mainAreaHeight', Number(document.documentElement.clientHeight) - 84)
+            },
+            handlerDelete(ids) {
+                this.$confirm(this.$t('action.sureDelete'), this.$t('action.waring'), {
+                    confirmButtonText: this.$t('action.yes'),
+                    cancelButtonText: this.$t('action.cancel'),
+                    type: 'warning'
+                }).then(() => {
+                    API_BoardTitle.remove(ids).then(
+                        response => {
+                            this.getList()
+                            this.$message({
+                                type: 'success',
+                                message: this.$t('action.deleted')
+                            })
+                        }
+                    ).catch(response => {
+                        this.$message({
+                            type: 'info',
+                            message: response.message
+                        })
+                    })
+                }).catch(() => {
+                    this.$message({
+                        type: 'info',
+                        message: this.$t('action.cancelDelete')
+                    })
+                })
+            },
+            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_BoardTitle.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.formtitle=this.$t('boardTitle.editTitle')
+                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_BoardTitle.add(this.formmodel).then(() => {
+                                this.formshow = false
+                                this.$message.success(this.$t('action.addSuccess'))
+                                this.getList()
+                            })
+                        } else {
+                            API_BoardTitle.update(this.formmodel.id, this.formmodel).then(() => {
+                                this.formshow = false
+                                this.$message.success(this.$t('action.editSuccess'))
+                                this.getList()
+                            })
+                        }
+                    } else {
+                        this.$message.error(this.$t('action.fromError'))
+                    }
+                })
+            },
+
+            handlerSubscribeSubmit() {
+                let subscribeIds = []
+                this.channelSubscribers.forEach(item => {
+                    subscribeIds = [...item.clerks.filter(p => p.checked).map(p => p.member_id), ...subscribeIds]
+                })
+                API_BoardTitle.setChannelSubscribers({ channel_id: this.formmodel.id, member_ids: subscribeIds.length === 0 ? null : [...subscribeIds] }).then(() => {
+                    this.formSubscribe = false
+                    this.$message.success(this.$t('action.editSuccess'))
+                })
+            },
+
+            toDesigner(row) {
+                this.$router.push({ name: 'BoardDesigner', params: { id:row.id }})
+            }
+
+
+        }
+    }
+
+</script>
+
+<style scoped>
+
+</style>

+ 69 - 0
src/views/custom-infoboard/mixin.js

@@ -0,0 +1,69 @@
+import layoutItem from './templates/layout-item'
+export default {
+    props: {
+        /** 数据 */
+        data: {
+            type: Object,
+            default: () => ({})
+        },
+        /** 是否为编辑模式 */
+        isEdit: {
+            type: Boolean,
+            default: false
+        }
+    },
+    components: {
+        layoutItem
+    },
+    methods: {
+        /** 获取颜色相关信息 */
+        colors(columnIndex = 0) {
+            const _colors = this.data.columnList[columnIndex].titleColors
+            return {
+                title: `background-color: ${_colors[0]}; background-image: linear-gradient(90deg, ${_colors.join(',')});`,
+                color: (colorIndex = 0) => `color: ${_colors[colorIndex]}`
+            }
+        },
+        /** 获取区块链接 */
+        blockHref(block) {
+            const { opt_type, opt_value } = block.block_opt
+            switch (opt_type) {
+                // 链接地址
+                case 'URL': return opt_value
+                // 商品
+                case 'GOODS': return `/goods/${opt_value}`
+                // 关键字
+                case 'KEYWORD': return `/goods?keyword=${encodeURIComponent(opt_value)}`
+                // 店铺
+                case 'SHOP': return `/shop/${opt_value}`
+                // 分类
+                case 'CATEGORY': return `/goods?category=${opt_value}`
+                default: return '/'
+            }
+        },
+        /** 构建空的block */
+        emptyBlock(num = 3, type) {
+            return [...new Array(num)].map(() => ({
+                block_type: type,
+                block_value: '',
+                block_opt: {
+                    opt_type: 'NONE',
+                    opt_value: ''
+                }
+            }))
+        },
+        /** 编辑区块 */
+        handleEditBlock(columnIndex, blockIndex) {
+            console.log(JSON.stringify(this.data))
+            this.$emit('edit-block', JSON.parse(JSON.stringify(this.data)), columnIndex, blockIndex)
+        },
+        /** 编辑标题 */
+        handleEditTitle(columnIndex) {
+            this.$emit('edit-title', JSON.parse(JSON.stringify(this.data)), columnIndex)
+        },
+        /** 编辑标签 */
+        handleEditTags(columnIndex) {
+            this.$emit('edit-tags', JSON.parse(JSON.stringify(this.data)), columnIndex)
+        }
+    }
+}

+ 459 - 0
src/views/custom-infoboard/screen-designer.vue

@@ -0,0 +1,459 @@
+<template>
+    <div class="container">
+        <el-header class="bg-blue" style="width: 1210px;margin:0 auto;">
+            <!--        <el-image :src="logo" style="width: 50px; height: 50px" fit="fill" />-->
+            <el-row>
+                <el-col :span="8">
+                    <div class="title text-shadow text-white text-left " style="font-size: 26px;overflow: hidden;text-overflow: ellipsis;width: 100%;height:60px;">{{ partInfo.full_name }} {{ partInfo.part_name }}</div>
+                </el-col>
+                <el-col :span="8">
+                    <div class="content_title" data-aos="zoom-in-up">{{ titleData.board_title }}</div>
+                </el-col>
+                <el-col :span="8" >
+                    <div class="time text-right" style="font-size: 26px">{{ currentTime }}</div>
+                </el-col>
+            </el-row>
+        </el-header>
+        <div class="floor-container" :style="{height:floorContainerHeight+'px' }">
+
+            <div class="tpl-box" :style="tplBoxStyle">
+                <draggable v-model="templateArray" :options="tplOptions" class="tpl-list">
+                    <div v-for="item in templateArray" :class="'item-' + item.tpl_id" class="tpl-item">
+                        <el-row>
+                            <el-col :span="24/item.tpl_id" v-for="size in item.tpl_id" :key="size" class="grid-content" :class="'bg-purple-'+size"></el-col>
+                        </el-row>
+                        <span class="text-tpl">{{ templates[item.tpl_id].title }}</span>
+                    </div>
+                </draggable>
+                <el-button type="primary" @click="handleSaveFloor" class="save-btn">保存发布</el-button>
+                <div class="tpl-btns">
+                    <div class="btn-item" @click="tplBoxShow = !tplBoxShow">
+                        <i v-if="tplBoxShow" class="el-icon-d-arrow-left"></i>
+                        <i v-else class="el-icon-d-arrow-right"></i>
+                    </div>
+                    <div style="border-top: 1px dashed #ccc;margin: 2px 0"></div>
+                    <el-tooltip class="item" effect="dark" content="快捷保存" placement="right">
+                        <div class="btn-item" @click="handleSaveFloor">
+                            <i class="el-icon-upload"></i>
+                        </div>
+                    </el-tooltip>
+                </div>
+            </div>
+
+            <div class="draggable-box floor">
+                <div class="floor-body">
+                    <draggable v-model="floorList" :options="floorOptions" class="floor-list">
+                        <div v-for="(item, index) in floorList" :class="'item-' + item.tpl_id" class="floor-item">
+                            <component
+                                    :is="templates[item.tpl_id]"
+                                    :data="JSON.parse(JSON.stringify(item))"
+                                    is-edit
+                                    @edit-block="(...props) => {  handleEditBlock(index, ...props) }"
+                                    @edit-title="(...props) => { handleEditTitle(index, ...props) }"
+                                    @edit-tags="(...props) => { handleEditTags(index, ...props) }"
+                            ></component>
+                            <div class="panel-handle">
+                                <span class="icon-handle handle-move"><svg-icon icon-class="drag"/></span>
+                                <span class="icon-handle handle-setting" @click="() => { handleModule(index, JSON.parse(JSON.stringify(item))) }"><svg-icon icon-class="setting"/></span>
+                                <span class="icon-handle handle-delete" @click="floorList.splice(index, 1)"><svg-icon icon-class="delete"/></span>
+                            </div>
+                        </div>
+                    </draggable>
+                </div>
+
+            </div>
+
+        </div>
+
+        <board-item-setting
+        :default-data="boardItemConfig"
+        :show="settingShow"
+        :board-items="boardItems"
+        @close="settingShow=false"
+        @confirm="handleBoardItemSet"
+        ></board-item-setting>
+
+        <board-module-setting
+                :default-data="boardModuleConfig"
+                :show="moduleSettingShow"
+                @close="moduleSettingShow=false"
+                @confirm="handleBoardModuleSet"
+        >
+
+        </board-module-setting>
+    </div>
+</template>
+
+<script>
+    import Vue from 'vue'
+    import draggable from 'vuedraggable'
+    import templates, { templateArray } from './templates'
+    import VueLazyload from 'vue-lazyload'
+    import BoardItemSetting from "./templates/board-item-setting";
+    import BoardModuleSetting from "./templates/board-module-setting";
+    import * as API_BoardTitle from '@/api/ncs_board_title'
+    import * as API_BoardItem from '@/api/ncs_board_item'
+    Vue.use(VueLazyload)
+    import moment from 'moment'
+    require('moment/locale/zh-cn')
+    export default {
+        name: "screen-designer",
+        components: {BoardModuleSetting, BoardItemSetting, draggable },
+        data(){
+            return{
+                currentTime: '',
+                templates,
+                templateArray,
+                boardItemConfig:{},
+                boardModuleConfig:{},
+                settingShow:false,
+                moduleSettingShow:false,
+                //看板标题
+                titleData:{},
+                //标题id
+                titleId:this.$route.params.id,
+                /** 模板列表 */
+                tplList: [],
+                /** 模板配置 */
+                tplOptions: {
+                    group: { name: 'tplGroup', pull: 'clone', put: false },
+                    sort: false
+                },
+                tplBoxShow:true,
+                /** 楼层列表 */
+                floorList: [],
+                /** 楼层配置 */
+                floorOptions: {
+                    animation: 150,
+                    group: { name: 'tplGroup', put: true },
+                    sort: true,
+                    handle: '.handle-move'
+                },
+                boardItems:[{
+                    area_content: "2,5,7",
+                    area_content_style: "color:green;",
+                    area_label: "今日出院",
+                    area_label_style: "color:red;",
+                    area_size: 1,
+                    his_board_title_keyval: "1",
+                    his_keyval: "1",
+                    his_part_keyval: "1"
+                }]
+
+            }
+        },
+        computed: {
+            // 楼层模板盒子样式
+            tplBoxStyle() {
+                const { sidebar } = this.$store.getters
+                let left = (sidebar.opened ? 210 : 60)
+                left = this.tplBoxShow ? left : left - 300
+                return {
+                    left: left + 'px'
+                }
+            },
+            floorContainerHeight() {
+                return  this.mainAreaHeight-60
+            },
+            partInfo() {
+                return this.$store.getters.organization
+            }
+        },
+        beforeRouteUpdate(to, from, next) {
+            this.titleId = to.params.id
+            next()
+        },
+        activated() {
+            this.titleId = this.$route.params.id
+        },
+       async mounted(){
+           this.boardItems = await API_BoardItem.getPartList(this.$store.getters.partId)
+            moment.locale()
+            this.currentTime = moment().format('YYYY-MM-DD HH:mm:ss dddd')
+            this.getBoardTitle()
+
+        },
+        methods:{
+            /** 保存发布 */
+            handleSaveFloor() {
+                this.titleData.content_config= JSON.stringify(this.floorList)
+                API_BoardTitle.update(this.titleData.id, this.titleData).then(() => this.$message.success('保存发布成功!'))
+            },
+
+            handleBoardItemSet(settingData){
+              console.log(settingData)
+                const { index, target, columnIndex } = this.editOptions
+                const blockData = {...settingData}
+                target.columnList[columnIndex]=blockData
+                this.$set(this.floorList, index, target)
+            },
+            handleBoardModuleSet(settingData){
+                const { index, blockdata } = this.editOptions
+                const moduleSetting = {...settingData}
+                blockdata.moduleStyle=moduleSetting
+                this.$set(this.floorList, index, blockdata)
+            },
+
+            /** 编辑楼层区块 */
+            handleEditBlock(index, target, columnIndex) {
+
+                const blockData = target.columnList[columnIndex]
+
+                this.settingShow=true
+                this.boardItemConfig = {...blockData}
+                // const block = target.columnList[columnIndex].blockList[blockIndex]
+                // const type = block.block_type
+                 this.editOptions = { index, target, columnIndex }
+                // const blockData = JSON.parse(JSON.stringify(block))
+                // if (type === 'IMAGE') {
+                //     this.defaultImageData = blockData.block_value ? [{
+                //         url: blockData.block_value,
+                //         opt: blockData.block_opt
+                //     }] : null
+                //     this.dialogImageShow = true
+                // } else if (type === 'GOODS') {
+                //     // 填充默认数据
+                //     // this.defaultGoodsData = blockData.block_value ? [blockData.block_value.goods_id] : []
+                //     // this.dialogGoodsShow = true
+                // } else if (type === 'BRAND') {
+                //     console.log('品牌模块')
+                // }
+            },
+
+            handleModule(index,blockdata){
+               this.boardModuleConfig = {...blockdata.moduleStyle}
+                this.editOptions = { index, blockdata }
+                this.moduleSettingShow=true
+              console.log(index,blockdata)
+            },
+
+            /** 编辑楼层标题 */
+            handleEditTitle(index, target, columnIndex) {
+                this.editOptions = { index, target, columnIndex }
+                const column = target.columnList[columnIndex]
+                const columnData = JSON.parse(JSON.stringify(column))
+                this.defaultTitleData = {
+                    text: column.title,
+                    start_color: column.titleColors[0],
+                    end_color: column.titleColors[1]
+                }
+                this.dialogTitleShow = true
+            },
+            /** 编辑楼层标签 */
+            handleEditTags(index, target, columnIndex) {
+                this.editOptions = { index, target, columnIndex }
+                const column = target.columnList[columnIndex]
+                const columnData = JSON.parse(JSON.stringify(column))
+                this.defaultTagsData = columnData.tagList
+                this.dialogTagsShow = true
+            },
+            getBoardTitle(){
+                API_BoardTitle.get(this.titleId,{}).then(
+                    res=>{
+                        console.log('res',res)
+                     this.titleData={...res}
+                     if(res.content_config!==null&&res.content_config!==''){
+                         this.floorList=JSON.parse(res.content_config)
+                         this.floorList.forEach(item=>{
+                             item.columnList.forEach(col=>{
+                                 if(col.boardItemHisKeyVal!==''){
+                                     console.log('col', this.boardItems)
+                                     const boardItem = this.boardItems.filter(p=>p.his_keyval===col.boardItemHisKeyVal)[0]
+                                     console.log('boardItem',boardItem)
+                                     if(boardItem!==null&&boardItem!==undefined){
+                                         col.content=boardItem.area_content
+                                         col.label=boardItem.area_label
+                                     }
+                                 }
+                             })
+                         })
+                     }else{
+                         this.floorList=[]
+                     }
+                    }
+                ).catch(error=>{
+                  this.$message.error(error.message)
+                })
+            }
+
+        }
+    }
+</script>
+
+<style scoped type="text/scss">
+    .container {
+        min-width: 1366px;
+    }
+    .floor-container {
+        display: flex;
+        justify-content: space-around;
+        background-color: #E5E7EA;
+        padding: 10px;
+    }
+    .draggable-box {
+        position: relative;
+        display: flex;
+        justify-content: center;
+        align-items: center;
+        flex-direction: column;
+        width: 80%;
+
+    }
+    .draggable-box .floor {
+        width: 1210px + 50px;
+        flex-shrink: 0;
+        align-items: center;
+    }
+    .tpl-list {
+        display: flex;
+        flex-wrap: wrap;
+        overflow: hidden;
+        width: 100%;
+        background-color: #fff;
+    }
+    .tpl-item {
+        display: flex;
+        width: 100%;
+        flex-direction: column;
+        justify-content: center;
+        box-sizing: border-box;
+        border-bottom: 2px solid #D9E0E7;
+        margin-bottom: 10px;
+        /*&.item-1 .img-tpl {*/
+        /*    background: url("../../../assets/pc-tpl-01.png") no-repeat;*/
+        /*    background-size: 100%;*/
+        /*}*/
+        /*&.item-2 .img-tpl {*/
+        /*    background: url("../../../assets/pc-tpl-02.png") no-repeat;*/
+        /*    background-size: 100%;*/
+        /*}*/
+        /*&.item-3 .img-tpl {*/
+        /*    background: url("../../../assets/pc-tpl-03.png") no-repeat;*/
+        /*    background-size: 100%;*/
+        /*}*/
+        /*&.item-4 .img-tpl {*/
+        /*    background: url("../../../assets/pc-tpl-04.png") no-repeat;*/
+        /*    background-size: 100%;*/
+        /*}*/
+    }
+    .img-tpl {
+        width: 100%;
+        min-height: 150px;
+    }
+    .text-tpl {
+        text-align: center;
+        margin: 5px 0;
+        color: #ACB0B9;
+        font-size: 12px;
+    }
+    .floor-body {
+        display: flex;
+        justify-content: center;
+        width: 100%;
+        height: 100%;
+        overflow-y: scroll;
+    }
+    .floor-list {
+        background-color: #E5E7EA;
+        min-width: 75%;
+        min-height: 500px;
+    }
+    .floor-item {
+        position: relative;
+        box-sizing: border-box;
+
+    }
+
+
+    .floor-item .panel-handle {
+        display: none;
+        position: absolute;
+        top: 0;
+        right: -25px;
+
+    }
+    .floor-item .panel-handle .icon-handle {
+        display: block;
+        cursor: pointer;
+        text-align: center;
+    }
+    .floor-item .panel-handle .svg-icon {
+        width: 25px;
+        height: 25px;
+        background-color: #fff;
+    }
+    .floor-item:hover .panel-handle{
+        display: block;
+    }
+    .floor-item:first-child .floor-layout {
+        margin-top: 0;
+    }
+    .tpl-box {
+        position: fixed;
+        top: 20%;
+        left: 180px;
+        z-index: 99;
+        width: 300px;
+        margin-top: (-500px - 32px + 84px) / 2;
+        border-top: 10px solid #fff;
+        box-shadow: 4px 5px 20px 0 rgba(0,0,0,.6);
+        transition: all ease .3s;
+    }
+
+    .tpl-box .tpl-list {
+        height: 300px;
+        overflow-y: scroll;
+    }
+    .tpl-box .save-btn {
+        width: 100%;
+    }
+    .tpl-box .tpl-btns {
+        position: absolute;
+        top: 50%;
+        right: -25px;
+        margin-top: -35px;
+        width: 25px;
+        height: 70px;
+        background-color: #fff;
+        text-align: center;
+        padding: 5px 0;
+
+    }
+
+    .tpl-box .tpl-btns .btn-item {
+        cursor: pointer;
+        padding: 5px 0;
+
+    }
+    .tpl-box .tpl-btns .btn-item + .btn-item {
+        margin-top: 8px;
+    }
+    .tpl-box .tpl-btns .btn-item:hover {
+        background-color: #46A0FC;
+        color: #fff
+    }
+    .bg-blue {
+        background-color: #0081ff;
+        color: #ffffff;
+    }
+    /deep/ .el-header{
+        line-height: 60px;
+    }
+    .content_title{font-size: 26px}
+    .grid-content {
+        border-radius: 4px;
+        min-height: 36px;
+    }
+    .el-col {
+        border-radius: 4px;
+    }
+    .bg-purple-1 {
+        background: #99a9bf;
+    }
+    .bg-purple-2 {
+        background: #d3dce6;
+    }
+    .bg-purple-3 {
+        background: #e5e9f2;
+    }
+</style>

+ 183 - 0
src/views/custom-infoboard/templates/board-item-setting.vue

@@ -0,0 +1,183 @@
+<template>
+    <el-dialog
+            :visible.sync="dialogVisible"
+            :close-on-click-modal="false"
+            :close-on-press-escape="false"
+            append-to-body
+            width="805px">
+        <div slot="title" class="image-picker-title">设置看板项</div>
+        <div class="image-picker-body">
+            <el-form :model="formmodel" label-width="100px">
+                <el-row :gutter="20">
+                    <el-col :span="12">
+                        <el-form-item label="标题文字颜色">
+                            <el-input placeholder="标题文字颜色" v-model="formmodel.labelColor">
+                                <el-color-picker slot="append" v-model="formmodel.labelColor" size="mini"></el-color-picker>
+                            </el-input>
+
+                        </el-form-item>
+                    </el-col>
+                    <el-col :span="12">
+                        <el-form-item label="标题背景颜色">
+                            <el-input placeholder="标题背景颜色" v-model="formmodel.labelBgColor">
+                                <el-color-picker slot="append" v-model="formmodel.labelBgColor" size="mini"></el-color-picker>
+                            </el-input>
+
+                        </el-form-item>
+                    </el-col>
+                    <el-col :span="12">
+                        <el-form-item label="内容文字颜色">
+                            <el-input placeholder="内容文字颜色" v-model="formmodel.contentColor">
+                                <el-color-picker slot="append" v-model="formmodel.contentColor" size="mini"></el-color-picker>
+                            </el-input>
+                        </el-form-item>
+                    </el-col>
+                    <el-col :span="12">
+
+                            <el-form-item label="内容背景颜色">
+                                <el-input placeholder="内容背景颜色" v-model="formmodel.contentBgColor">
+                                    <el-color-picker slot="append" v-model="formmodel.contentBgColor" size="mini"></el-color-picker>
+                                </el-input>
+                            </el-form-item>
+                    </el-col>
+                    <el-col :span="12">
+
+                        <el-form-item label="标题区域宽度">
+                            <el-input placeholder="标题区域宽度" v-model="formmodel.labelWidth" type="number">
+                                <template slot="append">px</template>
+                            </el-input>
+                        </el-form-item>
+                    </el-col>
+                    <el-col :span="12">
+
+                        <el-form-item label="标题文字大小">
+                            <el-input placeholder="标题文字大小" v-model="formmodel.labelTextSize" type="number">
+                                <template slot="append">px</template>
+                            </el-input>
+                        </el-form-item>
+                    </el-col>
+
+                    <el-col :span="12">
+                        <el-form-item label="内容文字大小">
+                            <el-input placeholder="内容文字大小" v-model="formmodel.contentTextSize" type="number">
+                                <template slot="append" class="padding-content">px</template>
+                            </el-input>
+                        </el-form-item>
+                    </el-col>
+               <el-col :span="24">
+                   <el-form-item label="显示看板项" prop="boardItemHisKeyVal">
+                       <el-select v-model="formmodel.boardItemHisKeyVal"
+                                  placeholder="请选择要显示的看板项"
+                                  @change="boardItemChange"
+                                  clearable
+                                  >
+                           <el-option v-for="(item, index) in boardItems" :key="index"
+                                      :label="item.area_label" :value="item.his_keyval"/>
+                       </el-select>
+                   </el-form-item>
+               </el-col>
+                </el-row>
+            </el-form>
+        </div>
+        <div slot="footer" class="image-picker-footer">
+            <span>
+        <el-button @click="dialogVisible = false">取 消</el-button>
+      <el-button type="primary" @click="handleConfirm">确 定</el-button>
+      </span>
+        </div>
+    </el-dialog>
+</template>
+
+<script>
+    export default {
+        name: "board-item-setting",
+        props: {
+            /** 显示dialog */
+            show: {
+                type: Boolean,
+                default: false
+            },
+            /** 默认数据 */
+            defaultData: {
+                type: Object,
+                default: () => {
+                }
+            },
+            boardItems:{
+                type:Array,
+                default:()=>([])
+            }
+        },
+        data() {
+            return {
+                dialogVisible: this.show,
+                color:'#ffffff',
+                formmodel:{...this.defaultData},
+                predefineColors: [
+                    '#ff4500',
+                    '#ff8c00',
+                    '#ffd700',
+                    '#90ee90',
+                    '#00ced1',
+                    '#1e90ff',
+                    '#c71585',
+                    'rgba(255, 69, 0, 0.68)',
+                    'rgb(255, 120, 0)',
+                    'hsv(51, 100, 98)',
+                    'hsva(120, 40, 94, 0.5)',
+                    'hsl(181, 100%, 37%)',
+                    'hsla(209, 100%, 56%, 0.73)',
+                    '#c7158577'
+                ]
+            }
+        },
+        methods: {
+            handleConfirm() {
+                this.$emit('confirm', this.formmodel)
+                this.$emit('close')
+            },
+            boardItemChange(val){
+                console.log('selectchagne',val)
+                if(val!==''){
+                    const selected = this.boardItems.filter(p=>p.his_keyval===val)[0]
+                    this.formmodel.label = selected.area_label
+                    this.formmodel.content=selected.area_content
+                }else{
+                    this.formmodel.label = '标题'
+                    this.formmodel.content='内容'
+                }
+            }
+        },
+        watch: {
+            show(newVal) {
+                console.log('show', newVal)
+                this.dialogVisible = newVal
+            },
+            dialogVisible(newVal) {
+                newVal === false && this.$emit('close')
+            },
+            defaultData(newVal) {
+                console.log('newVal',newVal)
+              this.formmodel={...newVal}
+            }
+        }
+    }
+</script>
+
+<style scoped type="text/scss" >
+    /deep/ .el-input-group__append {
+        padding: 0 10px;
+    .el-color-picker {
+        display: table-cell;
+        padding: 0;
+        border: none;
+    }
+    .el-color-picker__trigger {
+        display: inline-table;
+    }
+    }
+    .color-preview {
+        width: 100%;
+        height: 32px;
+    }
+</style>

+ 166 - 0
src/views/custom-infoboard/templates/board-module-setting.vue

@@ -0,0 +1,166 @@
+<template>
+    <el-dialog
+            :visible.sync="dialogVisible"
+            :close-on-click-modal="false"
+            :close-on-press-escape="false"
+            append-to-body
+            width="805px">
+        <div slot="title" class="image-picker-title">模块设置</div>
+        <div class="image-picker-body">
+            <el-form :model="formmodel" label-width="100px">
+                <el-row :gutter="20">
+                    <el-col :span="12">
+                        <el-form-item label="上边框">
+                            <el-switch
+                                    v-model="formmodel.borderTopShow"
+                                    active-color="#13ce66"
+                                    >
+                            </el-switch>
+                        </el-form-item>
+                    </el-col>
+                    <el-col :span="12">
+                        <el-form-item label="右边框">
+                            <el-switch
+                                    v-model="formmodel.borderRightShow"
+                                    active-color="#13ce66"
+                                    >
+                            </el-switch>
+                        </el-form-item>
+                    </el-col>
+                    <el-col :span="12">
+                        <el-form-item label="下边框">
+                            <el-switch
+                                    v-model="formmodel.borderBottomShow"
+                                    active-color="#13ce66"
+                                    >
+                            </el-switch>
+                        </el-form-item>
+                    </el-col>
+
+                    <el-col :span="12">
+                        <el-form-item label="左边框">
+                            <el-switch
+                                    v-model="formmodel.borderLeftShow"
+                                    active-color="#13ce66"
+                                    >
+                            </el-switch>
+                        </el-form-item>
+                    </el-col>
+
+                    <el-col :span="12">
+                        <el-form-item label="边框颜色">
+                            <el-input placeholder="分割线颜色" v-model="formmodel.borderColor">
+                                <el-color-picker slot="append" v-model="formmodel.borderColor" size="mini"></el-color-picker>
+                            </el-input>
+
+                        </el-form-item>
+                    </el-col>
+
+                    <el-col :span="12">
+                        <el-form-item label="边框大小">
+                            <el-input placeholder="边框大小" v-model="formmodel.borderWidth" type="number">
+                                <template slot="append">px</template>
+                            </el-input>
+
+                        </el-form-item>
+                    </el-col>
+
+                    <el-col :span="12">
+                        <el-form-item label="模块高度">
+                            <el-input placeholder="模块高度" v-model="formmodel.blockHeight" type="number">
+                                <template slot="append">px</template>
+                            </el-input>
+
+                        </el-form-item>
+                    </el-col>
+
+                </el-row>
+            </el-form>
+        </div>
+        <div slot="footer" class="image-picker-footer">
+            <span>
+        <el-button @click="dialogVisible = false">取 消</el-button>
+      <el-button type="primary" @click="handleConfirm">确 定</el-button>
+      </span>
+        </div>
+    </el-dialog>
+</template>
+
+<script>
+    export default {
+        name: "board-module-setting",
+        props: {
+            /** 显示dialog */
+            show: {
+                type: Boolean,
+                default: false
+            },
+            /** 默认数据 */
+            defaultData: {
+                type: Object,
+                default: () => {
+                }
+            }
+        },
+        data() {
+            return {
+                dialogVisible: this.show,
+                color:'#ffffff',
+                formmodel:{...this.defaultData},
+                predefineColors: [
+                    '#ff4500',
+                    '#ff8c00',
+                    '#ffd700',
+                    '#90ee90',
+                    '#00ced1',
+                    '#1e90ff',
+                    '#c71585',
+                    'rgba(255, 69, 0, 0.68)',
+                    'rgb(255, 120, 0)',
+                    'hsv(51, 100, 98)',
+                    'hsva(120, 40, 94, 0.5)',
+                    'hsl(181, 100%, 37%)',
+                    'hsla(209, 100%, 56%, 0.73)',
+                    '#c7158577'
+                ]
+            }
+        },
+        methods: {
+            handleConfirm() {
+                this.$emit('confirm', this.formmodel)
+                this.$emit('close')
+            }
+        },
+        watch: {
+            show(newVal) {
+                console.log('show', newVal)
+                this.dialogVisible = newVal
+            },
+            dialogVisible(newVal) {
+                newVal === false && this.$emit('close')
+            },
+            defaultData(newVal) {
+                console.log('hl',newVal)
+                this.formmodel={...newVal}
+            }
+        }
+    }
+</script>
+
+<style scoped type="text/scss" >
+    /deep/ .el-input-group__append {
+        padding: 0 10px;
+        .el-color-picker {
+            display: table-cell;
+            padding: 0;
+            border: none;
+        }
+        .el-color-picker__trigger {
+            display: inline-table;
+        }
+    }
+    .color-preview {
+        width: 100%;
+        height: 32px;
+    }
+</style>

+ 9 - 0
src/views/custom-infoboard/templates/common/index.js

@@ -0,0 +1,9 @@
+import tpl_one_cloum from './tpl-one-cloum'
+import tpl_two_cloum from './tpl-two-cloum'
+import tpl_three_cloum from './tpl-three-colum'
+
+export default {
+    1: tpl_one_cloum,
+    2: tpl_two_cloum,
+    3: tpl_three_cloum
+}

文件差异内容过多而无法显示
+ 438 - 0
src/views/custom-infoboard/templates/common/tpl-one-cloum.vue


文件差异内容过多而无法显示
+ 466 - 0
src/views/custom-infoboard/templates/common/tpl-three-colum.vue


文件差异内容过多而无法显示
+ 451 - 0
src/views/custom-infoboard/templates/common/tpl-two-cloum.vue


+ 14 - 0
src/views/custom-infoboard/templates/index.js

@@ -0,0 +1,14 @@
+import common from './common'
+
+const templates = {
+    ...common
+}
+
+const templateArray = []
+Object.keys(common).forEach(key => {
+    if (common[key].dataTpl) templateArray.push(common[key].dataTpl)
+})
+
+
+export { templateArray }
+export default templates

文件差异内容过多而无法显示
+ 304 - 0
src/views/custom-infoboard/templates/layout-item.vue