This commit is contained in:
liuye
2022-06-28 09:15:10 +08:00
parent 6896dfd197
commit b9964d64b0
32 changed files with 1246 additions and 929 deletions

View File

@@ -44,14 +44,17 @@ export default {
methods: {
...mapMutations(['setToken']),
getToken(params) {
this.setToken([params.token_type, params.access_token].join(' '))
this.dialog = false
this.$message.success("登录成功,正在刷新页面...")
location.reload()
if (params.access_token) {
this.setToken([params.token_type, params.access_token].join(' '))
this.dialog = false
this.$message.success("登录成功,正在刷新页面...")
location.reload()
} else this.$message.error(params.msg || "登录失败!")
},
getUserInfo() {
this.$axios.post("/admin/user/detail-phone").then(res => {
if (res && res.data) {
if (res?.data) {
this.$store.commit("setUserInfo", res.data)
if (/^\/project\/xiushan/.test(location.pathname)) {
this.$store.commit("setFinanceUser")
@@ -60,7 +63,7 @@ export default {
})
},
handleLogin() {
this.$axios.delete("/auth/token/logout").then(() => {
this.$axios.delete("/auth/token/logout").finally(() => {
this.dialog = true
})
},

View File

@@ -9,10 +9,12 @@ import 'dvcp-ui/lib/styles/common.scss';
import 'dvcp-ui/lib/dvcp-ui.css';
import store from './store';
import dataV from '@jiaminghi/data-view';
import dvui from '../project/dvui/entries'
Vue.use(dataV);
Vue.use(ui);
Vue.use(vcUI);
Vue.use(dvui)
//富文本编辑器配置
Vue.config.productionTip = false;
Vue.prototype.$axios = axios;

View File

@@ -1,93 +0,0 @@
{
"name": "cw-webapps",
"version": "2.0.0",
"private": false,
"author": "kubbo",
"main": "lib/cw-webapps.common.js",
"scripts": {
"dev": "vue-cli-service serve",
"lib": "vue-cli-service build --no-clean --target lib --dest lib packages/index.js&&npm unpublish --force&&npm publish",
"lib:core": "vue-cli-service build --target lib --dest core/dist core/index.js --name dvcp-core&&npm unpublish dvcp-core --force&&npm publish core/",
"lib:project": "node project/build.js",
"lib:all": "node project/allProject.js&&npm unpublish --workspaces --force&&npm publish --workspaces",
"ui": "npm i dvcp-ui@latest dvcp-dv-ui@latest"
},
"workspaces": [
"project/*"
],
"dependencies": {
"@amap/amap-jsapi-loader": "^1.0.1",
"@jiaminghi/data-view": "^2.10.0",
"bin-code-editor": "^0.9.0",
"dayjs": "^1.8.35",
"dvcp-dv": "^1.0.0",
"dvcp-dv-ui": "file:project/dvui",
"dvcp-ui": "^1.42.2",
"echarts": "^5.1.2",
"mp4box": "^0.4.1",
"print-js": "^1.0.63",
"serialize-javascript": "^6.0.0",
"sortablejs": "^1.12.0",
"vue-draggable-resizable": "^2.3.0",
"vue-json-editor": "^1.4.3",
"vue-okr-tree": "^1.0.10",
"vue-ruler-tool": "^1.2.4",
"vuedraggable": "^2.24.3"
},
"publishConfig": {
"registry": "http://192.168.1.87:4873/"
},
"devDependencies": {
"@babel/plugin-proposal-logical-assignment-operators": "^7.10.4",
"@babel/plugin-proposal-nullish-coalescing-operator": "^7.10.4",
"@babel/plugin-proposal-optional-chaining": "^7.10.4",
"@vue/cli-plugin-babel": "^3.6.0",
"@vue/cli-plugin-eslint": "^3.6.0",
"@vue/cli-service": "^3.6.0",
"axios": "^0.19.2",
"babel-eslint": "^10.1.0",
"core-js": "^2.6.11",
"element-ui": "^2.13.2",
"eslint": "^5.16.0",
"eslint-plugin-vue": "^5.0.0",
"image-webpack-loader": "^6.0.0",
"inquirer": "^6.5.2",
"node-sass": "npm:sass@^1.43.4",
"readline": "^1.3.0",
"sass-loader": "^7.1.0",
"uglifyjs-webpack-plugin": "^2.2.0",
"v-viewer": "^1.6.4",
"vue": "^2.6.11",
"vue-router": "^3.3.4",
"vue-template-compiler": "^2.6.11",
"vuex": "^3.5.1",
"vuex-persistedstate": "^2.7.1"
},
"vetur": {
"attributes": "./attributes.json"
},
"eslintConfig": {
"root": true,
"env": {
"node": true
},
"extends": [
"plugin:vue/essential",
"eslint:recommended"
],
"rules": {},
"parserOptions": {
"parser": "babel-eslint"
}
},
"postcss": {
"plugins": {
"autoprefixer": {}
}
},
"browserslist": [
"> 1%",
"last 2 versions",
"not ie <= 8"
]
}

View File

@@ -1,38 +1,19 @@
<template>
<ai-list v-if="!isShowDetail">
<template slot="title">
<ai-title title="大屏列表" :isShowBottomBorder="false" :instance="instance"></ai-title>
</template>
<template slot="tabs">
<el-tabs v-model="currIndex">
<el-tab-pane v-for="(tab,i) in tabs" :key="i" :label="tab.label">
<component :urlPrefix="urlPrefix" :areaId="areaId" :ref="tab.name" v-if="currIndex == i" :is="tab.comp" @change="onChange" lazy :instance="instance" :dict="dict" :permissions="permissions" />
</el-tab-pane>
</el-tabs>
</template>
</ai-list>
<Add v-else-if="componentName === 'Add'" :urlPrefix="urlPrefix" :areaId="areaId" :params="params" :instance="instance" :dict="dict" :permissions="permissions" @change="onChange"></Add>
<SourceData v-else-if="componentName === 'SourceData'" :urlPrefix="urlPrefix" :params="params" :instance="instance" :dict="dict" :permissions="permissions" @change="onChange"></SourceData>
<section class="AppDesigner">
<component :is="currentPage" v-bind="$props"/>
</section>
</template>
<script>
import List from './components/List.vue'
import Add from './components/Add'
import SourceData from './components/SourceData'
import dvui from '../../../project/dvui/entries'
import Vue from "vue";
Vue.use(dvui)
export default {
name: 'AppDesigner' ,
label: '大屏设计',
components: {
List,
Add,
SourceData
},
import Preview from "./components/preview";
export default {
name: 'AppDesigner',
label: '大屏设计',
components: {Preview, List, Add, SourceData},
props: {
instance: Function,
dict: Object,
@@ -44,6 +25,12 @@ export default {
},
computed: {
currentPage() {
const {hash} = this.$route
return hash == "#sourceData" ? SourceData :
hash == "#add" ? Add :
hash == "#preview" ? Preview : List
},
tabs() {
return [
{label: '大屏列表', name: 'FormList', comp: List, permission: ''}
@@ -84,8 +71,6 @@ export default {
}
}
},
created() {
}
}
</script>

View File

@@ -1,8 +1,7 @@
<template>
<ai-detail>
<template slot="title">
<ai-title :title="id ? '编辑项目' : '添加项目'" isShowBack isShowBottomBorder @onBackClick="cancel(false)">
</ai-title>
<ai-title :title="id ? '编辑项目' : '添加项目'" isShowBack isShowBottomBorder @onBackClick="cancel"/>
</template>
<template slot="content">
<el-form ref="form" :model="form" label-width="110px" label-position="right">
@@ -33,14 +32,14 @@
</template>
<template #content>
<ai-table
:tableData="tableData"
:col-configs="colConfigs"
:total="total"
style="margin-top: 6px;"
:border="true"
row-key="id"
:isShowPagination="false"
@getList="() => {}">
:tableData="tableData"
:col-configs="colConfigs"
:total="total"
style="margin-top: 6px;"
:border="true"
row-key="id"
:isShowPagination="false"
@getList="() => {}">
<el-table-column slot="options" width="160px" fixed="right" label="操作" align="center">
<template slot-scope="{ row, column, $index }">
<div class="table-options">
@@ -55,23 +54,15 @@
</ai-card>
</el-form>
<Layout
v-if="isShowLayout"
:instance="instance"
:dict="dict"
:params="query"
@change="onChange"
:urlPrefix="urlPrefix"
:theme="config.theme"
@close="isShowLayout = false">
</Layout>
<ai-dv-wrapper :views="[{label: '返回'}]" :theme="config.theme" @change="screenId = false" v-if="screenId" :title="form.name">
<AiDvBackground
v-if="isShowLayout"
:instance="instance"
:dict="dict"
:params="query"
@change="onChange"
:urlPrefix="urlPrefix"
:theme="config.theme"
v-if="config.length || config.theme === '1'"
:src="config.theme === '1' ? 'https://cdn.cunwuyun.cn/dvcp/dv/img/dj-bg.png' : config.backgroundImage[0].url">
</AiDvBackground>
<AppGigscreenViewer :urlPrefix="urlPrefix" :instance="instance" :dict="dict" :id="screenId"></AppGigscreenViewer>
</ai-dv-wrapper>
@close="isShowLayout = false">
</Layout>
<ai-dialog :visible.sync="dialog" title="定制大屏" @closed="custom={}" @onConfirm="handleCustomizedDV">
<el-form ref="CustomDVFrom" size="small" :model="custom" :rules="rules" label-width="80px">
<el-form-item label="大屏标题" prop="title">
@@ -94,29 +85,21 @@
</template>
<script>
import AppGigscreenViewer from '../../viewer/AppGigscreenViewer'
import Layout from './Layout.vue'
import Sortable from 'sortablejs'
import AppGigscreenViewer from "../../viewer/AppGigscreenViewer";
export default {
name: 'Add',
props: {
instance: Function,
dict: Object,
params: Object,
urlPrefix: String
},
inject: {
home:{default: ''}
home: {default: ''}
},
components: {
Layout,
AppGigscreenViewer
},
components: {AppGigscreenViewer, Layout},
data() {
return {
info: {},
@@ -152,24 +135,18 @@ export default {
created() {
this.dict.load('customizedDVs')
if (this.params && this.params.id) {
this.id = this.params.id
this.getInfo(this.params.id)
}
this.getInfo()
},
mounted () {
},
methods: {
getInfo(id) {
getInfo() {
let {id} = this.$route.query
this.instance.post(`${this.urlPrefix}/appdiylargescreen/queryLargeScreenProjectDetailById?id=${id}`).then(res => {
if (res.code === 0) {
if (res?.data) {
this.form = {
...res.data
}
if (res.data.relationLsIds) {
this.tableData = res.data.lsList.map(v => {
let conf = JSON.parse(v.config || '') || {}
@@ -194,7 +171,7 @@ export default {
const tbody = document.querySelector('.el-table__body-wrapper tbody')
const _this = this
Sortable.create(tbody, {
onEnd({ newIndex, oldIndex }) {
onEnd({newIndex, oldIndex}) {
const currRow = _this.tableData.splice(oldIndex, 1)[0]
_this.tableData.splice(newIndex, 0, currRow)
}
@@ -202,14 +179,8 @@ export default {
},
toViewer(id) {
this.instance.post(`${this.urlPrefix}/appdiylargescreen/queryLargeScreenDetailById?id=${id}`).then(res => {
if (res.data) {
this.config = JSON.parse(res.data.config).dashboard
}
})
this.screenId = id
this.$router.push({query: {id}, hash: "#preview"})
},
onChange(e) {
const ids = this.tableData.map(v => v.id)
if (ids.indexOf(e.id) < 0) {
@@ -267,7 +238,7 @@ export default {
this.home && this.home.refreshDvOptions && this.home.refreshDvOptions()
setTimeout(() => {
this.cancel(true)
this.cancel()
}, 600)
}
})
@@ -275,11 +246,8 @@ export default {
})
},
cancel(isRefresh) {
this.$emit('change', {
type: 'list',
isRefresh: !!isRefresh
})
cancel() {
this.$router.push({})
},
handleCustomizedDV() {

View File

@@ -91,7 +91,7 @@
<div class="coordinate-top"></div>
<div class="coordinate-label">{{ item.left }}, {{ item.top }}</div>
</div>
<RenderElement :data="item" :theme="dashboard.theme" :index="index"></RenderElement>
<ai-dv-render :data="item" :theme="dashboard.theme" :index="index" :instance="instance" />
</vue-draggable-resizable>
</div>
</ai-dv-wrapper>
@@ -335,12 +335,12 @@
</ai-dialog>
<ai-dialog :visible.sync="isShowAddImg" width="580px" append-to-body title="添加素材" @closed="form.images = []" @onConfirm="onImageConfirm">
<ai-uploader
:instance="instance"
v-model="form.images"
fileType="file"
:maxSize="100"
url="/admin/file/add-unlimited"
:limit="9">
:instance="instance"
v-model="form.images"
fileType="file"
:maxSize="100"
url="/admin/file/add-unlimited"
:limit="9">
</ai-uploader>
</ai-dialog>
</div>
@@ -353,7 +353,6 @@ import VueRulerTool from 'vue-ruler-tool'
import VueDraggableResizable from 'vue-draggable-resizable'
import 'vue-draggable-resizable/dist/VueDraggableResizable.css'
import DataConfig from './form/DataConfig.vue'
import RenderElement from './RenderElement'
export default {
props: {
@@ -366,7 +365,7 @@ export default {
data() {
return {
colConfigs: [
{ prop: 'url', label: '图片链接', showOverflowTooltip: false },
{prop: 'url', label: '图片链接', showOverflowTooltip: false},
// {slot: 'img', label: '图片'}
],
form: {
@@ -416,7 +415,6 @@ export default {
},
components: {
RenderElement,
DataConfig,
VueRulerTool,
VueDraggableResizable,

View File

@@ -1,38 +1,39 @@
<template>
<ai-list class="form-list" isTabs style="width: 100%">
<ai-list>
<ai-title slot="title" title="大屏列表" isShowBottomBorder/>
<template slot="content">
<ai-search-bar>
<template #left>
<ai-select
v-model="search.status"
@change="search.current = 1, getList()"
placeholder="发布状态"
:selectList="dict.getDict('cwpStatus')">
v-model="search.status"
@change="search.current = 1, getList()"
placeholder="发布状态"
:selectList="dict.getDict('cwpStatus')">
</ai-select>
<el-button type="primary" @click="toEdit('')">添加大屏</el-button>
<el-button type="primary" @click="toAddData">数据源管理</el-button>
</template>
<template #right>
<el-input
v-model="search.name"
size="small"
placeholder="请输入模板名称或创建人"
clearable
v-throttle="() => {search.current = 1, getList()}"
@clear="search.current = 1, search.title = '', getList()"
suffix-icon="iconfont iconSearch">
v-model="search.name"
size="small"
placeholder="请输入模板名称或创建人"
clearable
v-throttle="() => {search.current = 1, getList()}"
@clear="search.current = 1, search.title = '', getList()"
suffix-icon="iconfont iconSearch">
</el-input>
</template>
</ai-search-bar>
<ai-table
:tableData="tableData"
:col-configs="colConfigs"
:total="total"
v-loading="loading"
style="margin-top: 6px;"
:current.sync="search.current"
:size.sync="search.size"
@getList="getList">
:tableData="tableData"
:col-configs="colConfigs"
:total="total"
v-loading="loading"
style="margin-top: 6px;"
:current.sync="search.current"
:size.sync="search.size"
@getList="getList">
<el-table-column slot="options" width="160px" fixed="right" label="操作" align="center">
<template slot-scope="{ row }">
<div class="table-options">
@@ -43,11 +44,11 @@
</el-table-column>
</ai-table>
<ai-dialog
:visible.sync="isShowAdd"
width="780px"
title="复制大屏"
@close="onClose"
@onConfirm="onConfirm">
:visible.sync="isShowAdd"
width="780px"
title="复制大屏"
@close="onClose"
@onConfirm="onConfirm">
<el-form ref="form" :model="form" label-width="110px" label-position="right">
<div class="ai-form" :model="form" label-width="110px" label-position="right">
<el-form-item label="名称" prop="name" style="width: 100%;" :rules="[{ required: true, message: '请输入名称', trigger: 'blur' }]">
@@ -61,118 +62,106 @@
</template>
<script>
export default {
name: 'FormList',
props: {
instance: Function,
dict: Object,
areaId: String,
urlPrefix: String
export default {
name: 'FormList',
props: {
instance: Function,
dict: Object,
areaId: String,
urlPrefix: String
},
data() {
return {
search: {
current: 1,
status: '',
size: 10,
name: ''
},
form: {
name: ''
},
id: '',
isShowAdd: false,
colConfigs: [
{prop: 'name', label: '模板名称'},
{prop: 'createUserName', align: 'center', label: '创建人'},
{prop: 'description', align: 'center', label: '描述'},
{prop: 'status', align: 'center', label: '状态', formart: v => this.dict.getLabel('cwpStatus', v)},
{prop: 'createTime', align: 'center', label: '创建时间'}
],
tableData: [],
total: 0,
loading: false
}
},
created() {
this.dict.load('cwpStatus').then(() => {
this.getList()
})
},
mounted() {
this.loading = true
},
methods: {
copy(id) {
this.id = id
this.isShowAdd = true
},
data () {
return {
search: {
current: 1,
status: '',
size: 10,
name: ''
},
form: {
name: ''
},
id: '',
isShowAdd: false,
colConfigs: [
{ prop: 'name', label: '模板名称' },
{ prop: 'createUserName', align: 'center', label: '创建人' },
{ prop: 'description', align: 'center', label: '描述' },
{ prop: 'status', align: 'center', label: '状态', formart: v => this.dict.getLabel('cwpStatus', v) },
{ prop: 'createTime', align: 'center', label: '创建时间' }
],
tableData: [],
total: 0,
loading: false
}
onClose() {
this.id = ''
this.form.name = ''
},
created () {
this.dict.load('cwpStatus').then(() => {
this.getList()
onConfirm() {
this.$refs.form.validate((valid) => {
if (valid) {
this.instance.post(`${this.urlPrefix}/appdiylargescreen/copyLargeScreenProject`, null, {
params: {
...this.form,
id: this.id
}
}).then(res => {
if (res.code === 0) {
this.$message.success('复制成功')
this.isShowAdd = false
this.getList()
}
})
}
})
},
mounted () {
this.loading = true
},
methods: {
copy (id) {
this.id = id
this.isShowAdd = true
},
onClose () {
this.id = ''
this.form.name = ''
},
onConfirm () {
this.$refs.form.validate((valid) => {
if (valid) {
this.instance.post(`${this.urlPrefix}/appdiylargescreen/copyLargeScreenProject`, null, {
params: {
...this.form,
id: this.id
}
}).then(res => {
if (res.code === 0) {
this.$message.success('复制成功')
this.isShowAdd = false
this.getList()
}
})
}
})
},
getList () {
this.instance.post(`${this.urlPrefix}/appdiylargescreen/allLargeScreenProjectByPage`, null, {
params: {
...this.search
}
}).then(res => {
if (res.code == 0) {
this.tableData = res.data.records
this.total = res.data.total
this.loading = false
} else {
this.loading = false
}
}).catch(() => {
getList() {
this.instance.post(`${this.urlPrefix}/appdiylargescreen/allLargeScreenProjectByPage`, null, {
params: {
...this.search
}
}).then(res => {
if (res.code == 0) {
this.tableData = res.data.records
this.total = res.data.total
this.loading = false
})
},
toEdit (id) {
this.$emit('change', {
type: 'add',
params: {
id: id || ''
}
})
},
toAddData () {
this.$emit('change', {
type: 'SourceData'
})
}
} else {
this.loading = false
}
}).catch(() => {
this.loading = false
})
},
toEdit(id) {
this.$router.push({hash: "#add", query: {id}})
},
toAddData() {
this.$router.push({hash: "#sourceData"})
}
}
}
</script>
<style scoped lang="scss">
</style>

View File

@@ -1,7 +1,7 @@
<template>
<ai-detail>
<template slot="title">
<ai-title title="数据源" isShowBack isShowBottomBorder @onBackClick="cancel(false)">
<ai-title title="数据源" isShowBack isShowBottomBorder @onBackClick="cancel">
</ai-title>
</template>
<template slot="content">
@@ -13,25 +13,25 @@
<ai-search-bar class="search-bar">
<template slot="right">
<el-input
v-model="search.name"
size="small"
v-throttle="() => {search.current = 1, getList()}"
placeholder="请输入名字"
clearable
@clear="search.current = 1, search.name = '', getList()"
suffix-icon="iconfont iconSearch">
v-model="search.name"
size="small"
v-throttle="() => {search.current = 1, getList()}"
placeholder="请输入名字"
clearable
@clear="search.current = 1, search.name = '', getList()"
suffix-icon="iconfont iconSearch">
</el-input>
</template>
</ai-search-bar>
<ai-table
:tableData="tableData"
:col-configs="colConfigs"
:total="total"
style="margin-top: 6px;"
:border="true"
:current.sync="search.current"
:size.sync="search.size"
@getList="getList">
:tableData="tableData"
:col-configs="colConfigs"
:total="total"
style="margin-top: 6px;"
:border="true"
:current.sync="search.current"
:size.sync="search.size"
@getList="getList">
<el-table-column slot="options" width="160px" fixed="right" label="操作" align="center">
<template slot-scope="{ row }">
<div class="table-options">
@@ -44,18 +44,18 @@
</template>
</ai-card>
<ai-dialog
:visible.sync="isShow"
width="920px"
title="数据源"
@close="onClose"
@onConfirm="onConfirm">
:visible.sync="isShow"
width="920px"
title="数据源"
@close="onClose"
@onConfirm="onConfirm">
<el-form ref="form" :model="form" label-width="110px" label-position="right">
<div class="ai-form">
<el-form-item label="数据源描述" style="width: 100%;" prop="description" :rules="[{ required: true, message: '请输入数据源描述', trigger: 'blur' }]">
<el-input
size="small"
placeholder="请输入数据源描述"
v-model="form.description">
size="small"
placeholder="请输入数据源描述"
v-model="form.description">
</el-input>
</el-form-item>
<el-form-item label="类型" style="width: 100%;" prop="dataRange" :rules="[{ required: true, message: '请选择数据范围', trigger: 'change' }]">
@@ -64,55 +64,61 @@
<el-radio label="1">SQL</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item v-if="form.type === '1'" label="sql语句" style="width: 100%;" prop="description" :rules="[{ required: true, message: '请输入sql语句', trigger: 'blur' }]">
<el-form-item v-if="form.type === '1'" label="sql语句" style="width: 100%;" prop="description"
:rules="[{ required: true, message: '请输入sql语句', trigger: 'blur' }]">
<el-input
size="small"
type="textarea"
placeholder="请输入数据源描述"
v-model="form.sqlContent">
:rows="8"
size="small"
type="textarea"
placeholder="请输入数据源描述"
v-model="form.sqlContent">
</el-input>
</el-form-item>
<el-form-item v-if="form.type === '0'" label="村微应用" style="width: 100%;" prop="appId" :rules="[{ required: true, message: '请选择村微应用', trigger: 'change' }]">
<el-form-item v-if="form.type === '0'" label="村微应用" style="width: 100%;" prop="appId"
:rules="[{ required: true, message: '请选择村微应用', trigger: 'change' }]">
<el-select size="small" style="width: 100%;" v-model="form.appId" placeholder="请选择村微应用" @change="onAppChange">
<el-option
v-for="item in appList"
:key="item.id"
:label="item.appName"
:value="item.id">
v-for="item in appList"
:key="item.id"
:label="item.appName"
:value="item.id">
</el-option>
</el-select>
</el-form-item>
<el-form-item v-if="form.type === '0'" label="数据范围" style="width: 100%;" prop="dataRange" :rules="[{ required: true, message: '请选择数据范围', trigger: 'change' }]">
<el-form-item v-if="form.type === '0'" label="数据范围" style="width: 100%;" prop="dataRange"
:rules="[{ required: true, message: '请选择数据范围', trigger: 'change' }]">
<el-radio-group v-model="form.dataRange">
<el-radio label="0">全部</el-radio>
<el-radio label="1">自定义条数</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label="数据条数" style="width: 100%;" v-if="form.dataRange === '1' && form.type === '0'" prop="count" :rules="[{ required: true, message: '请输入数据条数', trigger: 'blur' }]">
<el-form-item label="数据条数" style="width: 100%;" v-if="form.dataRange === '1' && form.type === '0'" prop="count"
:rules="[{ required: true, message: '请输入数据条数', trigger: 'blur' }]">
<el-input
size="small"
placeholder="请输入数据条数"
v-model="form.count">
size="small"
placeholder="请输入数据条数"
v-model="form.count">
</el-input>
</el-form-item>
<div v-if="form.type === '0'">
<el-form-item :label="'统计项' + index" style="width: 100%;" v-for="(item, index) in form.statisticsConfigs" :key="'statisticsConfigs' + index">
<div class="form-flex">
<div>
<el-select size="small" style="width: 160px;" v-model="item.fieldName" @change="e => onChooseField('statisticsConfigs', e, index)" placeholder="请选择" clearable>
<el-select size="small" style="width: 160px;" v-model="item.fieldName" @change="e => onChooseField('statisticsConfigs', e, index)"
placeholder="请选择" clearable>
<el-option
v-for="(item, index) in filedList"
:key="index"
:label="item.fieldCnName"
:value="item.fieldName">
v-for="(item, index) in filedList"
:key="index"
:label="item.fieldCnName"
:value="item.fieldName">
</el-option>
</el-select>
<el-select size="small" style="margin: 0 10px; width: 160px;" v-model="item.calcType" placeholder="请选择" clearable>
<el-option
v-for="item in dict.getDict('diyLargeScreenDatasourceCalcType2')"
:key="item.id"
:label="item.dictName"
:value="item.dictValue">
v-for="item in dict.getDict('diyLargeScreenDatasourceCalcType2')"
:key="item.id"
:label="item.dictName"
:value="item.dictValue">
</el-option>
</el-select>
<el-input size="small" style="width: 165px;" placeholder="请输入别名" v-model="item.alias"></el-input>
@@ -130,10 +136,10 @@
<div>
<el-select size="small" style="width: 160px;" v-model="item.fieldName" placeholder="请选择" clearable>
<el-option
v-for="item in filedList"
:key="item.id"
:label="item.fieldCnName"
:value="item.fieldName">
v-for="item in filedList"
:key="item.id"
:label="item.fieldCnName"
:value="item.fieldName">
</el-option>
</el-select>
</div>
@@ -150,18 +156,18 @@
<div>
<el-select size="small" style="width: 160px;" v-model="item.fieldName" placeholder="请选择" clearable>
<el-option
v-for="item in filedList"
:key="item.id"
:label="item.fieldCnName"
:value="item.fieldName">
v-for="item in filedList"
:key="item.id"
:label="item.fieldCnName"
:value="item.fieldName">
</el-option>
</el-select>
<el-select size="small" style="width: 160px; margin-left: 10px;" v-model="item.orderType" placeholder="请选择" clearable>
<el-option
v-for="item in orderTypeDict"
:key="item.id"
:label="item.label"
:value="item.value">
v-for="item in orderTypeDict"
:key="item.id"
:label="item.label"
:value="item.value">
</el-option>
</el-select>
</div>
@@ -180,277 +186,274 @@
</template>
<script>
export default {
name: 'SourceData',
export default {
name: 'SourceData',
props: {
instance: Function,
dict: Object,
params: Object,
urlPrefix: String
},
props: {
instance: Function,
dict: Object,
params: Object,
urlPrefix: String
},
data () {
return {
isShow: false,
search: {
current: 1,
size: 10,
name: ''
data() {
return {
isShow: false,
search: {
current: 1,
size: 10,
name: ''
},
total: 0,
colConfigs: [
{prop: 'appName', label: '应用名'},
{prop: 'appTableName', align: 'center', label: '表名'},
{prop: 'description', align: 'center', label: '描述'},
{prop: 'type', align: 'center', label: '类型', formart: v => v === '0' ? '村微应用' : 'sql语句'},
{prop: 'createUserName', align: 'center', label: '创建人'},
{prop: 'createTime', align: 'center', label: '创建时间'}
],
tableData: [],
filedList: [],
appList: [],
form: {
orderType: 'asc',
dataRange: '0',
type: '0',
sqlContent: '',
appId: '',
description: '',
appName: '',
appTableName: '',
count: '100',
statisticsConfigs: [{
alias: '',
calcType: '',
dictCode: '',
fieldCnName: '',
fieldName: ''
}],
orderConfigs: [{
alias: '',
calcType: '',
dictCode: '',
fieldCnName: '',
fieldName: ''
}],
groupConfigs: [{
alias: '',
calcType: '',
dictCode: '',
fieldCnName: '',
fieldName: ''
}]
},
id: '',
orderTypeDict: [
{
value: 'asc',
label: '升序'
},
total: 0,
colConfigs: [
{ prop: 'appName', label: '应用名' },
{ prop: 'appTableName', align: 'center', label: '表名' },
{ prop: 'description', align: 'center', label: '描述' },
{ prop: 'type', align: 'center', label: '类型', formart: v => v === '0' ? '村微应用' : 'sql语句' },
{ prop: 'createUserName', align: 'center', label: '创建人' },
{ prop: 'createTime', align: 'center', label: '创建时间' }
],
tableData: [],
filedList: [],
appList: [],
form: {
orderType: 'asc',
dataRange: '0',
type: '0',
sqlContent: '',
appId: '',
description: '',
appName: '',
appTableName: '',
count: '100',
statisticsConfigs: [{
alias: '',
calcType: '',
dictCode: '',
fieldCnName: '',
fieldName: ''
}],
orderConfigs: [{
alias: '',
calcType: '',
dictCode: '',
fieldCnName: '',
fieldName: ''
}],
groupConfigs: [{
alias: '',
calcType: '',
dictCode: '',
fieldCnName: '',
fieldName: ''
}]
},
id: '',
orderTypeDict: [
{
value: 'asc',
label: '升序'
},
{
value: 'desc',
label: '降序'
{
value: 'desc',
label: '降序'
}
]
}
},
created() {
this.dict.load(['diyLargeScreenDatasourceCalcType2']).then(() => {
this.getList()
this.getAppList()
})
},
methods: {
getInfo(id) {
this.instance.post(`${this.urlPrefix}/wxcp/wxuser/queryDetailById?id=${id}`).then(res => {
if (res.code === 0) {
this.form = {
...res.data
}
]
}
},
created () {
this.dict.load(['diyLargeScreenDatasourceCalcType2']).then(() => {
this.getList()
this.getAppList()
}
})
},
methods: {
getInfo (id) {
this.instance.post(`${this.urlPrefix}/wxcp/wxuser/queryDetailById?id=${id}`).then(res => {
if (res.code === 0) {
this.form = {
...res.data
}
onChooseField(type, fieldName, index) {
const dictCode = this.filedList.filter(v => v.fieldName === fieldName)[0].dictCode
this.$set(this.form[type][index], 'dictCode', dictCode)
},
add(type) {
this.form[type].push({
alias: '',
calcType: '',
dictCode: '',
fieldCnName: '',
fieldName: ''
})
},
removeConfig(type, index) {
this.form[type].splice(index, 1)
},
toEdit(e) {
this.id = e.id
this.instance.post(`${this.urlPrefix}/appdiylargescreen/queryDatasourceDetailById?id=${e.id}`).then(res => {
if (res.code === 0) {
this.form = {
...res.data
}
})
},
onChooseField (type, fieldName, index) {
const dictCode = this.filedList.filter(v => v.fieldName === fieldName)[0].dictCode
this.$set(this.form[type][index], 'dictCode', dictCode)
},
add (type) {
this.form[type].push({
alias: '',
calcType: '',
dictCode: '',
fieldCnName: '',
fieldName: ''
})
},
removeConfig (type, index) {
this.form[type].splice(index, 1)
},
toEdit (e) {
this.id = e.id
this.instance.post(`${this.urlPrefix}/appdiylargescreen/queryDatasourceDetailById?id=${e.id}`).then(res => {
if (res.code === 0) {
this.form = {
...res.data
}
this.form.dataRange = this.form.dataRange === '0' ? '0' : '1'
this.form.count = res.data.dataRange
this.filedList = this.appList.filter(v => v.id === res.data.appId).length && this.appList.filter(v => v.id === res.data.appId)[0].fields.map(item => {
let value = []
res.data.configs.forEach(v => {
if (v.fieldName === item.fieldName) {
value.push(v.calcType)
}
})
return {
...item,
value
this.form.dataRange = this.form.dataRange === '0' ? '0' : '1'
this.form.count = res.data.dataRange
this.filedList = this.appList.filter(v => v.id === res.data.appId).length && this.appList.filter(v => v.id === res.data.appId)[0].fields.map(item => {
let value = []
res.data.configs.forEach(v => {
if (v.fieldName === item.fieldName) {
value.push(v.calcType)
}
})
this.isShow = true
return {
...item,
value
}
})
this.isShow = true
}
})
},
remove(id) {
this.$confirm('确定删除该数据?').then(() => {
this.instance.post(`${this.urlPrefix}/appquestionnairetemplate/delete?id=${id}`).then(res => {
if (res.code == 0) {
this.$message.success('删除成功!')
this.getList()
}
})
},
})
},
getList() {
this.instance.post(`${this.urlPrefix}/appdiylargescreen/allDatasourceByPage`, null, {
params: {
...this.search
}
}).then(res => {
if (res.code == 0) {
this.tableData = res.data.records
this.total = res.data.total
}
})
},
getAppList() {
this.instance.post(`${this.urlPrefix}/appdiylargescreen/allDatasourceApp`).then(res => {
if (res.code === 0) {
this.appList = res.data
}
})
},
onClose() {
this.id = ''
this.form.orderType = 'asc'
this.form.dataRange = 0
this.form.appId = ''
this.form.description = ''
this.form.appName = ''
this.form.appTableName = ''
this.form.count = 100
},
onAppChange(e) {
const value = this.appList.filter(v => v.id === e)[0]
this.form.appTableName = value.appTableName
this.form.appName = value.appName
this.form.statisticsConfigs = [{
alias: '',
calcType: '',
dictCode: '',
fieldCnName: '',
fieldName: ''
}]
this.form.orderConfigs = [{
alias: '',
calcType: '',
dictCode: '',
fieldCnName: '',
fieldName: ''
}]
this.form.groupConfigs = [{
alias: '',
calcType: '',
dictCode: '',
fieldCnName: '',
fieldName: ''
}]
this.filedList = value.fields.map(v => {
return {
...v,
value: ''
}
})
},
onConfirm() {
this.$refs.form.validate((valid) => {
if (valid) {
let configs = []
if (this.filedList.length) {
this.filedList.forEach(item => {
if (item.value.length) {
item.value.forEach(v => {
configs.push({
alias: item.fieldCnName,
calcType: v,
fieldCnName: item.fieldCnName,
fieldName: item.fieldName,
dictCode: item.dictCode,
orderType: this.orderType
})
})
}
})
}
this.instance.post(`${this.urlPrefix}/appdiylargescreen/addOrUpdateDatasource`, {
...this.form,
configs,
id: this.id ? this.id : '',
dataRange: this.form.dataRange === '0' ? 0 : this.form.count
}).then(res => {
if (res.code === 0) {
this.$message.success(this.id ? '编辑成功' : '添加成功')
this.search.current = 1
this.isShow = false
remove (id) {
this.$confirm('确定删除该数据?').then(() => {
this.instance.post(`${this.urlPrefix}/appquestionnairetemplate/delete?id=${id}`).then(res => {
if (res.code == 0) {
this.$message.success('删除成功!')
this.getList()
}
})
})
},
}
})
},
getList () {
this.instance.post(`${this.urlPrefix}/appdiylargescreen/allDatasourceByPage`, null, {
params: {
...this.search
}
}).then(res => {
if (res.code == 0) {
this.tableData = res.data.records
this.total = res.data.total
}
})
},
getAppList () {
this.instance.post(`${this.urlPrefix}/appdiylargescreen/allDatasourceApp`).then(res => {
if (res.code === 0) {
this.appList = res.data
}
})
},
onClose () {
this.id = ''
this.form.orderType = 'asc'
this.form.dataRange = 0
this.form.appId = ''
this.form.description = ''
this.form.appName = ''
this.form.appTableName = ''
this.form.count = 100
},
onAppChange (e) {
const value = this.appList.filter(v => v.id === e)[0]
this.form.appTableName = value.appTableName
this.form.appName = value.appName
this.form.statisticsConfigs = [{
alias: '',
calcType: '',
dictCode: '',
fieldCnName: '',
fieldName: ''
}]
this.form.orderConfigs = [{
alias: '',
calcType: '',
dictCode: '',
fieldCnName: '',
fieldName: ''
}]
this.form.groupConfigs = [{
alias: '',
calcType: '',
dictCode: '',
fieldCnName: '',
fieldName: ''
}]
this.filedList = value.fields.map(v => {
return {
...v,
value: ''
}
})
},
onConfirm () {
this.$refs.form.validate((valid) => {
if (valid) {
let configs = []
if (this.filedList.length) {
this.filedList.forEach(item => {
if (item.value.length) {
item.value.forEach(v => {
configs.push({
alias: item.fieldCnName,
calcType: v,
fieldCnName: item.fieldCnName,
fieldName: item.fieldName,
dictCode: item.dictCode,
orderType: this.orderType
})
})
}
})
}
this.instance.post(`${this.urlPrefix}/appdiylargescreen/addOrUpdateDatasource`, {
...this.form,
configs,
id: this.id ? this.id : '',
dataRange: this.form.dataRange === '0' ? 0 : this.form.count
}).then(res => {
if (res.code === 0) {
this.$message.success(this.id ? '编辑成功' : '添加成功')
this.search.current = 1
this.isShow = false
this.getList()
}
})
}
})
},
cancel (isRefresh) {
this.$emit('change', {
type: 'list',
isRefresh: !!isRefresh
})
}
cancel() {
this.$router.push({})
}
}
}
</script>
<style scoped lang="scss">
.form-flex {
display: flex;
justify-content: space-between;
align-items: center;
}
.form-flex {
display: flex;
justify-content: space-between;
align-items: center;
}
</style>

View File

@@ -29,7 +29,7 @@
<div class="layout-config__code" v-if="options.dataType === 'staticData'">
<el-button @click="showEditor" class="layout-config__code--btn" title="编辑" type="text" icon="iconfont iconjdq_led_edit"></el-button>
<vue-json-editor
:value="options.staticData"
:value="options.staticData"
:show-btns="false"
mode="view"
lang="zh">
@@ -206,7 +206,7 @@
this.options.src = JSON.parse(res.data).url
}
})
},
},
getDataList () {
this.instance.post(`${this.urlPrefix}/appdiylargescreen/allDatasourceByPage`, null, {
@@ -227,7 +227,7 @@
this.instance.post(this.options.api).then(res => {
if (res.code == 0) {
if (res.data.length) {
if (this.options.type === 'table') {
if (this.options.type === 'table') {
const keys = Object.keys(res.data[0])
const list = res.data
this.options.apiData = keys.map(v => {
@@ -259,6 +259,8 @@
this.keys = Object.keys(res.data[0])
}
}
} else {
this.options.dynamicData = []
}
})
},
@@ -312,6 +314,8 @@
this.list = res.data
this.keys = Object.keys(res.data[0])
}
} else {
this.options.dynamicData = []
}
}
})

View File

@@ -0,0 +1,58 @@
<template>
<section class="preview">
<ai-dv-wrapper :views="[{label: '返回'}]" :theme="config.theme" @change="$router.back()" v-if="screenId" :title="info.name">
<ai-dv-background
:theme="config.theme"
v-if="config.length || config.theme === '1'"
:src="config.theme === '1' ? 'https://cdn.cunwuyun.cn/dvcp/dv/img/dj-bg.png' : config.backgroundImage[0].url">
</ai-dv-background>
<app-gigscreen-viewer :urlPrefix="urlPrefix" :instance="instance" :dict="dict" :id="screenId"/>
</ai-dv-wrapper>
</section>
</template>
<script>
import AppGigscreenViewer from "../../viewer/AppGigscreenViewer";
export default {
name: "preview",
components: {AppGigscreenViewer},
props: {
instance: Function,
dict: Object,
permissions: Function,
urlPrefix: {
type: String,
default: '/app'
}
},
computed: {
screenId: v => v.$route.query.id
},
data() {
return {
info: {},
config: {}
}
},
methods: {
getDvData() {
let {id} = this.$route.query
this.instance.post(`${this.urlPrefix}/appdiylargescreen/queryLargeScreenDetailById?id=${id}`).then(res => {
if (res?.data) {
this.info = res.data
this.config = JSON.parse(res.data.config).dashboard
}
})
}
},
created() {
this.getDvData()
}
}
</script>
<style lang="scss" scoped>
.preview {
}
</style>

View File

@@ -537,7 +537,10 @@ const components = [
{
content: '中卫慧通',
lng: 117.1339399,
lat: 36.7190487
lat: 36.7190487,
地区: '中卫慧通',
经度: 117.1339399,
纬度: 36.7190487
}
],
api: '',
@@ -613,11 +616,11 @@ const components = [
dataType: 'staticData',
staticData: [
{
key: '个人服务办理',
label: '个人服务办理',
value: 247
},
{
key: '同比上月',
label: '同比上月',
value: 247
}
]

View File

@@ -1,5 +1,5 @@
<template>
<div class="AppGigscreenViewer">
<section class="AppGigscreenViewer">
<div v-if="!component">
<div
class="component-item"
@@ -14,21 +14,18 @@
}"
v-for="(item, index) in componentList"
:key="index">
<RenderElement :instance="instance" :data="item" :index="index" :theme="dashboard.theme"></RenderElement>
<ai-dv-render :instance="instance" :data="item" :index="index" :theme="dashboard.theme"/>
</div>
</div>
<components v-else :is="component" :dict="dict" :instance="instance" :nav="meta"/>
</div>
</section>
</template>
<script>
import RenderElement from '../designer/components/RenderElement'
export default {
name: 'AppGigscreenViewer',
label: '大屏预览',
props: {
instance: Function,
dict: Object,
@@ -38,17 +35,11 @@ export default {
default: '/app'
}
},
watch: {
id(v) {
this.getInfo(v)
}
},
components: {
RenderElement
},
data() {
return {
component: '',
@@ -65,32 +56,25 @@ export default {
meta: {}
}
},
created() {
this.getInfo(this.id)
// this.scale = document.body.clientWidth / 1920
},
mounted() {
this.$nextTick(() => {
let content = document.querySelector('#dv-full-screen-container')
if (content) {
const transform = content.style.transform
const scale = transform.replace('scale', '').replace('(', '').replace(')', '')
if (scale == 1) {
this.scale = document.body.clientWidth / 1920
}
}
})
},
methods: {
getInfo(id) {
this.component = null
this.instance.post(`${this.urlPrefix}/appdiylargescreen/queryLargeScreenDetailById?id=${id}`).then(res => {
id && this.instance.post(`${this.urlPrefix}/appdiylargescreen/queryLargeScreenDetailById?id=${id}`).then(res => {
if (res?.data) {
const config = JSON.parse(res.data.config)
if (config.custom) {
@@ -123,7 +107,6 @@ export default {
}
})
},
getSourceData(item, index) {
const api = item.dataType === 'apiData' ? item.api : `${this.urlPrefix}/appdiylargescreen/statisticsByLsid?id=${item.sourceDataId}`
this.instance.post(api).then(res => {
@@ -174,9 +157,13 @@ export default {
...obj
})
})
} else dynamicData = res.data
} else {
dynamicData = res.data
}
}
this.$set(this.componentList[index], item.dataType, dynamicData)
} else {
this.$set(this.componentList[index], item.dataType, [])
}
}
})

View File

@@ -41,7 +41,7 @@
</template>
</ai-search-bar>
<ai-table :tableData="tableData" :col-configs="colConfigs" :total="page.total" border :dict="dict" :current.sync="page.current"
:size.sync="page.size" @getDetail="getDetail"/>
:size.sync="page.size" @getList="getDetail"/>
</template>
</ai-card>
</template>

View File

@@ -4,18 +4,15 @@
<ai-title slot="title" title="广播设备管理" isShowBottomBorder/>
<template #content>
<ai-search-bar bottomBorder>
<template slot="left">
<el-button type="primary" icon="iconfont iconResetting" @click="update" :loading="btnLoading">更新数据</el-button>
</template>
<template slot="right">
<el-input v-model="search.name" size="small" placeholder="设备名称/设备编号" clearable
v-throttle="() => {page.current = 1, getList()}"
@clear=";(page.current = 1), (search.name = ''), getList()" suffix-icon="iconfont iconSearch"/>
</template>
</ai-search-bar>
<ai-search-bar class="ai-search-ba mar-t10">
<template slot="left">
<!-- <el-button icon="iconfont" type="primary" size="small">数据同步</el-button> -->
<!-- <el-button icon="iconfont iconDelete" size="small" @click="removeAll" :disabled="ids.length == 0">删除 </el-button> -->
</template>
</ai-search-bar>
<ai-table :tableData="tableData" :col-configs="colConfigs" :total="total" ref="aitableex"
:current.sync="page.current" :size.sync="page.size" @getList="getList"
@selection-change="(v) => (ids = v.map((e) => e.id))">
@@ -114,6 +111,7 @@ export default {
areaId: '',
bindVisible: false,
changeInfo: {},
btnLoading: false,
locate: false
}
},
@@ -198,6 +196,22 @@ export default {
},
})
},
update () {
this.btnLoading = true
this.instance.post(`/app/appdlbquipment/sync`, null, {
timeout: 1000000
}).then(res => {
if (res.code == 0) {
this.$message.success('更新成功')
this.getList()
}
this.btnLoading = false
}).catch(() => {
this.btnLoading = false
})
},
},
}
</script>

View File

@@ -1,6 +1,6 @@
<template>
<section class="AppISManage">
<device-slider :permissions="permissions" :show.sync="slider" :ins="instance" :dict="dict" @treeCommand="handleSliderOption" @select="handleSelectMonitor" :render-item="renderTreeItem" ref="DeviceSlider" />
<device-slider :permissions="permissions" :show.sync="slider" :instance="instance" :dict="dict" @treeCommand="handleSliderOption" @select="handleSelectMonitor" :render-item="renderTreeItem" ref="DeviceSlider" />
<div class="monitorPane" v-loading="isLoading" element-loading-background="rgba(0, 0, 0, 0.6)">
<div class="headerBar">
<el-select default-first-option size="small" v-model="splitScreen" @change="onChange">
@@ -54,8 +54,7 @@
splitOps() {
return [
{ label: '单分屏', value: 1, per: '100%' },
{ label: '四分屏', value: 4, per: '49.2%' },
{ label: '九分屏', value: 9, per: '32%' },
{ label: '四分屏', value: 4, per: '49.2%' }
]
},
currentSplitStyle() {

View File

@@ -1,6 +1,6 @@
<template>
<section class="AppISMap">
<device-slider :show.sync="slider" :ins="instance" :dict="dict" @list="v=>list=v" @select="markerClickEvent"/>
<device-slider :show.sync="slider" :instance="instance" :dict="dict" @list="v=>list=v" @select="markerClickEvent"/>
<div id="amap"/>
<div ref="selectedInfoWin" class="selected">
<b>{{ selected.deviceName }}</b>

View File

@@ -22,7 +22,10 @@
prefix-icon="el-icon-search"
@clear="search.name = '', handleTreeFilter()" clearable/>
</div>
<div title>设备列表</div>
<div title>
<div>设备列表</div>
<el-button type="text" icon="iconfont iconResetting" @click="updateDev" size="mini" :loading="btnLoading">刷新</el-button>
</div>
<div fill class="deviceList">
<el-tree ref="deviceTree" highlight-current :render-content="renderItem" :data="treeData" :props="propsConfig"
@node-click="handleNodeClick" @node-contextmenu="nodeContextmenu"
@@ -48,10 +51,10 @@ export default {
name: "deviceSlider",
props: {
show: Boolean,
ins: Function,
instance: Function,
dict: Object,
permissions: Function,
renderItem: Function
renderItem: Function,
},
computed: {
overview() {
@@ -98,7 +101,8 @@ export default {
x: '',
y: '',
node: {}
}
},
btnLoading: false,
}
},
methods: {
@@ -110,8 +114,10 @@ export default {
this.isShowMenu = false
},
getDevices() {
this.ins.post("/app/appzyvideoequipment/tree", null, {
params: {size: 999}
this.instance.post(`/app/appzyvideoequipment/tree`, null, {
params: {
size: 999
}
}).then(res => {
if (res?.data) {
this.staData = res.data.count
@@ -122,6 +128,21 @@ export default {
})
},
updateDev() {
this.btnLoading = true
this.instance.post(`/app/appzyvideoequipment/sync`, null, {
timeout: 1000000
}).then(res => {
if (res.code == 0) {
this.$message.success('更新成功')
this.getDevices()
}
this.btnLoading = false
}).catch(() => {
this.btnLoading = false
})
},
handleTreeCommand(e, node) {
this.$emit('treeCommand', {
type: e,
@@ -154,14 +175,16 @@ export default {
handleTreeFilter() {
this.$refs.deviceTree?.filter(this.search.name)
},
onChange() {
this.$refs.deviceTree?.filter(this.search.name)
}
},
},
created() {
this.dict.load("deviceStatus")
this.getDevices()
this.$dict.load("deviceStatus").then(()=>{
this.getDevices()
})
},
mounted() {
@@ -247,6 +270,18 @@ export default {
background: #3E4A69;
padding: 0 16px;
line-height: 28px;
display: flex;
justify-content: space-between;
align-items: center;
::v-deep .el-button {
padding: 0 4px;
height: 28px;
background: #3E4A69;
}
::v-deep .el-button:hover {
border: none;
}
}
::v-deep.deviceList {

View File

@@ -57,8 +57,8 @@ export default {
<style lang="scss" scoped>
.communityOverview {
max-width: 400px;
max-height: 700px;
overflow-y: auto;
max-height: 600px;
overflow-y: auto!important;
.units {
display: flex;

View File

@@ -57,8 +57,8 @@ export default {
<style lang="scss" scoped>
.communityOverview {
max-width: 400px;
max-height: 700px;
overflow-y: auto;
max-height: 600px;
overflow-y: auto!important;
.units {
display: flex;

View File

@@ -5,6 +5,7 @@
* @param params showList:打印加载的应用;apps:加载的应用文件名数组
*/
import core from './core.import'
import dvui from '../project/dvui/entries'
const install = function (Vue, params) {
if (install.installed) return
@@ -31,6 +32,7 @@ const install = function (Vue, params) {
apps.push(app.component)
Vue.component(app.name, app.component)
})
Vue.use(dvui)
return Promise.resolve(apps)
}

View File

@@ -95,9 +95,11 @@
})
},
remove(id) {
remove(ids) {
this.$confirm('确定删除该数据?').then(() => {
this.instance.post(`/app/appjob/delete?id=${id}`).then(res => {
this.instance.post(`/app/appjob/delete`,null,{
params:{ids}
}).then(res => {
if (res.code == 0) {
this.$message.success('删除成功!')
this.getList()

View File

@@ -45,7 +45,7 @@
</div>
</div>
<ai-wechat-selecter slot="append" :instance="instance" :props="{id:'wxUserId',label:'name'}"
v-model="item.candidateList" v-if="item.candidateApproverType==1">
v-model="item.candidateList" v-if="item.candidateApproverType==1">
<el-button size="mini" type="primary">选择指定人员</el-button>
</ai-wechat-selecter>
</div>
@@ -53,8 +53,8 @@
</el-steps>
</template>
</ai-card>
<el-dialog :title="titleType" class="editStyle" :visible.sync="isAddStep" width="575px" height="380px"
:close-on-click-modal="false">
<ai-dialog :title="titleType" class="editStyle" :visible.sync="isAddStep" width="575px" height="380px"
:close-on-click-modal="false" @onConfirm="saveAddProgress('addForm')">
<el-form :model="nodeObj" label-width="120px" ref="addForm" :rules="addRules">
<el-form-item label="审批步骤名称:" prop="nodeName">
<el-input size="small" v-model="nodeObj.nodeName" placeholder="如部门主管审批限10个字" :maxLength="10"
@@ -87,12 +87,7 @@
</el-radio-group>
</el-form-item>
</el-form>
<div slot="footer" style="text-align: center;">
<el-button style="width: 92px;" size="small" @click="isAddStep = false">取消</el-button>
<el-button style="width: 92px;" size="small" type="primary" @click="saveAddProgress('addForm')">确认
</el-button>
</div>
</el-dialog>
</ai-dialog>
</div>
</template>
@@ -175,7 +170,6 @@ export default {
this.titleType = '编辑审批步骤';
item.nodeType = item.nodeType * 1;
item.candidateApproverType = item.candidateApproverType * 1;
item.scopeCandidates = item.scopeCandidates * 1;
this.nodeObj = JSON.parse(JSON.stringify(item));
} else {
this.titleType = '添加审批步骤';
@@ -188,7 +182,7 @@ export default {
saveAddProgress(formName) {
this.$refs[formName].validate((valid) => {
if (valid) {
if (this.nodeObj.scopeCandidates == 0) this.nodeObj.candidateList = [];
if (this.nodeObj.scopeCandidates == '0') this.nodeObj.candidateList = [];
if (this.indexType == 1) {
this.form.processNodeList.push(JSON.parse(JSON.stringify(this.nodeObj)));
} else {
@@ -206,7 +200,7 @@ export default {
nodeIndex: '',
nodeName: '',
nodeType: '',
scopeCandidates: ''
scopeCandidates: '1'
};
this.$refs['addForm'].resetFields();
},

View File

@@ -0,0 +1,50 @@
<template>
<section class="AppMassNotification">
<keep-alive :include="['List']">
<component ref="component" :is="currentPage" :instance="instance" :params="params" :dict="dict" @change="onChange"/>
</keep-alive>
</section>
</template>
<script>
import List from "./components/List.vue";
import Add from "./components/Add.vue";
export default {
name: "AppMassNotification",
label: "群发通知",
props: {
instance: Function,
dict: Object,
},
components: {Add, List},
data() {
return {
component: "List",
params: {},
include: [],
}
},
computed: {
currentPage() {
const {hash} = this.$route
return hash == "#add" ? Add : List
},
},
methods: {
onChange(data) {
if (data.type === "Add") {
this.$router.push({hash: "#add", query: data.params})
} else {
this.$router.push({})
}
},
},
}
</script>
<style lang="scss" scoped>
.AppMassNotification {
height: 100%;
}
</style>

View File

@@ -0,0 +1,422 @@
<template>
<section class="Add">
<ai-detail v-if="!$route.query.id">
<template slot="title">
<ai-title title="群发通知" isShowBack isShowBottomBorder @onBackClick="cancel(false)"></ai-title>
</template>
<template slot="content">
<ai-card>
<template #title>
<div class="ai-card__title">
<h2>发送条件</h2>
</div>
</template>
<template #content>
<el-form size="small" class="ai-form" :rules="rules" ref="form" :model="form" label-width="100px" label-position="right">
<el-form-item label="发送方式" prop="messageSource" style="width: 50%">
<el-radio-group v-model="form.messageSource" @change="sourceChange" >
<el-radio label="2">居民群</el-radio>
<el-radio label="1">居民</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label="地区选择" style="width: 100%">
<ai-area-get v-model="areaId" :root="areaRootId" :instance="instance" @select="handleAreaSelect" multiple size="small" placeholder="请选择"/>
</el-form-item>
<el-form-item label="发送范围" prop="deptList" style="width: 100%">
<select-dept-user v-model="form.deptList" v-bind="$props" :source="form.messageSource"/>
</el-form-item>
</el-form>
</template>
</ai-card>
<ai-card title="群发消息设置">
<template #content>
<el-form class="ai-form" ref="form" :rules="rules" :model="form" label-width="110px" label-position="right">
<el-form-item class="el-form-item__textarea" label="群发内容" prop="content" style="width: 100%">
<el-input type="textarea" placeholder="请输入…" v-model="form.content" maxlength="1000" :rows="5" show-word-limit></el-input>
</el-form-item>
<!-- 图片 -->
<el-form-item label="图片" style="width: 100%">
<ai-uploader :instance="instance" isWechat v-model="imgList" multiple acceptType=".jpg,.png,.jpeg" :limit="9"
url="/app/wxcp/upload/uploadFile?type=image"></ai-uploader>
</el-form-item>
<!-- 视频 -->
<el-form-item label="视频" style="width: 100%">
<ai-uploader :instance="instance" fileType="file" isWechat multiple acceptType=".mp4" v-model="videoList" :limit="9"
url="/app/wxcp/upload/uploadFile?type=video"></ai-uploader>
</el-form-item>
<!-- 附件 -->
<el-form-item label="附件" style="width: 100%">
<ai-uploader :instance="instance" fileType="file" isWechat multiple v-model="filesList" :limit="9"
url="/app/wxcp/upload/uploadFile?type=file"></ai-uploader>
</el-form-item>
</el-form>
</template>
</ai-card>
</template>
<template #footer>
<el-button @click="cancel">取消</el-button>
<el-button type="primary" @click="confirm">确认发送</el-button>
</template>
</ai-detail>
<ai-detail class="add" v-if="$route.query.id">
<template slot="title">
<ai-title title="群发通知详情" isShowBack isShowBottomBorder @onBackClick="cancel(false)"></ai-title>
</template>
<template slot="content">
<ai-card title="详情">
<template #content>
<ai-wrapper>
<ai-info-item label="创建者" :value="data.userName" isLine></ai-info-item>
<ai-info-item label="发送方式" :value="data.messageSource" isLine>{{ data.messageSource | format }}</ai-info-item>
</ai-wrapper>
<ai-wrapper v-for="item in data.fileList" :key="item.id">
<ai-info-item label="群发内容" :value="item.content" isLine v-if="item.contentType == 'text'"></ai-info-item>
</ai-wrapper>
<!-- <ai-wrapper v-for="item in data.fileList" :key="item.id">
<ai-info-item label="图片" isLine v-if="item.contentType == 'image'">
<ai-uploader v-model="images" :instance="instance" :limit="9" disabled/>
</ai-info-item>
</ai-wrapper>
<ai-wrapper v-for="item in data.fileList" :key="item.id">
<ai-info-item label="视频" isLine v-if="item.contentType == 'video'">
<video :src="item.accessUrl" style="width: 100%; height:100%; object-fit: fill;" muted controls="controls"></video>
</ai-info-item>
</ai-wrapper>
<ai-wrapper v-for="item in data.fileList" :key="item.id">
<ai-info-item label="附件" isLine v-if="item.contentType == 'file'">
<ai-file-list :fileList="fileDownLoad"></ai-file-list>
</ai-info-item>
</ai-wrapper> -->
<ai-wrapper>
<ai-info-item label="图片" isLine v-show="images.length">
<ai-uploader v-model="images" :instance="instance" :limit="9" disabled/>
</ai-info-item>
</ai-wrapper>
<ai-wrapper>
<ai-info-item label="视频" isLine v-show="videoArr.length" v-for="(item,index) in videoArr" :key="index">
<video :src="item.accessUrl" style="width: 100%; height:100%; object-fit: fill;" muted controls="controls"></video>
</ai-info-item>
</ai-wrapper>
<ai-wrapper>
<ai-info-item label="附件" isLine v-show="fileDownLoad.length">
<ai-file-list :fileList="fileDownLoad"></ai-file-list>
</ai-info-item>
</ai-wrapper>
</template>
</ai-card>
</template>
</ai-detail>
</section>
</template>
<script>
import {mapState} from "vuex";
import SelectDeptUser from "./SelectDeptUser";
export default {
name: 'Add',
components: {SelectDeptUser},
props: {
instance: Function,
dict: Object
},
data() {
return {
isShow: false,
data: {},
form: {
areaId: '',
tag: '',
messageSource: '2',
sendTime: '',
content: '',
contentType: 'text',
fileList: [],
organization: '',
deptList: [],
},
tags: [],
subTags: {},
areaId: [],
areaName: [],
imgList: [],
videoList: [],
filesList: [],
fileDownLoad: [],
areaRootId: '',
users: [],
images: [],
imgs: [],
videos: [],
videoArr: [],
files: [],
rules: {
deptList: [{required: true, message: '请选择发送范围'}],
content: [{required: true, message: '请输入群发内容'}],
messageSource: [{required: true, message: '请选择群发方式'}],
},
}
},
computed: {
...mapState(['user']),
tagsChange() {
if (this.tags?.length) {
return this.form.tag = this.tags.toString();
}
},
areaid() {
return this.form.areaId = this.areaId.toString();
},
},
created() {
if (this.$route.query.id) {
this.getInfo()
}
this.areaRootId = [this.user.info.areaId.substr(0, 6), '000000'].join("")
},
filters: {
format(val) {
if(val == 1) {
return '居民'
} else if(val == 2) {
return '居民群'
}
}
},
methods: {
handleAreaSelect(v) {
this.areaName = v?.[0]?.label
},
sourceChange(val) {
this.form.messageSource = val
this.form.deptList = []
},
getInfo() {
this.instance.post(`/app/pushmessage/detail?id=${this.$route.query.id}`).then(res => {
if (res?.data) {
this.data = res.data
// this.images = [{url: res.data.fileList.filter(e => e.contentType == "image").map().accessUrl}]
// this.fileDownLoad = [{url: res.data.fileList.filter(e => e.contentType == "file")[0]?.accessUrl}]
this.images = res.data.fileList.filter(e => e.contentType == "image")?.map(i => {
return {
url: i.accessUrl
}
})
this.fileDownLoad = res.data.fileList.filter(e => e.contentType == "file")?.map(v => {
return {
url: v.accessUrl
}
})
if (res.data.fileList.filter(e => e.contentType == "video")) {
this.videoArr = res.data.fileList.filter(e => e.contentType == "video")
}
}
})
},
confirm() {
if(!this.form.deptList.length) {
return this.$message.error('请选择发送范围')
}
this.$refs.form.validate((valid) => {
if (valid) {
this.form.fileList = []
let contentList = [{
content: this.form.content,
contentType: 'text'
}]
if (this.imgList.length) {
this.imgs = this.imgList.map(item => {
return {
contentType: 'image',
mediaId: item.media.mediaId,
accessUrl: item.url,
}
})
}
if (this.videoList.length) {
this.videos = this.videoList.map(item => {
return {
contentType: 'video',
mediaId: item.media.mediaId,
accessUrl: item.url,
}
})
}
if (this.filesList.length) {
this.files = this.filesList.map(item => {
return {
contentType: 'file',
mediaId: item.media.mediaId,
accessUrl: item.url,
}
})
}
this.form.fileList = [...contentList, ...this.imgs, ...this.videos, ...this.files]
this.instance.post(`/app/pushmessage/addOrUpdate`, {
...this.form
}).then(res => {
if (res.code == 0) {
this.$message.success('提交成功')
setTimeout(() => {
this.cancel(true)
}, 600)
}
})
}
})
},
cancel(isRefresh) {
this.$emit('change', {
type: 'List',
isRefresh: !!isRefresh
})
}
}
}
</script>
<style scoped lang="scss">
.Add {
height: 100%;
}
.ai-card__title {
display: flex;
align-items: center;
h2 {
margin-right: 20px;
color: #222222;
font-size: 16px;
font-weight: 700;
}
span {
color: #888888;
font-size: 14px;
}
}
.appletss {
display: flex;
flex-wrap: wrap;
.applets-item {
display: flex;
align-items: center;
width: 400px;
height: 60px;
margin-right: 8px;
margin-bottom: 8px;
padding: 0 17px;
background: #FFFFFF;
border-radius: 2px;
border: 1px solid #D0D4DC;
cursor: pointer;
&:hover {
border-color: #2266FF;
}
::v-deep {
.el-radio__label {
display: none;
}
}
img {
width: 40px;
height: 40px;
margin: 0 8px 0 13px;
}
span {
color: #222222;
font-size: 12px;
}
.el-radio {
margin: 0;
}
&.applets-active {
border-color: #2266FF;
}
}
}
.tips {
position: relative;
top: 2px;
padding-left: 8px;
color: #222222;
font-size: 14px;
}
.el-form-item-item__textarea {
position: relative;
}
.el-form-item__btn {
position: absolute;
bottom: 12px;
left: 12px;
line-height: 1;
z-index: 1;
color: #2266FF;
font-size: 14px;
user-select: none;
background: #fff;
cursor: pointer;
}
.tags {
// padding: 10px;
.tag_title {
font-weight: 600;
}
.tag_item {
margin: 5px 0;
span {
display: inline-block;
// padding: 5px 10px;
width: 80px;
text-align: center;
height: 30px;
line-height: 30px;
background: #DDD;
color: #333;
border-radius: 4px;
margin-right: 8px;
}
.active {
background: #53bcea;
color: #FFFFFF;
}
}
}
</style>

View File

@@ -233,6 +233,7 @@
handleNodeClick (e) {
this.girdLevel = e.girdLevel
this.isLoading = true
console.log(e)
this.getGirdInfo(e.id, e.girdLevel)
this.getStatisticsInfo(e.id)
},
@@ -341,43 +342,16 @@
this.y = '50%'
},
getGirdInfo (id, level) {
getGirdInfo (id) {
this.instance.post(`/app/appgirdinfo/listAllGirdAndMemberByTop?id=${id || ''}`).then((res) => {
if (res.code == 0) {
const chartData = this.formatList(res.data)
if (res.data && res.data[0] && res.data[0].parentGirdInfo) {
const parentGirdInfo = res.data[0].parentGirdInfo
const girdMemberList = parentGirdInfo.girdMemberManageList ? parentGirdInfo.girdMemberManageList.map(v => {
return {
...v,
label: v.name,
id: v.id,
checkType: '2',
girdName: parentGirdInfo.girdName,
girdLevel: parentGirdInfo.girdLevel,
isUser: true
}
}) : [{
label: '-',
id: parentGirdInfo.id,
girdLevel: parentGirdInfo.girdLevel,
girdName: parentGirdInfo.girdName
}]
this.chartData = [{
label: parentGirdInfo.girdName,
id: parentGirdInfo.id,
girdLevel: parentGirdInfo.girdLevel,
isUser: false,
children: chartData,
userList: girdMemberList
}]
} else {
this.chartData = chartData
}
const chartData = this.formatList([res.data])
console.log(chartData)
this.chartData = chartData
this.$nextTick(() => {
if (level === '2') {
this.getUserList(id)
if (id) {
this.getUserList(id, chartData[0].id)
} else {
this.isLoading = false
this.autoScale()
@@ -387,7 +361,7 @@
})
},
getUserList (id) {
getUserList (id, parentId) {
this.instance.post(`/app/appgirdmemberresident/listByGirdMember`, null, {
params: {
size: 1000,
@@ -402,7 +376,7 @@
label: v.name
}
})
this.isLoading = false
if (!userList.length) {
@@ -410,7 +384,7 @@
return false
}
const node = this.$refs.VueOkrTree.getNode(id)
const node = this.$refs.VueOkrTree.getNode(parentId)
this.$refs.VueOkrTree.append({
id: new Date().getTime(),
label: '子节点',
@@ -546,7 +520,7 @@
.el-table {
background-color: transparent;
}
.el-table__body tr td:first-child .cell, .ai-table .el-table__header tr th:first-child .cell {
padding-left: 0!important;
}
@@ -690,7 +664,7 @@
text-overflow:ellipsis;
white-space: nowrap;
margin-bottom: 10px;
&:nth-of-type(2n) {
margin-right: 0;
}
@@ -875,4 +849,4 @@
}
}
}
</style>
</style>

View File

@@ -57,8 +57,8 @@ export default {
<style lang="scss" scoped>
.communityOverview {
max-width: 400px;
max-height: 700px;
overflow-y: auto;
max-height: 600px;
overflow-y: auto!important;
.units {
display: flex;

View File

@@ -4,8 +4,8 @@
<ai-title slot="title" title="审批详情" isShowBack isShowBottomBorder @onBackClick="approval.goBack()">
<template #rightBtn>
<template v-if="listType==0&&$permissions('zwsp_oaapprovalapplyinfo_approve')">
<el-button size="small" class="iconfont iconClean del-btn-list" @click="agreeRefulse(0)">拒绝</el-button>
<el-button size="small" type="primary" class="iconfont iconCorrect" @click="agreeRefulse(1)">同意</el-button>
<el-button size="small" icon="iconfont iconClean del-btn-list" @click="agreeRefulse(0)">拒绝</el-button>
<el-button size="small" type="primary" icon="iconfont iconCorrect" @click="agreeRefulse(1)">同意</el-button>
</template>
<el-button v-if="listType==2&&detail.approvalStatus==0&&$permissions('app_oaapprovalapplyinfo_del')"
size="small" class="iconfont iconRevoke del-btn-list" style="width: 76px;" @click="recall">撤回
@@ -157,9 +157,9 @@
<span class="li_opinion" v-if="item.annexFiles && item.annexFiles.length>0">审批附件</span>
<div style="flex: 1;">
<div class="desc_div">
<img @click="openImg(value.accessUrl)" v-for="(value,_v) in item.pictureFiles" :key="_v"
:src="value.accessUrl" alt="图片" width="80px" height="80px"
style="border: 1px solid #ddd;cursor: pointer;">
<el-image v-for="(value,_v) in item.pictureFiles" :key="_v" :preview-src-list="[value.accessUrl]"
:src="value.accessUrl" alt="图片" width="80px" height="80px"
style="border: 1px solid #ddd;cursor: pointer;"/>
</div>
<ul class="file_ul">
<li v-for="(v,_i) in item.annexFiles" :key="_i" @click="downFile(v.accessUrl)">
@@ -205,15 +205,12 @@
</template>
</ai-detail>
<el-dialog :visible.sync="isOpen" width="600px">
<img :src="imgUrl" alt="" width="100%" height="500px">
</el-dialog>
<!--审批同意拒绝-->
<el-dialog :title="titleType" center :visible.sync="isAgree" width="720px" v-loading="loading"
:close-on-click-modal="false" @close="form.fieldInfos = []">
<div style="height: 400px;overflow-y: auto;">
<el-form size="small" :model="form" label-width="90px" ref="ruleForm" label-position="right"
<div style="max-height: 400px;overflow-y: auto;">
<el-form size="small" :model="form" label-width="120px" ref="ruleForm" label-position="right"
class="dialog-form">
<el-form-item v-for="(op,i) in form.fieldInfos" :key="i"
:label="op.fieldName + (op.fieldNameSuffix ? op.fieldNameSuffix : '')" class="dynamicFormItem"
@@ -240,15 +237,15 @@
type="date"
placeholder="请选择">
</el-date-picker>
<ai-select v-if="op.fieldDataType=='9'" v-model="op.fieldValue"
:selectList="dict.getDict(op.dictionaryCode)"/>
<ai-select v-if="op.fieldDataType=='9'" v-model="op.fieldValue" :selectList="dict.getDict(op.dictionaryCode)"/>
</el-form-item>
<el-form-item label="审批意见" prop="opinion" :rules="[{ required: true, message: '请输入审批意见', trigger: 'blur' }]"
v-if="titleType=='审批拒绝'">
<el-input type="textarea" :rows="4" v-model.trim="form.opinion" placeholder="请输入" show-word-limit
:maxlength="150"></el-input>
<el-form-item label="指定审批人" prop="appointNextCandidateId" :rules="[{ required: true, message: '请选择指定审批人'}]" v-if="form.nextNodeAreaFilter==3">
<ai-select v-model="form.appointNextCandidateId" :selectList="form.nextCandidateList"/>
</el-form-item>
<el-form-item label="图片" prop="imgList" style="position: relative;">
<el-form-item label="审批意见" prop="opinion" :rules="[{ required: true, message: '请输入审批意见', trigger: 'blur' }]" v-if="!form.pass">
<el-input type="textarea" :rows="4" v-model.trim="form.opinion" placeholder="请输入" show-word-limit :maxlength="150"/>
</el-form-item>
<el-form-item label="图片" prop="imgList" style="position: relative;" v-if="form.pictureEnable==1">
<span style="position: absolute;left: -78px;top: 18px;font-size: 12px;color: #999;">最多9张</span>
<el-upload
action
@@ -268,7 +265,7 @@
</div>
</el-upload>
</el-form-item>
<el-form-item label="附件" prop="fileList">
<el-form-item label="附件" prop="fileList" v-if="form.annexEnable==1">
<el-upload
class="upload-demo"
action
@@ -324,7 +321,6 @@ export default {
detailObj: {},
dataList: [],
processList: [],
titleType: '',
isAgree: false,
form: {
id: '',
@@ -344,7 +340,6 @@ export default {
fileList: [],
alreadyList: [],//已审批的
imgUrl: '',
isOpen: false,
url: "/admin/sysunit/getAll2",
applyForm: {},
menuList: ["基本信息", '申请表单', '附件材料', "审批记录"],
@@ -370,7 +365,8 @@ export default {
{slot: "annex"},
{slot: "options"}
]
}
},
titleType: v => v.form.pass ? '审批同意' : '审批拒绝'
},
methods: {
handleDownload() {
@@ -417,10 +413,6 @@ export default {
this.fileList = []
this.isAgree = false
},
openImg(url) {
this.isOpen = true;
this.imgUrl = url;
},
// 下载
downFile(url) {
window.open(url);
@@ -558,36 +550,22 @@ export default {
let dictionaryArr = []
this.loading = true
this.instance.post(`/app/approv-alapply-info/approval-popup?id=${this.detail.id}&type=${index}`).then(res => {
this.loading = false
if (res && res.data) {
if (res?.data) {
if (index == 1) {
res.data.fieldInfos.map(e => {
if (e.fieldType == 3 && e.dictionaryCode && dictionaryArr.indexOf(e.dictionaryCode) == -1) {
this.form = res.data
this.form.fieldInfos = res.data.fieldInfos.filter(e => e.fieldType == 3)
this.form.nextCandidateList = this.form.nextCandidateList?.map(e => ({dictValue: e.candidate, dictName: e.name}))
this.form.fieldInfos.map(e => {
if (e.dictionaryCode && !dictionaryArr.includes(e.dictionaryCode)) {
dictionaryArr.push(e.dictionaryCode)
}
})
if (dictionaryArr.length) {
this.dict.load(dictionaryArr).then(() => {
this.form.fieldInfos = res.data.fieldInfos.filter(e => e.fieldType == 3)
})
} else {
this.form.fieldInfos = res.data.fieldInfos.filter(e => e.fieldType == 3)
}
dictionaryArr.length > 0 && this.dict.load(dictionaryArr)
}
this.form.pass = index == 1
this.isAgree = true;
if (index == 0) {
this.form.pass = false;
this.titleType = '审批拒绝';
} else {
this.form.pass = true;
this.titleType = '审批同意';
}
}
}).catch(err => {
this.loading = false
console.log(err);
})
}).finally(() => this.loading = false)
},
saveAgree() {
this.form.id = this.detail.id;

View File

@@ -13,7 +13,7 @@
</el-tabs>
</template>
</ai-list>
<component v-else :is="currentComp" :instance="instance" :dict="dict" :processType="currentTab.value" :row="row" @back="back"/>
<component v-else :is="currentTab.detail" :instance="instance" :dict="dict" :processType="currentTab.value" :row="row" @back="back"/>
</section>
</template>
@@ -35,7 +35,6 @@ export default {
return {
currIndex: "0",
row: {},
currentComp: "",
}
},
computed: {
@@ -49,22 +48,18 @@ export default {
return this.tabs?.[this.currIndex] || {}
},
showDetail() {
return !!this.$route.query?.id || !!this.$route.query?.processType
return this.$route.hash == "#add" || !!this.$route.query?.processType
}
},
methods: {
goPage(params) {
this.row = params.row
this.currentComp = params.comp
this.$router.push({query: {processType: this.currentTab.value}})
this.$router.push({query: {id: params.row.id}, hash: "#add"})
},
back() {
this.$router.push({query: {}})
}
},
created() {
this.$router.push({query: {}});
this.$dict.load("hbDepartment", 'sex', 'nation', 'marital', 'native_place', 'education', 'candidateApproverType', 'scopeCandidates', 'nodeType')
}
}

View File

@@ -9,12 +9,12 @@
</el-steps>
</div>
</template>
<template #content v-if="refresh">
<baseInfo ref="baseInfo" :instance="instance" :dict="dict" v-show="activeStep==0"/>
<template #content v-if="loaded">
<baseInfo ref="baseInfo" :instance="instance" :dict="dict" v-if="activeStep==0"/>
<applyForm ref="applyForm" :instance="instance" :dict="dict" v-show="activeStep==1"/>
<attachmentMaterial ref="attachmentMaterial" :instance="instance" v-show="activeStep==2"/>
<attachmentMaterial ref="attachmentMaterial" :instance="instance" v-if="activeStep==2"/>
<processApproval ref="processApproval" :approvalSteps="applyForm.approvalSteps" :instance="instance"
:dict="dict" v-show="activeStep==3"/>
:dict="dict" v-if="activeStep==3"/>
</template>
<template #footer>
<el-button class="btn" v-if="activeStep==0" @click="handleBack">取消</el-button>
@@ -39,12 +39,10 @@ export default {
props: {
instance: Function,
dict: Object,
row: Object
},
components: {baseInfo, applyForm, attachmentMaterial, processApproval},
data() {
return {
activeStep: 0,
baseInfo: {},
applyForm: {
tableId: "",
@@ -52,7 +50,8 @@ export default {
},
processAnnexDefs: [],
detailObj: {},
refresh: true
activeStep: 0,
loaded: false
}
},
computed: {
@@ -66,7 +65,7 @@ export default {
},
detailTitle() {
return this.detailObj?.id ? "编辑事项" : "添加事项"
}
},
},
methods: {
/**
@@ -103,9 +102,9 @@ export default {
}
},
handleBaseInfo() {
this.$refs['baseInfo'].banseInfoForm().then(res => {
this.$refs.baseInfo.banseInfoForm().then(res => {
if (res) {
this.$refs['applyForm'].getFormList()
this.$refs.applyForm?.getFormList()
this.baseInfo = res
this.activeStep++
}
@@ -115,18 +114,17 @@ export default {
* 保存
*/
save() {
this.$refs['processApproval'].handleProcessApproval().then(res => {
this.$refs.processApproval?.handleProcessApproval().then(res => {
this.instance.post(`/approval-process-def/add-update`, {
...this.detailObj,
...this.baseInfo,
processDefStatus: Number(this.baseInfo.processDefStatus),
tableId: this.applyForm.tableId,
processType: 0,
tableType: 2,
processAnnexDefs: this.annexs.map(e => ({...e, mustFill: Number(e.mustFill)})),
processAnnexDefs: this.annexs?.map(e => ({...e, mustFill: Number(e.mustFill)})),
processNodeList: res.processNodeList
}).then(res => {
if (res.code == 0) {
if (res?.code == 0) {
this.$message.success("保存成功")
this.$emit("back")
}
@@ -139,28 +137,21 @@ export default {
this.instance.post(`/approval-process-def/info-id`, null, {params: {id}}).then(res => {
if (res?.data) {
this.detailObj = res.data
this.refreshDetail()
}
})
}).finally(() => this.loaded = true)
},
getStepIcon(rowIndex) {
if (rowIndex < this.activeStep) return "iconfont iconSteps_Finished"
else if (this.activeStep == rowIndex) return "iconfont iconSteps_In_Progress"
return ""
},
refreshDetail() {
this.refresh = false
this.$nextTick(() => this.refresh = true)
},
handleBack() {
this.detailObj?.id && this.$router.push({query: {}})
this.$emit('back')
}
},
created() {
if (this.row.id) {
this.getDetail(this.row.id)
}
this.getDetail(this.$route.query.id)
}
}
</script>

View File

@@ -29,15 +29,7 @@
<el-checkbox :label="p.dictName" v-for="(p,i) in dict.getDict(e.dictionaryCode)"
:key="Math.random()"></el-checkbox>
</el-checkbox-group>
<el-select placeholder="请选择" disabled size="small" clearable style="width: 100%;" v-if="e.fieldDataType==9">
<el-option
v-for="(item,i) in dict.getDict(e.fieldDbName)" :key="i"
:label="item.dictName"
:value="item.dictValue">
</el-option>
</el-select>
<ai-select v-if="e.fieldDataType==9" disabled/>
<el-date-picker
v-model="form.picker"
v-if="['2','3','7','8'].includes(e.fieldDataType)"

View File

@@ -44,25 +44,8 @@
</el-button>
</div>
</div>
<!-- <ai-wechat-selecter slot="append" :instance="instance" :props="{id:'wxUserId',label:'name'}"
v-model="item.candidateList" v-if="item.candidateApproverType==1">
<el-button size="mini" type="primary">选择指定人员</el-button>
</ai-wechat-selecter> -->
<!-- <ai-user-picker :instance="instance" v-model="item.candidateList" v-if="item.candidateApproverType==1"/> -->
<!-- <ai-people :showAiArea="false" customCliker :instance="instance"
unitUrl="/admin/sysunit/getAll2"
:meta="[]" v-model="item.candidateList"
v-if="item.candidateApproverType==1">
<el-button size="mini" type="primary">选择指定人员</el-button>
</ai-people> -->
<!-- <ai-user-picker :instance="instance" v-model="form.portalUserId"/> -->
<ai-person-select
:chooseUserList="item.candidateList"
v-if="item.candidateApproverType==1"
:instance="instance" customRightText url="/user/page"
headerTitle="人员列表" dialogTitle="选择" :isMultiple="true"
@selectPerson="e => changeCharge(e, index)">
<ai-person-select :chooseUserList="item.candidateList" v-if="item.candidateApproverType==1" :instance="instance" customRightText url="/user/page"
headerTitle="人员列表" dialogTitle="选择" :isMultiple="true" @selectPerson="e => changeCharge(e, index)">
<template v-slot:option="{ item }">
<span class="iconfont iconProlife">{{ item.name }}</span>
<span>{{ item.phone }}</span>
@@ -73,63 +56,40 @@
</el-steps>
</template>
</ai-card>
<el-dialog :title="titleType" class="editStyle" :visible.sync="isAddStep" width="575px" height="380px"
:close-on-click-modal="false">
<el-form size="small" :model="nodeObj" label-width="120px" ref="addForm" :rules="addRules">
<el-form-item label="审批步骤名称" prop="nodeName">
<el-input v-model="nodeObj.nodeName" placeholder="如部门主管审批限10个字" :maxLength="10"
clearable/>
<ai-dialog :title="titleType" class="editStyle" :visible.sync="isAddStep" width="575px" height="380px"
:close-on-click-modal="false" @onConfirm="saveAddProgress">
<el-form size="small" :model="nodeObj" label-width="100px" ref="addForm" :rules="addRules">
<el-form-item label="审批步骤" prop="nodeName">
<el-input v-model="nodeObj.nodeName" placeholder="如部门主管审批限10个字" :maxLength="10" clearable/>
</el-form-item>
<el-form-item label="审批方式" prop="nodeType">
<el-radio-group v-model="nodeObj.nodeType">
<el-radio :label="2">或签
<el-popover
placement="top-start"
width="200"
trigger="click"
content="或签是指该节点指定多名负责人审批时,其中任何一人完成审批即可。适合一个事项只需要某个岗位任何一人审批即可的业务场景。">
<el-button class="el-icon-warning" slot="reference"
style="padding:0;height:14px;border:0;"></el-button>
</el-popover>
</el-radio>
<el-radio :label="3">抄送
<el-popover
placement="top-start"
width="200"
trigger="click"
content="抄送是指一个事项审批完成后,抄送给需要知晓的单位或个人,被抄送的对象可以查阅该事项内容,无需审批。适合一个事项无需对方审批,但审批完成后需要通知对方知晓的业务场景。">
<el-button class="el-icon-warning" slot="reference"
style="padding:0;height:14px;border:0;"></el-button>
</el-popover>
</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label="数据权限" prop="areaFilter">
<el-radio-group v-model="nodeObj.areaFilter">
<el-radio :label="0">不限
<el-popover placement="top-start" width="200" trigger="click" content="审批人员可查看全部申报事项">
<el-button class="el-icon-warning" slot="reference" style="padding:0;height:14px;border:0;"/>
</el-popover>
</el-radio>
<el-radio :label="1">村社区
<el-popover placement="top-start" width="200" trigger="click" content="审批人员可查看本村申报事项">
<el-button class="el-icon-warning" slot="reference" style="padding:0;height:14px;border:0;"/>
</el-popover>
</el-radio>
<el-radio :label="2">镇街
<el-popover placement="top-start" width="200" trigger="click" content="审批人员可查看本镇申报事项">
<el-button class="el-icon-warning" slot="reference" style="padding:0;height:14px;border:0;"/>
<el-radio-group v-model="nodeObj.nodeType" @change="nodeObj.areaFilter='',nodeObj.annexEnable='',nodeObj.pictureEnable=''">
<el-radio v-for="op in approvalWays" :key="op.value" :label="op.value">
<span v-text="op.label"/>
<el-popover placement="top-start" width="200" trigger="click" :content="op.tips">
<el-button type="text" slot="reference" icon="el-icon-warning" class="color-666"/>
</el-popover>
</el-radio>
</el-radio-group>
</el-form-item>
<template v-if="nodeObj.nodeType==2">
<el-form-item label="数据权限" prop="areaFilter">
<el-radio-group v-model="nodeObj.areaFilter">
<el-radio v-for="op in dict.getDict('processNodeAreaFilter')" :key="op.dictValue" :label="op.dictValue">
<span v-text="op.dictName"/>
<el-popover placement="top-start" width="200" trigger="click" :content="dict.getLabel('processNodeAreaFilterTips',op.dictValue)">
<el-button type="text" slot="reference" icon="el-icon-warning" class="color-666"/>
</el-popover>
</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label="附件图片">
<el-checkbox v-model="nodeObj.annexEnable" true-label="1" false-label="0">附件</el-checkbox>
<el-checkbox v-model="nodeObj.pictureEnable" true-label="1" false-label="0">图片</el-checkbox>
</el-form-item>
</template>
</el-form>
<div slot="footer" style="text-align: center;">
<el-button style="width: 92px;" size="small" @click="isAddStep = false">取消</el-button>
<el-button style="width: 92px;" size="small" type="primary" @click="saveAddProgress">确认
</el-button>
</div>
</el-dialog>
</ai-dialog>
</div>
</template>
@@ -149,19 +109,15 @@ export default {
form: {
processNodeList: [],
},
areaId: "",
approvalWays: [
{value: 2, label: '或签', tips: '或签是指该节点指定多名负责人审批时,其中任何一人完成审批即可。适合一个事项只需要某个岗位任何一人审批即可的业务场景。'},
{value: 3, label: '抄送', tips: '抄送是指一个事项审批完成后,抄送给需要知晓的单位或个人,被抄送的对象可以查阅该事项内容,无需审批。适合一个事项无需对方审批,但审批完成后需要通知对方知晓的业务场景。'},
],
isAddStep: false,
isSelectImg: false,
isSelectUnit: false,
isSelectPerson: false,
nodeObj: {
candidateApproverType: '1',
candidateList: [],
nodeIndex: '',
nodeName: '',
nodeType: '',
scopeCandidates: ''
},
nodeObj: {areaFilter: [], annexEnable: null, pictureEnable: null},
indexType: '',
titleType: '',
bomIndex: '',
@@ -190,15 +146,11 @@ export default {
handleProcessApproval() {
return Promise.resolve(this.form)
},
/**
*删除
* */
deleteInfo(index) {
this.$confirm("是否删除").then(() => {
this.form.processNodeList.splice(index, 1)
})
}).catch(() => 0)
},
changeCharge(e, i) {
this.$set(this.form.processNodeList[i], 'candidateList', e.map(v => {
return {
@@ -209,9 +161,6 @@ export default {
},
/**
* 添加流程
* @param index
* @param item
* @param i
*/
addAppStep(index, item, i) {
this.isAddStep = true;
@@ -220,10 +169,8 @@ export default {
if (index == 2) {
this.titleType = '编辑审批步骤';
item.nodeType = item.nodeType * 1;
item.areaFilter = item.areaFilter * 1;
item.candidateApproverType = item.candidateApproverType * 1;
item.scopeCandidates = item.scopeCandidates * 1;
this.nodeObj = JSON.parse(JSON.stringify(item));
this.nodeObj = this.$copy(item)
} else {
this.titleType = '添加审批步骤';
if (this.form.processNodeList.length > 0) {
@@ -235,11 +182,11 @@ export default {
saveAddProgress() {
this.$refs.addForm.validate((valid) => {
if (valid) {
if (this.nodeObj.scopeCandidates == 0) this.nodeObj.candidateList = [];
if (this.nodeObj.scopeCandidates == '0') this.nodeObj.candidateList = [];
if (this.indexType == 1) {
this.form.processNodeList.push(JSON.parse(JSON.stringify(this.nodeObj)));
this.form.processNodeList.push(this.$copy(this.nodeObj));
} else {
this.form.processNodeList.splice(this.bomIndex, 1, JSON.parse(JSON.stringify(this.nodeObj)));
this.form.processNodeList.splice(this.bomIndex, 1, this.$copy(this.nodeObj));
}
this.$refs.addForm.resetFields();
this.isAddStep = false;
@@ -253,13 +200,16 @@ export default {
nodeIndex: '',
nodeName: '',
nodeType: '',
scopeCandidates: ''
scopeCandidates: '1',
annexEnable: null,
pictureEnable: null,
areaFilter: null
};
this.$refs.addForm?.resetFields();
},
},
created() {
this.areaId = this.user.info.areaId.substring(0, 6) + '000000'
this.dict.load("processNodeAreaFilter", 'processNodeAreaFilterTips')
if (this.config.detailObj?.id) {
Object.keys(this.form).map(e => this.form[e] = this.config.detailObj[e])
}
@@ -442,6 +392,10 @@ export default {
}
}
.color-666 {
color: #666;
}
.dia_per_content {
width: 640px;
height: 400px;
@@ -511,7 +465,7 @@ export default {
.peraoBtn {
.el-button--text {
color: #333;
font-size: 12px;
font-size: 14px;
}
}

View File

@@ -96,6 +96,14 @@ module.exports = {
'^/ns': '/'
}
},
'/lns': {
target: 'http://localhost:12525',
changeOrigin: true,
pathRewrite: {
//地址重写
'^/lns': '/'
}
},
'/xsjr': {
target: 'http://192.168.1.87:39896',
changeOrigin: true,