Compare commits
19 Commits
a3ea6d9c51
...
feature/vi
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a5dbdbe778 | ||
|
|
cef8dad5f0 | ||
|
|
da8e8f0d65 | ||
|
|
e91d1f73dc | ||
|
|
d0e18eb2f6 | ||
|
|
82535aff40 | ||
|
|
65fb4ac65b | ||
|
|
93d0e0aafe | ||
|
|
1eb9c532f3 | ||
|
|
3174382666 | ||
|
|
92890111ee | ||
|
|
9b35506181 | ||
|
|
73f300cd7a | ||
|
|
2f79210970 | ||
|
|
8744f115cf | ||
|
|
2174909bb8 | ||
|
|
bd512c3caa | ||
|
|
861e7c688f | ||
|
|
4f0178c627 |
4
.env.oms
@@ -1,4 +0,0 @@
|
||||
VUE_APP_SCOPE=oms
|
||||
VUE_APP_API=http://192.168.1.87:19897
|
||||
VUE_APP_IS_SIMPLE_SERVER=1
|
||||
VUE_APP_PORT=19897
|
||||
@@ -1,5 +0,0 @@
|
||||
VUE_APP_SCOPE=xumu
|
||||
VUE_APP_API=http://192.168.1.87:12413
|
||||
VUE_APP_IS_SIMPLE_SERVER=1
|
||||
VUE_APP_PORT=12413
|
||||
VUE_APP_OMS_ID=2cd70a15-a3cf-4b4d-9a22-0f3b3a888b08 # oms定制方案的ID
|
||||
30
.gitignore
vendored
@@ -1,33 +1,31 @@
|
||||
.DS_Store
|
||||
node_modules
|
||||
/dist
|
||||
|
||||
# local env files
|
||||
.env.local
|
||||
.env.*.local
|
||||
|
||||
# Log files
|
||||
# Logs
|
||||
logs
|
||||
*.log
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
pnpm-debug.log*
|
||||
lerna-debug.log*
|
||||
|
||||
node_modules
|
||||
dist
|
||||
dist-ssr
|
||||
*.local
|
||||
|
||||
# Editor directories and files
|
||||
.vscode/*
|
||||
!.vscode/extensions.json
|
||||
.idea
|
||||
.vscode
|
||||
.DS_Store
|
||||
*.suo
|
||||
*.ntvs*
|
||||
*.njsproj
|
||||
*.sln
|
||||
*.sw?
|
||||
|
||||
/package-lock.json
|
||||
/lib
|
||||
.prettierrc
|
||||
/oms/dist/
|
||||
/project/*/index.js
|
||||
/project/*/dist
|
||||
/ui/package-lock.json
|
||||
/examples/modules.json
|
||||
/examples/router/apps.js
|
||||
/src/apps/
|
||||
/src/config.json
|
||||
/src/utils/apps.js
|
||||
|
||||
14
.npmignore
@@ -1,14 +0,0 @@
|
||||
# 忽略目录
|
||||
examples/
|
||||
packages/
|
||||
subPackages/
|
||||
core/
|
||||
public/
|
||||
project/
|
||||
.idea/
|
||||
ui/lib/
|
||||
|
||||
# 忽略指定文件
|
||||
vue.config.js
|
||||
babel.config.js
|
||||
*.map
|
||||
6
.npmrc
@@ -1,4 +1,6 @@
|
||||
registry=http://192.168.1.87:4873/
|
||||
email=aixianling@sinoecare.com
|
||||
always-auth=true
|
||||
_auth="YWRtaW46YWRtaW4xMjM="
|
||||
package-lock=false
|
||||
registry=http://registry.npmmirror.com
|
||||
legacy-peer-deps=true
|
||||
|
||||
|
||||
@@ -1,11 +0,0 @@
|
||||
module.exports = {
|
||||
presets: [
|
||||
'@vue/app',
|
||||
],
|
||||
plugins: [
|
||||
// 可选链插件, 其他babel插件也是一样的安装方式
|
||||
"@babel/plugin-proposal-optional-chaining",
|
||||
"@babel/plugin-proposal-nullish-coalescing-operator",
|
||||
"@babel/plugin-proposal-logical-assignment-operators"
|
||||
]
|
||||
}
|
||||
@@ -1,38 +0,0 @@
|
||||
const axios = require("axios");
|
||||
const {chalkTag, findApp, fs} = require("./tools");
|
||||
const compiler = require('vue-template-compiler')
|
||||
const saveApps = app => {
|
||||
if (app.list.length > 0) {
|
||||
return axios.post("http://192.168.1.87:12525/node/wechatapps/addOrUpdate", app, {timeout: 1000}).then(res => {
|
||||
if (res.data.code == 0) chalkTag.done("产品库目录已同步至后台数据库...")
|
||||
}).catch(() => 0)
|
||||
} else return Promise.reject("没有应用")
|
||||
}
|
||||
const getAppInfo = (file, apps) => {
|
||||
if (/[\\\/](App[A-Z][^\\\/]+)\.vue$/g.test(file)) {
|
||||
const name = file.replace(/.+[\\\/](App[^\\\/]+)\.vue$/, '$1'),
|
||||
source = fs.readFileSync(file).toString(),
|
||||
parsed = compiler.parseComponent(source),
|
||||
script = parsed.script?.content || "",
|
||||
label = script.match(/label:[^,]+/)?.[0]?.replace(/.+["']([^"']+).+/, '$1')
|
||||
apps.push({
|
||||
id: file.replace(/\.vue$/, '').replace(/[\\\/]/g, '_'),
|
||||
label: label || name,
|
||||
libPath: `/${file.replace(/\.vue$/, '').replace(/[\\\/]/g, '/')}`,
|
||||
name,
|
||||
type: 'web'
|
||||
})
|
||||
}
|
||||
}
|
||||
const sync = () => {
|
||||
chalkTag.info("开始扫描库工程...")
|
||||
const list = []
|
||||
Promise.all([
|
||||
findApp('packages', app => getAppInfo(app, list)),
|
||||
findApp('project', app => getAppInfo(app, list)),
|
||||
]).then(() => {
|
||||
chalkTag.info("正在同步...")
|
||||
saveApps({type: "web", list}).catch(() => 0).finally(() => chalkTag.done("同步成功!"))
|
||||
})
|
||||
}
|
||||
sync()
|
||||
99
bin/build.js
@@ -1,99 +0,0 @@
|
||||
const axios = require('axios')
|
||||
const {fsExtra, copyFiles, findApp, chalkTag, fs} = require("./tools");
|
||||
const compiler = require('vue-template-compiler')
|
||||
const getBuildConfig = id => {
|
||||
axios.post('http://192.168.1.87:12525/node/custom/detail', null, {params: {id}}).then(res => {
|
||||
if (res?.data) {
|
||||
const config = res.data.data
|
||||
fsExtra.outputJson('src/config.json', config.extra)
|
||||
createPages(config)
|
||||
}
|
||||
})
|
||||
}
|
||||
const getAppInfo = (file, apps) => {
|
||||
if (/[\\\/](App[A-Z][^\\\/]+)\.vue$/g.test(file)) {
|
||||
const name = file.replace(/.+[\\\/](App[^\\\/]+)\.vue$/, '$1'),
|
||||
source = fs.readFileSync(file).toString(),
|
||||
parsed = compiler.parseComponent(source),
|
||||
script = parsed.script?.content || "",
|
||||
label = script.match(/label:[^,]+/)?.[0]?.replace(/.+["']([^"']+).+/, '$1')
|
||||
const paths = file.split(/[\\\/]/)
|
||||
apps.push({
|
||||
id: file.replace(/\.vue$/, '').replace(/[\\\/]/g, '_'),
|
||||
label: label || name,
|
||||
path: `/${file.replace(/\.vue$/, '').replace(/[\\\/]/g, '/')}`,
|
||||
workspace: paths.at(0),
|
||||
esm: file.replace(/[\\\/]/g, '/').substring(4),
|
||||
name
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据配置生成应用路由
|
||||
* @param {Object} config - 配置对象,用于定制化路由生成过程
|
||||
* @returns {Promise} - 返回一个Promise对象,表示路由生成完成
|
||||
*/
|
||||
const createRoutes = (config = {}) => {
|
||||
// 初始化路由数组
|
||||
const routes = []
|
||||
// 获取签到页面的路径,如果未指定,则使用默认路径
|
||||
let signPage = '../views/sign'
|
||||
let {signPage: sign, homePage: home = "console"} = config.extra || {}
|
||||
if (config.extra?.signPage) {
|
||||
signPage = `../apps/custom/${sign}/${sign}`
|
||||
}
|
||||
let homePage = `../views/console`
|
||||
if (config.extra?.homePage) {
|
||||
homePage = `../apps/custom/${home}/${home}`
|
||||
}
|
||||
// 查找并处理所有应用,将它们的信息添加到路由中
|
||||
return findApp("src/apps", app => getAppInfo(app, routes)).then(() => {
|
||||
// 生成并输出apps.js文件,定义所有应用的路由
|
||||
fsExtra.outputFile('src/utils/apps.js', `export default [
|
||||
{path: "/login", name: "登录", component: () => import('${signPage}')},
|
||||
{path: '/dv', name: '数据大屏入口', component: () => import('../views/dvIndex')},
|
||||
{path: '/v', name: 'Home', component: () => import('../views/home'), children: [
|
||||
{path:'/',name:'mainEntry', component:()=>import('../views/mainEntry'),children:[
|
||||
{name: "${home}", path: "${home}", component: () => import('${homePage}')},
|
||||
${routes.filter(e => ![sign, home].includes(e.name)).map(e => {
|
||||
// 解构每个路由的属性,用于生成路由配置
|
||||
const {name, label, esm} = e
|
||||
// 生成单个路由配置的字符串表示
|
||||
return `{name:"${name}",label:"${label}",path:"${name}",component:()=>import("../${esm}")}`
|
||||
}).join(',\n')},
|
||||
{path: '*',name: '404',component: ()=>import('../views/building')},
|
||||
]}
|
||||
]},
|
||||
{path: '/', name: "init"},
|
||||
|
||||
]`)
|
||||
// 扫描完毕,使用chalkTag标记任务完成
|
||||
chalkTag.done("扫描完毕")
|
||||
})
|
||||
}
|
||||
|
||||
const createPages = (config = {}) => {
|
||||
fsExtra.emptyDir("src/apps", err => {
|
||||
if (!err) {
|
||||
const {customPath, appList} = config
|
||||
const stdApps = {}
|
||||
appList.filter(e => !/project/.test(e.id))?.forEach(e => {
|
||||
const paths = e.libPath.split('/').filter(Boolean) || []
|
||||
paths.pop()
|
||||
stdApps[paths.join("/")] = 1
|
||||
})
|
||||
Promise.all([
|
||||
copyFiles("src/apps/core", "packages/core"),
|
||||
copyFiles("src/apps/custom", `project/${customPath}`),
|
||||
...Object.keys(stdApps).map(e => copyFiles(`src/apps/${e.replace(/^packages[\\\/]/, '')}`, e)),
|
||||
]).then(() => createRoutes(config)).then(() => fsExtra.ensureFile("src/apps/actions.js"))
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
const start = () => {
|
||||
const buildId = process.argv[2] || process.env.VUE_APP_OMS_ID || 'f670cc46-7cf7-4a0f-86ee-3077044c0b17'
|
||||
getBuildConfig(buildId)
|
||||
}
|
||||
start()
|
||||
@@ -1,37 +0,0 @@
|
||||
const {chalkTag, findApp, fs, fsExtra} = require("./tools");
|
||||
const compiler = require('vue-template-compiler')
|
||||
const getAppInfo = (file, apps) => {
|
||||
if (/[\\\/](App[A-Z][^\\\/]+)\.vue$/g.test(file)) {
|
||||
const name = file.replace(/.+[\\\/](App[^\\\/]+)\.vue$/, '$1'),
|
||||
source = fs.readFileSync(file).toString(),
|
||||
parsed = compiler.parseComponent(source),
|
||||
script = parsed.script?.content || "",
|
||||
label = script.match(/label:[^,]+/)?.[0]?.replace(/.+["']([^"']+).+/, '$1')
|
||||
const paths = file.split(/[\\\/]/)
|
||||
apps.push({
|
||||
id: file.replace(/\.vue$/, '').replace(/[\\\/]/g, '_'),
|
||||
label: label || name,
|
||||
path: `/${file.replace(/\.vue$/, '').replace(/[\\\/]/g, '/')}`,
|
||||
workspace: paths.at(0),
|
||||
esm: file.replace(/[\\\/]/g, '/'),
|
||||
name
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
const start = () => {
|
||||
chalkTag.info("开始扫描库工程...")
|
||||
const {VUE_APP_SCOPE, VUE_APP_CORE} = process.env
|
||||
const list = []
|
||||
let scanScope = ['packages', 'project']
|
||||
if (VUE_APP_SCOPE) scanScope = [`project/${VUE_APP_SCOPE}`]
|
||||
if (VUE_APP_CORE) scanScope.push('packages/core')
|
||||
Promise.all(scanScope.map(e => findApp(e, app => getAppInfo(app, list)))).then(() => {
|
||||
fsExtra.outputFile('examples/router/apps.js', `export default [${list.map(e => {
|
||||
const {name, label, path, esm} = e
|
||||
return `{name:"${name}",label:"${label}",path:"${path}",component:()=>import("@${esm}")}`
|
||||
}).join(',\n')}]`)
|
||||
chalkTag.done("扫描完毕")
|
||||
})
|
||||
}
|
||||
start()
|
||||
70
bin/tools.js
@@ -1,70 +0,0 @@
|
||||
const fsExtra = require('fs-extra')
|
||||
const path = require('path')
|
||||
const chalk = require('chalk')
|
||||
const fs = require('fs')
|
||||
/**
|
||||
* 将函数封装成promise
|
||||
*/
|
||||
const promisify = fn => {
|
||||
return function () {
|
||||
let args = arguments;
|
||||
return new Promise(function (resolve, reject) {
|
||||
[].push.call(args, function (err, result) {
|
||||
if (err) {
|
||||
console.log(err)
|
||||
reject(err);
|
||||
} else {
|
||||
resolve(result);
|
||||
}
|
||||
});
|
||||
fn.apply(null, args);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
const readdir = promisify(fs.readdir)
|
||||
const stat = promisify(fs.stat)
|
||||
|
||||
/**
|
||||
* 封装打印工具
|
||||
*/
|
||||
const {log} = console
|
||||
const chalkTag = {
|
||||
info: msg => log([chalk.bgBlue.black(' INFO '), msg].join(' ')),
|
||||
done: msg => log([chalk.bgGreen.black(' DONE '), msg].join(' ')),
|
||||
warn: msg => log([chalk.bgYellow.black(' WARN '), msg].join(' ')),
|
||||
error: msg => log([chalk.bgRed.black(' ERROR '), msg].join(' ')),
|
||||
}
|
||||
|
||||
/**
|
||||
* 遍历应用的方法
|
||||
*/
|
||||
const findApp = (dir, cb) => {
|
||||
fsExtra.ensureDirSync(dir)
|
||||
return readdir(dir).then(apps => {
|
||||
return Promise.all(apps.map(e => {
|
||||
let cPath = path.join(dir, e)
|
||||
return stat(cPath).then(state => {
|
||||
if (state.isDirectory()) {
|
||||
return findApp(cPath, cb)
|
||||
} else if (state.isFile()) {
|
||||
cb && cb(cPath)
|
||||
}
|
||||
})
|
||||
}) || [])
|
||||
})
|
||||
}
|
||||
const copyFiles = (dir, source = 'src/mods') => {
|
||||
chalkTag.info(`开始扫描${source}...`)
|
||||
return new Promise(resolve => {
|
||||
fsExtra.emptyDir(dir, err => {
|
||||
if (!err) {
|
||||
fsExtra.copy(source, dir).then(() => {
|
||||
chalkTag.done(source + ' 扫描完毕')
|
||||
resolve()
|
||||
})
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
module.exports = {findApp, chalkTag, fsExtra, copyFiles, fs, path}
|
||||
5
core/.npmignore
Normal file
@@ -0,0 +1,5 @@
|
||||
apps/
|
||||
index.js
|
||||
*.map
|
||||
vcapps.import.js
|
||||
dist/
|
||||
@@ -72,9 +72,11 @@
|
||||
|
||||
<script>
|
||||
import {mapState} from "vuex";
|
||||
import AiAddressBookMenu from "../../components/AiAddressBookMenu";
|
||||
|
||||
export default {
|
||||
name: "AppAccount",
|
||||
components: {AiAddressBookMenu},
|
||||
label: "账号管理(村微版)",
|
||||
props: {
|
||||
instance: Function,
|
||||
@@ -267,17 +269,17 @@ export default {
|
||||
.AppAccount {
|
||||
height: 100%;
|
||||
|
||||
:deep( .avatar ){
|
||||
::v-deep .avatar {
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
:deep( .ai-list__content--left ){
|
||||
::v-deep .ai-list__content--left {
|
||||
margin-right: 2px;
|
||||
}
|
||||
|
||||
:deep( .el-form ){
|
||||
::v-deep .el-form {
|
||||
.el-cascader {
|
||||
width: 100%;
|
||||
}
|
||||
@@ -345,7 +345,7 @@ export default {
|
||||
.accountRoleList {
|
||||
height: 100%;
|
||||
|
||||
:deep(.ai-card ){
|
||||
::v-deep.ai-card {
|
||||
box-shadow: none;
|
||||
border: 1px solid #eee;
|
||||
|
||||
@@ -1,19 +1,76 @@
|
||||
<template>
|
||||
<section class="AppDictionary">
|
||||
<ai-list v-if="!showDetail">
|
||||
<ai-title slot="title" title="数据字典" isShowBottomBorder/>
|
||||
<template #content>
|
||||
<ai-search-bar>
|
||||
<template #left>
|
||||
<el-button type="primary" size="small" icon="iconfont iconAdd" @click="addDict"
|
||||
v-if="$permissions('admin_sysdictionary_add')">添加
|
||||
</el-button>
|
||||
</template>
|
||||
<template #right>
|
||||
<el-input size="small" v-model="search.condition" placeholder="数据项" clearable
|
||||
@change="page.current=1,getDicts()" prefix-icon="iconfont iconSearch"/>
|
||||
<el-button type="primary" size="small" icon="iconfont iconSearch"
|
||||
@click="page.current=1,getDicts()">查询
|
||||
</el-button>
|
||||
<el-button size="small" icon="el-icon-refresh-right" @click="resetSearch">重置</el-button>
|
||||
</template>
|
||||
</ai-search-bar>
|
||||
<el-table size="mini" :data="dictList" header-cell-class-name="table-header" tooltip-effect="light"
|
||||
row-class-name="table-row" cell-class-name="table-cell" @expand-change="getDictInfo">
|
||||
<el-table-column type="expand">
|
||||
<el-row slot-scope="{row}" type="flex" align="middle" style="flex-wrap: wrap">
|
||||
<el-tag v-for="(op,i) in row.detail||[]" :key="i" style="margin: 4px">{{ op.dictValue }}|{{ op.dictName }}
|
||||
{{ op.dictColor ? '| ' + op.dictColor : '' }}
|
||||
</el-tag>
|
||||
</el-row>
|
||||
</el-table-column>
|
||||
<el-table-column align="center" label="数据项" prop="code"/>
|
||||
<el-table-column align="center" label="数据项名称" prop="name"/>
|
||||
<el-table-column align="center" label="操作">
|
||||
<div slot-scope="{row}">
|
||||
<el-button type="text" @click="openDetail(row.id)" v-text="'编辑'"
|
||||
v-if="$permissions('admin_sysdictionary_edit')"/>
|
||||
<el-button type="text" @click="handleDelete(row.id)" v-text="'删除'"
|
||||
v-if="$permissions('admin_sysdictionary_del')"/>
|
||||
</div>
|
||||
</el-table-column>
|
||||
<div slot="empty" class="no-data"></div>
|
||||
</el-table>
|
||||
<div class="pagination">
|
||||
<el-pagination background :current-page.sync="page.current" :total="page.total"
|
||||
layout="total,prev, pager, next,sizes, jumper"
|
||||
@size-change="handleSizeChange"
|
||||
:page-size="page.size"
|
||||
:page-sizes="[10, 20, 50, 100,200]"
|
||||
@current-change="getDicts"/>
|
||||
</div>
|
||||
</template>
|
||||
</ai-list>
|
||||
<dict-detail v-else :instance="instance" :permissions="permissions"/>
|
||||
</section>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
const columns = [
|
||||
{slot: "expand"},
|
||||
{label: "数据项", prop: "code"},
|
||||
{label: "数据项名称", prop: "name"},
|
||||
]
|
||||
import DictDetail from "./dictDetail";
|
||||
|
||||
export default {
|
||||
name: "dictList",
|
||||
name: "AppDictionary",
|
||||
components: {DictDetail},
|
||||
label: "数据字典",
|
||||
props: {
|
||||
instance: Function,
|
||||
dict: Object,
|
||||
permissions: Function
|
||||
},
|
||||
computed: {
|
||||
showDetail() {
|
||||
return this.$route.hash == "#add"
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
columns,
|
||||
page: {
|
||||
current: 1,
|
||||
total: 0,
|
||||
@@ -91,52 +148,9 @@ export default {
|
||||
},
|
||||
}
|
||||
</script>
|
||||
<template>
|
||||
<section class="dictList">
|
||||
<ai-list>
|
||||
<ai-title slot="title" title="数据字典" isShowBottomBorder/>
|
||||
<template #content>
|
||||
<ai-search-bar>
|
||||
<template #left>
|
||||
<el-button type="primary" size="small" icon="iconfont iconAdd" @click="addDict"
|
||||
v-if="$permissions('admin_sysdictionary_add')">添加
|
||||
</el-button>
|
||||
</template>
|
||||
<template #right>
|
||||
<el-input size="small" v-model="search.condition" placeholder="数据项" clearable
|
||||
@change="page.current=1,getDicts()" prefix-icon="iconfont iconSearch"/>
|
||||
<el-button type="primary" size="small" icon="iconfont iconSearch"
|
||||
@click="page.current=1,getDicts()">查询
|
||||
</el-button>
|
||||
<el-button size="small" icon="el-icon-refresh-right" @click="resetSearch">重置</el-button>
|
||||
</template>
|
||||
</ai-search-bar>
|
||||
<ai-table :tableData="dictList" :colConfigs="columns" :dict="dict" @getList="getDicts"
|
||||
:total="page.total" :current.sync="page.current" :size.sync="page.size" :page-sizes="[10, 20, 50, 100,200]"
|
||||
@expand-change="getDictInfo">
|
||||
<el-table-column slot="expand" type="expand">
|
||||
<template slot-scope="{row}">
|
||||
<div class="flex" style="gap:4px">
|
||||
<el-tag v-for="(op,i) in row.detail||[]" :key="i">{{ [op.dictValue, op.dictName, op.dictColor].filter(Boolean).join("|") }}</el-tag>
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column slot="options" label="操作" fixed="right" align="center">
|
||||
<template slot-scope="{row}">
|
||||
<div class="table-options">
|
||||
<el-button type="text" @click="openDetail(row.id)" v-if="$permissions('admin_sysdictionary_edit')">编辑</el-button>
|
||||
<el-button type="text" @click="handleDelete(row.id)" v-if="$permissions('admin_sysdictionary_del')">删除</el-button>
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</ai-table>
|
||||
</template>
|
||||
</ai-list>
|
||||
</section>
|
||||
</template>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.dictList {
|
||||
<style lang="scss" scoped>
|
||||
.AppDictionary {
|
||||
height: 100%;
|
||||
}
|
||||
</style>
|
||||
@@ -187,7 +187,7 @@ export default {
|
||||
.dictDetail {
|
||||
height: 100%;
|
||||
|
||||
:deep( .el-table__row ){
|
||||
::v-deep .el-table__row {
|
||||
|
||||
.el-input__inner {
|
||||
padding: 0 30px;
|
||||
@@ -14,8 +14,7 @@ export default {
|
||||
label: "菜单管理",
|
||||
props: {
|
||||
instance: Function,
|
||||
dict: {default: () => ({})},
|
||||
permissions: Function
|
||||
dict: {default: () => ({})}
|
||||
},
|
||||
computed: {
|
||||
currentPage() {
|
||||
@@ -33,8 +33,11 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import AiEditBtn from "../../components/AiEditBtn";
|
||||
|
||||
export default {
|
||||
name: "introPage",
|
||||
components: {AiEditBtn},
|
||||
props: {
|
||||
instance: Function,
|
||||
dict: {default: () => ({})}
|
||||
@@ -82,7 +85,7 @@ export default {
|
||||
.introPage {
|
||||
height: 100%;
|
||||
|
||||
:deep(.ai-detail__content--wrapper ){
|
||||
::v-deep.ai-detail__content--wrapper {
|
||||
min-height: 100%;
|
||||
|
||||
&.list {
|
||||
@@ -38,9 +38,8 @@
|
||||
</el-row>
|
||||
<el-row type="flex" align="middle" class="operation">
|
||||
<div v-if="node.isLeaf" class="opBtn del" v-text="`删除`" @click="handleDelete(data)"/>
|
||||
<div v-if="permissions('guide_page_config')&&data.component&&data.type==1" class="opBtn" v-text="`引导页`"
|
||||
@click="$router.push({hash:'#intro',query:{id:data.id}})"/>
|
||||
<div v-if="!data.component" class="opBtn" v-text="`添加下级`" @click="addMenu(data)"/>
|
||||
<div v-if="data.component&&data.type==1" class="opBtn" v-text="`引导页`" @click="$router.push({hash:'#intro',query:{id:data.id}})"/>
|
||||
<div v-if="data.type<2" class="opBtn" v-text="`添加下级`" @click="addMenu(data)"/>
|
||||
<div class="opBtn" v-text="`编辑`" @click="handleEdit(data)"/>
|
||||
</el-row>
|
||||
</el-row>
|
||||
@@ -48,22 +47,32 @@
|
||||
</el-scrollbar>
|
||||
</template>
|
||||
</ai-list>
|
||||
<ai-dialog :visible.sync="dialog" title="菜单设置" width="500px" @onConfirm="handleSubmit" :close-on-click-modal="false"
|
||||
@closed="form={status:1},selected={}">
|
||||
<ai-dialog :visible.sync="dialog" title="菜单设置" width="500px" @onConfirm="handleSubmit"
|
||||
@closed="form={},selected={}">
|
||||
<el-form ref="MenuForm" :model="form" size="small" label-width="100px" :rules="rules">
|
||||
<el-form-item label="菜单名称" prop="name">
|
||||
<el-input v-model="form.name" placeholder="请输入" clearable/>
|
||||
</el-form-item>
|
||||
<el-form-item label="菜单图标" prop="style">
|
||||
<el-input v-model="form.style" placeholder="请输入" clearable/>
|
||||
<el-form-item label="菜单类型" prop="type">
|
||||
<ai-select v-model="form.type" clearable :selectList="dict.getDict('menuType')"/>
|
||||
</el-form-item>
|
||||
<el-form-item label="菜单应用" prop="component">
|
||||
<el-input v-model="form.component" placeholder="请输入" clearable/>
|
||||
</el-form-item>
|
||||
<el-form-item label="路径(path)" prop="path">
|
||||
<el-input v-model="form.path" placeholder="请输入" clearable/>
|
||||
</el-form-item>
|
||||
<template v-if="form.component">
|
||||
<template v-if="form.type==0">
|
||||
<el-form-item label="菜单图标" prop="style">
|
||||
<el-input v-model="form.style" placeholder="请输入" clearable/>
|
||||
</el-form-item>
|
||||
</template>
|
||||
<template v-if="form.type==1">
|
||||
<el-form-item label="路由名" prop="route">
|
||||
<span v-text="form.route||'提交保存后会自动生成'"/>
|
||||
</el-form-item>
|
||||
<el-form-item label="菜单应用" prop="component">
|
||||
<el-input v-model="form.component" placeholder="请输入" clearable/>
|
||||
</el-form-item>
|
||||
<el-form-item label="路径(path)" prop="path">
|
||||
<el-input v-model="form.path" placeholder="请输入" clearable/>
|
||||
</el-form-item>
|
||||
</template>
|
||||
<template v-if="form.type==2">
|
||||
<el-form-item label="权限码" prop="permission">
|
||||
<el-input v-model="form.permission" placeholder="请输入" clearable/>
|
||||
</el-form-item>
|
||||
@@ -71,7 +80,7 @@
|
||||
<el-form-item label="显示菜单" prop="status">
|
||||
<ai-select v-model="form.status" clearable :selectList="dict.getDict('yesOrNo')"/>
|
||||
</el-form-item>
|
||||
<el-form-item label="排序" prop="showIndex">
|
||||
<el-form-item v-if="form.type<2" label="排序" prop="showIndex">
|
||||
<el-input v-model="form.showIndex" placeholder="请输入" clearable/>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
@@ -85,14 +94,13 @@ export default {
|
||||
name: "list",
|
||||
props: {
|
||||
instance: Function,
|
||||
dict: {default: () => ({})},
|
||||
permissions: Function
|
||||
dict: {default: () => ({})}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
treeData: [],
|
||||
dialog: false,
|
||||
form: {status: 1},
|
||||
form: {},
|
||||
selected: {},
|
||||
rules: {
|
||||
name: [{required: true, message: "请输入 菜单名称"}],
|
||||
@@ -150,7 +158,7 @@ export default {
|
||||
},
|
||||
addMenu(row) {
|
||||
this.dialog = true
|
||||
this.form = {parentId: row.id, status: "1"}
|
||||
this.form = {parentId: row.id}
|
||||
this.selected = row
|
||||
},
|
||||
handleEdit(row) {
|
||||
@@ -173,7 +181,7 @@ export default {
|
||||
.list {
|
||||
height: 100%;
|
||||
|
||||
:deep( .ai-list__content--right-wrapper ) {
|
||||
::v-deep .ai-list__content--right-wrapper {
|
||||
height: calc(100% - 10px);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
@@ -1,9 +1,7 @@
|
||||
<template>
|
||||
<section class="AiSelectCard" flex>
|
||||
<div class="checkCard" v-for="op in list" :key="op[props.value]" :class="{checked:op.dictValue==value}">
|
||||
<el-image :src="op.thumb">
|
||||
<div class="defaultThumb" slot="error"/>
|
||||
</el-image>
|
||||
<el-image :src="op.thumb"/>
|
||||
<el-row type="flex" class="bottomPane">
|
||||
<b class="label fill" v-text="op[props.label]"/>
|
||||
<el-button type="text" @click.stop="$emit('change',op[props.value])">使用</el-button>
|
||||
@@ -53,11 +51,6 @@ export default {
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
& > .el-image {
|
||||
width: inherit;
|
||||
height: calc(100% - 50px);
|
||||
}
|
||||
|
||||
&.checked:before {
|
||||
position: absolute;
|
||||
content: "应用中";
|
||||
@@ -76,15 +69,6 @@ export default {
|
||||
padding: 0 16px;
|
||||
border-top: 1px solid #eee;
|
||||
}
|
||||
|
||||
.defaultThumb {
|
||||
background-image: url("https://cdn.cunwuyun.cn/theme/thumb/web_blue.png");
|
||||
background-repeat: no-repeat;
|
||||
background-position: center;
|
||||
background-size: 360px 206px;
|
||||
width: inherit;
|
||||
height: 206px;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -36,14 +36,13 @@
|
||||
active-color="#5088FF" inactive-color="#D0D4DC"></el-switch>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column slot="options" align="center" label="操作" width="500">
|
||||
<el-table-column slot="options" align="center" label="操作" width="400">
|
||||
<el-row type="flex" justify="center" align="middle" slot-scope="{row}">
|
||||
<el-button type="text" @click="detail(row)">详情</el-button>
|
||||
<el-button type="text" @click="del(row)">删除</el-button>
|
||||
<el-button type="text" @click="handleSystemInfo(row.id)">系统信息</el-button>
|
||||
<el-button type="text" @click="handlePush(row.id)">推送随手拍样式</el-button>
|
||||
<el-button type="text" @click="handleTheme(row.id)">主题样式</el-button>
|
||||
<el-button type="text" @click="handleSession(row)">会话存档</el-button>
|
||||
</el-row>
|
||||
</el-table-column>
|
||||
</ai-table>
|
||||
@@ -135,73 +134,40 @@
|
||||
</el-input>
|
||||
<div id="searchPlaceOutput"/>
|
||||
</ai-dialog>
|
||||
<ai-dialog title="系统信息设置" :visible.sync="sysInfoDialog" width="1200px" @onConfirm="submitSystemInfo"
|
||||
<ai-dialog title="系统信息设置" :visible.sync="sysInfoDialog" width="600px" @onConfirm="submitSystemInfo"
|
||||
@closed="sysInfo={}">
|
||||
<el-form size="small" label-width="140px">
|
||||
<el-form-item label="页签标题">
|
||||
<el-input v-model="sysInfo.title" placeholder="请输入..." clearable/>
|
||||
</el-form-item>
|
||||
<el-form-item label="系统标题">
|
||||
<el-input v-model="sysInfo.fullTitle" placeholder="请输入..." clearable/>
|
||||
</el-form-item>
|
||||
<el-form-item label="favicon">
|
||||
<el-input v-model="sysInfo.favicon" placeholder="浏览器页签图标" clearable/>
|
||||
</el-form-item>
|
||||
<el-form-item label="logo">
|
||||
<el-row type="flex">
|
||||
<el-input v-model="sysInfo.logo" placeholder="请输入..." clearable/>
|
||||
<el-input class="mar-l10" v-model="sysInfo.logoText" placeholder="logo文字">
|
||||
<template #prepend>logo文字</template>
|
||||
</el-input>
|
||||
</el-row>
|
||||
<el-input v-model="sysInfo.logo" placeholder="请输入..." clearable/>
|
||||
</el-form-item>
|
||||
<el-form-item label="登录页">
|
||||
<el-row type="flex" class="mar-b10">
|
||||
<el-input v-model="sysInfo.loginLogo" placeholder="登录页左上角logo,带/代表图片" clearable>
|
||||
<template #prepend>左页首logo</template>
|
||||
</el-input>
|
||||
<el-input class="mar-l10" v-model="sysInfo.loginLogoText" placeholder="logo文字" clearable>
|
||||
<template #prepend>logo文字</template>
|
||||
</el-input>
|
||||
</el-row>
|
||||
<el-row type="flex">
|
||||
<el-input v-model="sysInfo.name" placeholder="左上角标题" clearable>
|
||||
<template #prepend>左上角标题</template>
|
||||
</el-input>
|
||||
<el-input class="mar-l10" v-model="sysInfo.title" placeholder="左上角副标题" clearable>
|
||||
<template #prepend>左上角副标题</template>
|
||||
</el-input>
|
||||
</el-row>
|
||||
<el-input class="mar-t10" type="textarea" rows="5" v-model="sysInfo.desc" placeholder="副标题" clearable/>
|
||||
<el-form-item label="登录页左上角标题">
|
||||
<el-input v-model="sysInfo.name" placeholder="请输入..." clearable/>
|
||||
</el-form-item>
|
||||
<el-row type="flex">
|
||||
<div class="fill">
|
||||
<el-form-item label="版权所有">
|
||||
<el-input v-model="sysInfo.recordDesc" placeholder="请输入..." clearable/>
|
||||
</el-form-item>
|
||||
<el-form-item label="备案号">
|
||||
<el-input v-model="sysInfo.recordNo" placeholder="请输入..." clearable/>
|
||||
</el-form-item>
|
||||
</div>
|
||||
<div class="fill">
|
||||
<el-form-item label="框架版本">
|
||||
<!--edition :版本,标准版:standard、上架版:saas 简易版(不带扫码):simple -->
|
||||
<el-input v-model="sysInfo.edition" placeholder="请输入..." clearable/>
|
||||
</el-form-item>
|
||||
<el-form-item label="备案跳转链接">
|
||||
<el-input v-model="sysInfo.recordURL" placeholder="请输入..." clearable/>
|
||||
</el-form-item>
|
||||
</div>
|
||||
</el-row>
|
||||
<el-form-item label="可信证书">
|
||||
<el-input type="textarea" v-model="sysInfo.ssl" placeholder="请输入可信证书的html代码" clearable rows="5"/>
|
||||
<el-form-item label="登录页副标题">
|
||||
<el-input type="textarea" rows="5" v-model="sysInfo.desc" placeholder="请输入..." clearable/>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="版权所有">
|
||||
<el-input v-model="sysInfo.recordDesc" placeholder="请输入..." clearable/>
|
||||
</el-form-item>
|
||||
<el-form-item label="备案号">
|
||||
<el-input v-model="sysInfo.recordNo" placeholder="请输入..." clearable/>
|
||||
</el-form-item>
|
||||
<el-form-item label="备案跳转链接">
|
||||
<el-input v-model="sysInfo.recordURL" placeholder="请输入..." clearable/>
|
||||
</el-form-item>
|
||||
<el-form-item label="框架版本">
|
||||
<!--edition :版本,标准版:standard、上架版:saas-->
|
||||
<el-input v-model="sysInfo.edition" placeholder="请输入..." clearable/>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</ai-dialog>
|
||||
<ai-dialog title="会话存档设置" :visible.sync="sessionDialog" width="500px" @onConfirm="submitSessionInfo">
|
||||
<el-radio-group v-model="sessionInfo.status">
|
||||
<el-radio label="0">全部</el-radio>
|
||||
<el-radio label="1">内部</el-radio>
|
||||
<el-radio label="2">外部</el-radio>
|
||||
</el-radio-group>
|
||||
</ai-dialog>
|
||||
</section>
|
||||
</template>
|
||||
|
||||
@@ -264,6 +230,7 @@ export default {
|
||||
miniappStatus: [{required: true, message: "请选择小程序状态", trigger: "change"}],
|
||||
areaId: [{required: true, message: "请选择地区", trigger: "change"}],
|
||||
lat: [{required: true, message: "请选择中心点"}],
|
||||
systemInfo: [{required: true, message: "请输入系统配置信息"}],
|
||||
}
|
||||
},
|
||||
},
|
||||
@@ -282,9 +249,7 @@ export default {
|
||||
name: ""
|
||||
},
|
||||
sysInfo: {},
|
||||
sysInfoDialog: false,
|
||||
sessionDialog: false,
|
||||
sessionInfo: {status: '', corpId: ''}
|
||||
sysInfoDialog: false
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
@@ -433,7 +398,7 @@ export default {
|
||||
params: {id}
|
||||
}).then(res => {
|
||||
if (res?.data) {
|
||||
this.sysInfo = JSON.parse(res.data?.systemInfo || null)
|
||||
this.sysInfo = JSON.parse(res.data)
|
||||
this.sysInfo.id = id
|
||||
}
|
||||
})
|
||||
@@ -456,20 +421,6 @@ export default {
|
||||
},
|
||||
handleTheme(id) {
|
||||
this.$router.push({hash: "#theme", query: {id}})
|
||||
},
|
||||
handleSession(row) {
|
||||
this.sessionInfo.corpId = row.corpId
|
||||
this.sessionInfo.status = row.saveConfig || '0'
|
||||
this.sessionDialog = true
|
||||
},
|
||||
submitSessionInfo() {
|
||||
this.instance.post(`/app/appsessionarchiveconfig/updateSessionArchiveConfig?corpId=${this.sessionInfo.corpId}&status=${this.sessionInfo.status}`).then(res => {
|
||||
if (res?.code == 0) {
|
||||
this.getTableData();
|
||||
this.$message.success("提交成功!")
|
||||
this.sessionDialog = false
|
||||
}
|
||||
})
|
||||
}
|
||||
},
|
||||
created() {
|
||||
@@ -483,7 +434,7 @@ export default {
|
||||
height: 100%;
|
||||
|
||||
|
||||
:deep( .mapDialog ){
|
||||
::v-deep .mapDialog {
|
||||
.el-dialog__body {
|
||||
padding: 0;
|
||||
|
||||
@@ -373,7 +373,7 @@ export default {
|
||||
height: 100%;
|
||||
|
||||
|
||||
:deep( .ai-dialog ){
|
||||
::v-deep .ai-dialog {
|
||||
.ai-card {
|
||||
box-shadow: none;
|
||||
border: 1px solid #eee;
|
||||
@@ -389,7 +389,7 @@ export default {
|
||||
}
|
||||
}
|
||||
|
||||
:deep( .rightsGraphDialog ){
|
||||
::v-deep .rightsGraphDialog {
|
||||
.el-dialog__body {
|
||||
padding: 0;
|
||||
}
|
||||
@@ -399,7 +399,7 @@ export default {
|
||||
}
|
||||
}
|
||||
|
||||
:deep( .datail-table-body ){
|
||||
::v-deep .datail-table-body {
|
||||
width: 100%;
|
||||
height: auto;
|
||||
margin-bottom: 16px;
|
||||
@@ -5,7 +5,7 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
;
|
||||
import * as echarts from "echarts";
|
||||
|
||||
export default {
|
||||
name: "rightsGraph",
|
||||
@@ -183,7 +183,7 @@ export default {
|
||||
.rightsGraph {
|
||||
height: 100%;
|
||||
|
||||
:deep( #RightGraph ){
|
||||
::v-deep #RightGraph {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
min-height: 500px;
|
||||
@@ -196,13 +196,13 @@ export default {
|
||||
.AppSystemAccount {
|
||||
height: 100%;
|
||||
|
||||
:deep( .avatar ){
|
||||
::v-deep .avatar {
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
:deep( .el-form ){
|
||||
::v-deep .el-form {
|
||||
.el-cascader, .el-select {
|
||||
width: 100%;
|
||||
}
|
||||
@@ -180,11 +180,11 @@ export default {
|
||||
.AppUserInfo {
|
||||
height: 100%;
|
||||
|
||||
:deep( .ai-list__content--wrapper ){
|
||||
::v-deep .ai-list__content--wrapper {
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
:deep( .el-input__inner ){
|
||||
::v-deep .el-input__inner {
|
||||
|
||||
-webkit-text-security: disc !important;
|
||||
|
||||
@@ -109,7 +109,7 @@ export default {
|
||||
if (res?.data) {
|
||||
this.list = res.data?.filter(e => !e.parentid)
|
||||
this.list.map(p => this.addChild(p, res.data, {parent: 'parentid'}))
|
||||
|
||||
|
||||
this.$nextTick(() => {
|
||||
this.$refs.tree.setCurrentKey(res.data[0].id)
|
||||
this.$emit('select', res.data[0])
|
||||
@@ -209,7 +209,7 @@ export default {
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
:deep( .el-tree ){
|
||||
::v-deep .el-tree {
|
||||
width: 100%;
|
||||
margin-top: 4px;
|
||||
background: transparent;
|
||||
@@ -28,7 +28,7 @@ export default {
|
||||
right: 0;
|
||||
pointer-events: none;
|
||||
|
||||
:deep(.vdr ){
|
||||
::v-deep.vdr {
|
||||
pointer-events: auto;
|
||||
}
|
||||
}
|
||||
45
core/index.js
Normal file
@@ -0,0 +1,45 @@
|
||||
/**
|
||||
* 系统业务模块
|
||||
* @param Vue 外部接入Vue
|
||||
* @param params showList:打印加载的应用;apps:加载的应用文件名数组
|
||||
*/
|
||||
|
||||
const install = function (Vue, params) {
|
||||
if (install.installed) return Promise.resolve()
|
||||
else {
|
||||
// 遍历工作控件内的应用
|
||||
let apps = []
|
||||
let contexts = require.context('.', true, /\.(\/.+)\/App[^\/]+\.vue$/)
|
||||
if (contexts) {
|
||||
contexts.keys().map(e => {
|
||||
if (contexts(e).default) {
|
||||
if (params?.apps) {
|
||||
if (params?.apps.includes(contexts(e).default.name)) {
|
||||
apps.push(contexts(e).default)
|
||||
Vue.component(contexts(e).default.name, contexts(e).default)
|
||||
}
|
||||
} else {
|
||||
apps.push(contexts(e).default)
|
||||
Vue.component(contexts(e).default.name, contexts(e).default)
|
||||
}
|
||||
}
|
||||
})
|
||||
// apps.map(e=>{
|
||||
// console.log(e.name,e.label)
|
||||
// })
|
||||
!!params?.showList && console.log(apps.map(e => e.name))
|
||||
}
|
||||
return Promise.resolve(apps)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// 判断是否是直接引入文件
|
||||
if (typeof window !== 'undefined' && window.Vue) {
|
||||
install(window.Vue)
|
||||
}
|
||||
|
||||
export default {
|
||||
// 导出的对象必须具有 install,才能被 Vue.use() 方法安装
|
||||
install
|
||||
}
|
||||
12
core/package.json
Normal file
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"name": "dvcp-core",
|
||||
"description": "系统业务模块",
|
||||
"version": "1.0.13",
|
||||
"main": "dist/dvcp-core.common.js",
|
||||
"files": [
|
||||
"dist"
|
||||
],
|
||||
"publishConfig": {
|
||||
"registry": "http://cli.sinoecare.net"
|
||||
}
|
||||
}
|
||||
@@ -2,20 +2,14 @@
|
||||
<div id="app">
|
||||
<header-nav v-if="showTools" title="web端产品库">
|
||||
<template #right>
|
||||
<mock/>
|
||||
<div @click="showTools=false,dvDev=true">大屏开发</div>
|
||||
<div @click="showTools=false">隐藏工具栏</div>
|
||||
<div @click="handleLogin">点此登录</div>
|
||||
</template>
|
||||
</header-nav>
|
||||
<ai-dv-wrapper class="fill" v-if="dvDev">
|
||||
<router-view v-bind="commonAttrs"/>
|
||||
</ai-dv-wrapper>
|
||||
<el-row v-else-if="showTools" class="fill mar-t48" type="flex">
|
||||
<slider-nav/>
|
||||
<main-content class="fill" :commonAttrs="commonAttrs"/>
|
||||
<el-row class="fill mar-t48" type="flex">
|
||||
<slider-nav v-if="showTools"/>
|
||||
<main-content class="fill"/>
|
||||
</el-row>
|
||||
<router-view class="fill" v-else v-bind="commonAttrs"/>
|
||||
<div v-if="dialog" class="sign-box">
|
||||
<ai-sign style="margin: auto" :instance="$request" :action="{login}"
|
||||
visible @login="getToken" :showScanLogin="false"/>
|
||||
@@ -29,12 +23,10 @@ import SliderNav from "./components/sliderNav";
|
||||
import MainContent from "./components/mainContent";
|
||||
import HeaderNav from "./components/headerNav";
|
||||
import {mapActions, mapMutations, mapState} from "vuex";
|
||||
import Mock from "./components/mock";
|
||||
import AiDvWrapper from "dui/dv/layout/AiDvWrapper/AiDvWrapper.vue";
|
||||
|
||||
export default {
|
||||
name: 'app',
|
||||
components: {AiDvWrapper, Mock, HeaderNav, MainContent, SliderNav},
|
||||
components: {HeaderNav, MainContent, SliderNav},
|
||||
computed: {
|
||||
...mapState(['user']),
|
||||
login() {
|
||||
@@ -42,29 +34,16 @@ export default {
|
||||
/project\/sass/g.test(location.pathname) && (url += "?corpId=ww596787bb70f08288")
|
||||
return url
|
||||
},
|
||||
commonAttrs() {
|
||||
return {
|
||||
instance: this.$request,
|
||||
dict: this.$dict,
|
||||
permissions: this.$permissions
|
||||
}
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
dialog: false,
|
||||
showTools: true,
|
||||
dvDev: false
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
showTools(v) {
|
||||
v && (this.dvDev = false)
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
...mapMutations(['setToken']),
|
||||
...mapActions(['getUserInfo', 'getFinanceUser']),
|
||||
...mapMutations(['setToken', 'setFinanceUser']),
|
||||
...mapActions(['getUserInfo']),
|
||||
getToken(params) {
|
||||
if (params.access_token) {
|
||||
this.setToken([params.token_type, params.access_token].join(' '))
|
||||
@@ -79,15 +58,12 @@ export default {
|
||||
this.dialog = true
|
||||
})
|
||||
},
|
||||
handleMock() {
|
||||
}
|
||||
},
|
||||
created() {
|
||||
const {jWeixin} = window
|
||||
window.wx = jWeixin
|
||||
if (this.user.token) this.getUserInfo().finally(() => {
|
||||
wx = jWeixin
|
||||
if (this.user.token) this.getUserInfo().then(() => {
|
||||
if (/^\/project\/xiushan/.test(location.pathname)) {
|
||||
this.getFinanceUser()
|
||||
this.setFinanceUser()
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -121,7 +97,6 @@ html, body {
|
||||
top: 0;
|
||||
right: 60px;
|
||||
opacity: 0;
|
||||
z-index: 999;
|
||||
|
||||
&:hover {
|
||||
opacity: 1;
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
<el-avatar :src="user.info.avatar">
|
||||
{{ defaultAvatar }}
|
||||
</el-avatar>
|
||||
<span v-text="defaultName"/>
|
||||
<span>{{ [user.info.name, user.info.roleName].join(" - ") }}</span>
|
||||
<i :class="dropdownIcon"/>
|
||||
</el-row>
|
||||
<el-dropdown-menu>
|
||||
@@ -45,9 +45,12 @@ export default {
|
||||
},
|
||||
computed: {
|
||||
...mapState(['user']),
|
||||
dropdownIcon: v => v.isClick ? 'el-icon-caret-top' : 'el-icon-caret-bottom',
|
||||
defaultAvatar: v => v.user.info.name?.slice(-2) || "无名",
|
||||
defaultName: v => [v.user.info.name, v.user.info.roleName].filter(Boolean)?.join(" - ") || "请先登录"
|
||||
dropdownIcon() {
|
||||
return this.isClick ? 'el-icon-caret-top' : 'el-icon-caret-bottom'
|
||||
},
|
||||
defaultAvatar() {
|
||||
return this.user.info.name?.slice(-2) || "无名"
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
// 获取最新的安卓、ios下载二维码
|
||||
@@ -121,12 +124,11 @@ export default {
|
||||
z-index: -1;
|
||||
}
|
||||
|
||||
:deep(.toolbar) {
|
||||
::v-deep.toolbar {
|
||||
gap: 12px;
|
||||
margin-right: 32px;
|
||||
|
||||
& > div, .toolbarBtn {
|
||||
color: #fff;
|
||||
& > div {
|
||||
padding: 0 12px;
|
||||
|
||||
&:hover {
|
||||
@@ -165,7 +167,7 @@ export default {
|
||||
}
|
||||
}
|
||||
|
||||
:deep( .downLoad_main ) {
|
||||
::v-deep .downLoad_main {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
padding: 16px;
|
||||
|
||||
@@ -1,22 +1,76 @@
|
||||
<template>
|
||||
<section class="mainContent">
|
||||
<ai-nav-tab :routes="$apps"/>
|
||||
<div class="fill">
|
||||
<router-view v-bind="$attrs.commonAttrs"/>
|
||||
<ai-empty v-if="isHome">欢迎使用村微产品库</ai-empty>
|
||||
</div>
|
||||
<el-tabs class="layout" type="card" :value="currentTab" @tab-click="handleTabClick"
|
||||
@tab-remove="handleTabRemove">
|
||||
<el-tab-pane label="默认页" class="layoutItem">
|
||||
<ai-empty>欢迎使用村微产品库</ai-empty>
|
||||
</el-tab-pane>
|
||||
<el-tab-pane v-for="op in tabs" :key="op.name" :closable="op.name!='工作台'" :name="op.name" :label="op.label" lazy>
|
||||
<router-view v-if="currentTab==op.name"/>
|
||||
</el-tab-pane>
|
||||
</el-tabs>
|
||||
</section>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import AiNavTab from "dui/packages/basic/AiNavTab";
|
||||
import {mapState} from "vuex";
|
||||
|
||||
export default {
|
||||
name: "mainContent",
|
||||
components: {AiNavTab},
|
||||
computed: {
|
||||
isHome: v => v.$route.path == '/',
|
||||
...mapState(['apps']),
|
||||
currentTab() {
|
||||
let {name, query, hash} = this.$route
|
||||
return [name?.replace(query?.id, ''), query?.id, hash].join("") || "0"
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
tabs: []
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
$route: {
|
||||
immediate: true,
|
||||
handler() {
|
||||
this.getTabs("route")
|
||||
}
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
handleTabClick({name}) {
|
||||
let {name: route, query, hash} = this.tabs.find(e => e.name == name),
|
||||
exps = []
|
||||
query.id && exps.push(query.id)
|
||||
hash && exps.push(hash)
|
||||
let reg = new RegExp(`(${exps.join("|")})`, 'g')
|
||||
this.$router.push({name: route.replace(reg, ''), query, hash})
|
||||
},
|
||||
handleTabRemove(id = this.currentTab) {
|
||||
let tabs = JSON.parse(JSON.stringify(this.tabs)),
|
||||
index = tabs?.findIndex(e => id == e.name)
|
||||
if (id == this.currentTab) {
|
||||
let next = tabs?.[index + 1] || tabs?.[index - 1]
|
||||
next ? this.handleTabClick(next) : this.$router.push({path: '/'})
|
||||
}
|
||||
this.tabs.splice(index, 1)
|
||||
},
|
||||
getTabs(from) {
|
||||
let {name, query, hash} = this.$route
|
||||
console.log(`getTabs>>>>>>>>>%s>>>>>>>%s`, from, name)
|
||||
let tab = this.tabs.find(e => e.name == this.currentTab),
|
||||
tabName = [name, query?.id, hash].join("")
|
||||
if (tab) {
|
||||
} else if (!name) {
|
||||
} else if (tabName) {
|
||||
let menu = this.apps.find(e => e.name == name)
|
||||
this.tabs.push({name: tabName, query, hash, label: menu?.label})
|
||||
}
|
||||
},
|
||||
},
|
||||
created() {
|
||||
this.getTabs("created")
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -24,7 +78,86 @@ export default {
|
||||
.mainContent {
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
::v-deep.layout {
|
||||
height: 100%;
|
||||
background: #F5F6F9;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
& > .el-tabs__header {
|
||||
margin-bottom: 0;
|
||||
background: linear-gradient(180deg, #FCFCFC 0%, #E0E2E4 100%);
|
||||
height: 40px;
|
||||
display: flex;
|
||||
align-items: flex-end;
|
||||
border: none;
|
||||
|
||||
.el-tabs__nav {
|
||||
border: none;
|
||||
}
|
||||
|
||||
.el-tabs__item {
|
||||
padding: 0 8px 0 12px;
|
||||
text-align: left;
|
||||
min-width: 130px;
|
||||
height: 36px;
|
||||
line-height: 36px;
|
||||
border: none;
|
||||
color: #555;
|
||||
font-size: 12px;
|
||||
|
||||
& + .el-tabs__item {
|
||||
margin-left: 2px;
|
||||
}
|
||||
|
||||
.el-icon-close {
|
||||
float: right;
|
||||
width: auto;
|
||||
height: 100%;
|
||||
line-height: 36px;
|
||||
background: transparent;
|
||||
font-size: 16px;
|
||||
color: #89b;
|
||||
|
||||
&:hover {
|
||||
color: #000;
|
||||
}
|
||||
}
|
||||
|
||||
&.is-active {
|
||||
border: 1px solid #D8DCE3;
|
||||
border-bottom: none;
|
||||
border-radius: 4px 4px 0 0;
|
||||
background: #F5F6F9;
|
||||
color: #222;
|
||||
|
||||
&:after {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
&:after {
|
||||
position: absolute;
|
||||
right: 0;
|
||||
content: " ";
|
||||
width: 1px;
|
||||
background: #D8DCE3;
|
||||
height: 24px;
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.el-tabs__content {
|
||||
flex: 1;
|
||||
min-height: 0;
|
||||
|
||||
.el-tab-pane {
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,110 +0,0 @@
|
||||
<template>
|
||||
<section class="mock">
|
||||
<el-dropdown>
|
||||
<div class="toolbarBtn" v-text="`生成随机数据`"/>
|
||||
<el-dropdown-menu slot="dropdown">
|
||||
<el-dropdown-item>
|
||||
<ai-dialog-btn dialogTitle="随机数据配置" :customFooter="false" @onConfirm="submit" appendToBody @open="getBeans" width="500px">
|
||||
<div class="btn" slot="btn">生成数据</div>
|
||||
<el-form size="small" label-width="60px">
|
||||
<el-form-item label="接口">
|
||||
<el-input v-model="action" placeholder="请输入接口" @change="handleAction"/>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</ai-dialog-btn>
|
||||
</el-dropdown-item>
|
||||
<el-dropdown-item>
|
||||
<ai-dialog-btn dialogTitle="随机数据配置" :customFooter="false" @onConfirm="generateForm" appendToBody @open="getBeans" width="500px">
|
||||
<div class="btn" slot="btn">页面数据</div>
|
||||
<el-form size="small" label-width="60px">
|
||||
<el-form-item label="接口">
|
||||
<el-input v-model="action" placeholder="请输入接口" @change="handleAction"/>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</ai-dialog-btn>
|
||||
</el-dropdown-item>
|
||||
</el-dropdown-menu>
|
||||
</el-dropdown>
|
||||
</section>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import Mock from "mockjs"
|
||||
import instance from "../router/axios";
|
||||
|
||||
export default {
|
||||
name: "mock",
|
||||
data() {
|
||||
return {
|
||||
instance,
|
||||
action: "",
|
||||
config: "",
|
||||
swagger: {},//swagger接口对象集合
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
url: v => /addOrUpdate/.test(v.action) ? v.action : `/${v.action}/addOrUpdate`
|
||||
},
|
||||
methods: {
|
||||
handleAction() {
|
||||
let formName = this.swagger.paths[this.url]?.post.parameters.find(e => e.in == "body")?.name || ""
|
||||
const {Random} = Mock
|
||||
if (formName) {
|
||||
formName = Random.capitalize(formName)
|
||||
const props = this.swagger.definitions[formName]?.properties || {}
|
||||
Object.keys(props).map(e => {
|
||||
const item = props[e]
|
||||
if (item.format == "date-time") {
|
||||
props[e] = () => Random.datetime()
|
||||
} else if (/[0-9a-zA-Z]/.test(item.description)) {
|
||||
props[e] = () => Random.pick(item.description?.match(/\b[0-9a-zA-Z]+\b/g))
|
||||
} else if (/address/i.test(e)) {
|
||||
props[e] = () => Random.county(true)
|
||||
} else if (/userName/i.test(e)) {
|
||||
props[e] = () => Random.cname()
|
||||
} else if (/lat/.test(e)) {
|
||||
props[e] = () => Random.float(3, 53, 6, 8)
|
||||
} else if (/lng/.test(e)) {
|
||||
props[e] = () => Random.float(73, 135, 6, 8)
|
||||
} else if (item.type == "number") {
|
||||
props[e] = () => Random.float(0, 1000, 0, 2)
|
||||
} else if (item.type == "integer") {
|
||||
props[e] = () => Random.integer(0, 1000)
|
||||
} else if (item.type == "string") {
|
||||
props[e] = () => Random.ctitle()
|
||||
} else props[e] = null
|
||||
})
|
||||
this.config = props
|
||||
}
|
||||
},
|
||||
getBeans() {
|
||||
this.instance.get("/app/v2/api-docs", {withoutToken: true}).then(res => this.swagger = res)
|
||||
},
|
||||
generateForm() {
|
||||
const {mock} = Mock
|
||||
this.$vm.$emit("mock", mock(this.config))
|
||||
},
|
||||
submit() {
|
||||
const {mock} = Mock
|
||||
const data = mock({
|
||||
'list|50-100': [this.config]
|
||||
})
|
||||
Promise.all(data.list.map(e => this.instance.post(this.url, e))).then(() => this.$message.success("随机数据生成,执行完毕!"))
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.mock {
|
||||
.btn {
|
||||
cursor: pointer;
|
||||
user-select: none;
|
||||
padding: 0 12px;
|
||||
|
||||
&:hover {
|
||||
color: rgba(#fff, .8);
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -39,22 +39,25 @@ export default {
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
...mapState(['user']),
|
||||
...mapState(['user', 'apps']),
|
||||
navs() {
|
||||
let reg = new RegExp(`.*${this.searchApp?.replace(/-/g,'')||''}.*`, 'gi')
|
||||
return (this.$apps || []).filter(e => !this.searchApp || reg?.test(e.name) || reg?.test(e.label)).map(e => {
|
||||
return (this.apps || []).filter(e => !this.searchApp || reg?.test(e.name) || reg?.test(e.label)).map(e => {
|
||||
if (/\/project\//.test(e.path)) {
|
||||
e.project = process.env.VUE_APP_SCOPE || e.path.replace(/.*project\/([^\/]+)\/.+/, '$1')
|
||||
e.project = e.path.replace(/.*project\/([^\/]+)\/.+/, '$1')
|
||||
} else if (/\/core\//.test(e.path)) {
|
||||
e.project = "core"
|
||||
}
|
||||
return e
|
||||
})
|
||||
},
|
||||
isConsoleRoute() {
|
||||
return this.$route.name == "工作台"
|
||||
},
|
||||
menuPath() {
|
||||
let paths = [], current = this.$apps?.find(e => e.name == this.$route.name)
|
||||
let paths = [], current = this.apps?.find(e => e.name == this.$route.name)
|
||||
const findParent = name => {
|
||||
let menu = this.$apps?.find(e => e.name == name)
|
||||
let menu = this.apps?.find(e => e.name == name)
|
||||
if (menu) {
|
||||
paths.push(menu.name)
|
||||
if (!!menu.parentId) findParent(menu.parentId)
|
||||
@@ -197,7 +200,7 @@ export default {
|
||||
}
|
||||
}
|
||||
|
||||
:deep( .ai-menu ) {
|
||||
::v-deep .ai-menu {
|
||||
padding-left: 0;
|
||||
flex: 1;
|
||||
min-height: 0;
|
||||
@@ -211,7 +214,7 @@ export default {
|
||||
}
|
||||
}
|
||||
|
||||
:deep( .searchApp ) {
|
||||
::v-deep .searchApp {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
height: 44px;
|
||||
|
||||
@@ -1,18 +1,19 @@
|
||||
import Vue from 'vue';
|
||||
import App from './App.vue';
|
||||
import ui from 'element-ui';
|
||||
import router from './router';
|
||||
import router from './router/router';
|
||||
import axios from './router/axios';
|
||||
import utils from './utils';
|
||||
import dui from 'dui/packages';
|
||||
import vcUI from 'dvcp-ui';
|
||||
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 'dui/dv'
|
||||
import dvui from '../project/dvui/entries'
|
||||
|
||||
Vue.use(dataV)
|
||||
Vue.use(ui);
|
||||
Vue.use(dui);
|
||||
Vue.use(dvui);
|
||||
Vue.use(vcUI);
|
||||
Vue.use(dvui)
|
||||
//富文本编辑器配置
|
||||
Vue.config.productionTip = false;
|
||||
Object.keys(utils).map((e) => (Vue.prototype[e] = utils[e]));
|
||||
@@ -22,14 +23,12 @@ const app = new Vue({
|
||||
store,
|
||||
render: h => h(App)
|
||||
});
|
||||
|
||||
let theme = null
|
||||
store.dispatch('getSystem').then(res => {
|
||||
theme = JSON.parse(res?.colorScheme || null)
|
||||
store.dispatch('getSystem').then(({colorScheme}) => {
|
||||
theme = JSON.parse(colorScheme || null)
|
||||
Vue.prototype.$theme = theme?.web || "blue"
|
||||
return import(`dui/lib/styles/theme.${theme?.web}.scss`).catch(() => 0)
|
||||
return import(`dvcp-ui/lib/styles/theme.${theme?.web}.scss`).catch(() => 0)
|
||||
}).finally(() => {
|
||||
Vue.prototype.$vm = app
|
||||
import(`dui/lib/styles/common.scss`).finally(() => app.$mount('#app'))
|
||||
!theme ? app.$mount('#app') : import(`dvcp-ui/lib/styles/common.scss`).finally(() => app.$mount('#app'))
|
||||
})
|
||||
|
||||
|
||||
49
examples/router/autoRoutes.js
Normal file
@@ -0,0 +1,49 @@
|
||||
import store from "../store";
|
||||
import appEntry from "../views/appEntry";
|
||||
import {waiting} from "../utils";
|
||||
import router from "./router";
|
||||
import axios from "./axios";
|
||||
|
||||
export default {
|
||||
routes: [],
|
||||
init() {
|
||||
//约束正则式
|
||||
store.commit("cleanApps")
|
||||
this.routes = []
|
||||
// 自动化本工程应用
|
||||
return this.loadApps()
|
||||
},
|
||||
loadApps() {
|
||||
//新App的自动化格式
|
||||
let apps = require.context('../../packages/', true, /\.(\/.+)\/App[A-Z][^\/]+\.vue$/, 'lazy'),
|
||||
projects = require.context('../../project/', true, /\.(\/.+)\/App[A-Z][^\/]+\.vue$/, 'lazy')
|
||||
const promise = (mods, base) => Promise.all(mods.keys().map(path => mods(path).then(file => {
|
||||
if (file.default) {
|
||||
let {name, label} = file.default,
|
||||
addApp = {
|
||||
name: path.replace(/\.\/?(vue)?/g, '')?.split("/").join("_"), label: label || name,
|
||||
path: `/${base}${path.replace(/\.(\/.+\/App.+)\.vue$/, '$1')}`,
|
||||
component: appEntry,
|
||||
module: file.default
|
||||
}
|
||||
waiting.setContent(`加载${name}...`)
|
||||
router.addRoute(addApp)
|
||||
//命名规范入口文件必须以App开头
|
||||
return store.commit("addApp", addApp)
|
||||
} else return 0
|
||||
})))
|
||||
waiting.init({innerHTML: '应用加载中..'})
|
||||
Promise.all([
|
||||
promise(apps, "packages"),
|
||||
promise(projects, "project")
|
||||
]).then(() => {
|
||||
axios.post("/node/wechatapps/addOrUpdate", {
|
||||
type: "web",
|
||||
list: this.routes().map(({path: libPath, label, module: {name}, name: id}) => ({
|
||||
id, type: 'web', libPath, label, name
|
||||
}))
|
||||
}, {baseURL: "/ns"}).catch(() => 0)
|
||||
waiting.close()
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
import { Message } from 'element-ui'
|
||||
import instance from 'dui/lib/js/request'
|
||||
import instance from 'dvcp-ui/lib/js/request'
|
||||
import {Message} from 'element-ui'
|
||||
|
||||
let baseURLs = {
|
||||
production: "/",
|
||||
@@ -8,10 +8,20 @@ let baseURLs = {
|
||||
instance.defaults.baseURL = baseURLs[process.env.NODE_ENV]
|
||||
instance.interceptors.request.use(config => {
|
||||
if (config.url.startsWith("/node")) {
|
||||
config.url = "/ns" + config.url
|
||||
config.baseURL = "/ns"
|
||||
} else if (/\/project\/beta/.test(location.pathname)) {
|
||||
config.baseURL = "/wg"
|
||||
} else if (/\/project\/sass/.test(location.pathname)) {
|
||||
config.baseURL = "/saas"
|
||||
} else if (/\/xiushan/.test(location.pathname)) {
|
||||
config.baseURL = "/xsjr"
|
||||
} else if (/project\/oms/.test(location.pathname)) {
|
||||
config.baseURL = "/omsapi"
|
||||
} else if (/#url-/.test(location.hash)) {
|
||||
config.baseURL = location.hash.replace(/#url-/, '/')
|
||||
}
|
||||
if (process.env.VUE_APP_IS_SIMPLE_SERVER == 1) {
|
||||
config.url = config.url.replace(/^\/(app|auth|admin)\//, "/api/")
|
||||
if (["/xsjr", "/omsapi"].includes(config.baseURL)) {
|
||||
config.url = config.url.replace(/(app|auth|admin)\//, "")
|
||||
}
|
||||
return config
|
||||
}, error => Message.error(error))
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
import Vue from 'vue'
|
||||
import VueRouter from 'vue-router'
|
||||
import apps from "./apps";
|
||||
import autoRoutes from './autoRoutes'
|
||||
import Vue from "vue";
|
||||
|
||||
autoRoutes.init()
|
||||
Vue.use(VueRouter)
|
||||
Vue.prototype.$apps = apps
|
||||
export default new VueRouter({
|
||||
mode: 'history',
|
||||
hashbang: false,
|
||||
routes: apps,
|
||||
routes: [{path: "/", redirect: "/v", name: "产品库", component: import('../App')}],
|
||||
scrollBehavior(to) {
|
||||
if (to.hash) {
|
||||
return {
|
||||
@@ -1,12 +1,28 @@
|
||||
import Vue from 'vue'
|
||||
import Vuex from 'vuex'
|
||||
import preState from 'vuex-persistedstate'
|
||||
import * as modules from "dui/lib/js/modules"
|
||||
import xsActions from "../../project/xiushan/actions"
|
||||
import * as modules from "dvcp-ui/lib/js/modules"
|
||||
import axios from "../router/axios";
|
||||
|
||||
Vue.use(Vuex)
|
||||
|
||||
export default new Vuex.Store({
|
||||
actions: {...xsActions},
|
||||
state: {
|
||||
apps: []
|
||||
},
|
||||
mutations: {
|
||||
addApp(state, app) {
|
||||
state.apps.push(app)
|
||||
},
|
||||
cleanApps(state) {
|
||||
state.apps = []
|
||||
},
|
||||
setFinanceUser(state) {
|
||||
axios.post("appfinancialorganizationuser/checkUser").then(res => {
|
||||
state.user.financeUser = res.data
|
||||
}).catch(() => 0)
|
||||
}
|
||||
},
|
||||
modules,
|
||||
plugins: [preState()]
|
||||
})
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import {MessageBox} from 'element-ui'
|
||||
import store from '../store'
|
||||
import tools from 'dui/lib/js/utils'
|
||||
import tools from 'dvcp-ui/lib/js/utils'
|
||||
|
||||
const addChildParty = (parent, pending) => {
|
||||
let doBeforeCount = pending.length
|
||||
@@ -28,7 +28,6 @@ const $confirm = (content, options) => {
|
||||
return MessageBox.confirm(content, {
|
||||
type: "warning",
|
||||
confirmButtonText: "确认",
|
||||
closeOnClickModal: false,
|
||||
center: true,
|
||||
title: "提示",
|
||||
dangerouslyUseHTMLString: true,
|
||||
@@ -70,7 +69,7 @@ export const waiting = {
|
||||
div.style.lineHeight = '100vh'
|
||||
div.style.color = '#26f'
|
||||
div.style.fontSize = '20px'
|
||||
div.style.background = 'rgba(255,255,255,.6)'
|
||||
div.style.background = 'rgba(255,255,255,.8)'
|
||||
div.style.backdropFilter = 'blur(6px)'
|
||||
document.body.appendChild(div)
|
||||
} else if (count < 10) {
|
||||
|
||||
37
examples/views/appEntry.vue
Normal file
@@ -0,0 +1,37 @@
|
||||
<template>
|
||||
<section class="appEntry">
|
||||
<component v-if="app" :is="app" :instance="$request" :dict="$dict" :permissions="$permissions"/>
|
||||
<ai-empty v-else>无法找到应用文件</ai-empty>
|
||||
</section>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
||||
import {mapState} from "vuex";
|
||||
|
||||
export default {
|
||||
name: "appEntry",
|
||||
label: "应用库-应用",
|
||||
computed: {
|
||||
...mapState(['apps']),
|
||||
app() {
|
||||
let app = this.apps.find(e => e.name == this.$route.name)
|
||||
return app ? app.module : ""
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.appEntry {
|
||||
width: 100%;
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
min-height: 0;
|
||||
height: 100%;
|
||||
|
||||
& > * {
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
13
examples/views/index.vue
Normal file
@@ -0,0 +1,13 @@
|
||||
<template>
|
||||
<router-view />
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: "index"
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
||||
15
index.html
Normal file
@@ -0,0 +1,15 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<link rel="icon" type="image/svg+xml" href="/favicon.ico" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>村务云应用库-展示页面</title>
|
||||
<script src="https://res.wx.qq.com/open/js/jweixin-1.2.0.js" referrerpolicy="origin"></script>
|
||||
<script src="https://open.work.weixin.qq.com/wwopen/js/jwxwork-1.0.0.js" referrerpolicy="origin"></script>
|
||||
</head>
|
||||
<body>
|
||||
<div id="app"></div>
|
||||
<script type="module" src="/examples/main.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
106
package.json
@@ -1,88 +1,36 @@
|
||||
{
|
||||
"name": "dvcp-web-apps",
|
||||
"version": "4.0.0",
|
||||
"name": "dvcp-vite-webapps",
|
||||
"private": false,
|
||||
"author": "kubbo",
|
||||
"version": "0.0.0",
|
||||
"main": "lib/dvcp-vite-webapps.umd.js",
|
||||
"scripts": {
|
||||
"dev": "vue-cli-service serve examples/main.js",
|
||||
"build": "vue-cli-service build",
|
||||
"oms": "vue-cli-service serve examples/main.js --mode oms",
|
||||
"xumu": "vue-cli-service serve examples/main.js --mode xumu",
|
||||
"sync": "node bin/appsSync.js",
|
||||
"preview": "node bin/build.js && vue-cli-service serve",
|
||||
"predev": "node bin/scanApps.js",
|
||||
"preoms": "dotenv -e .env.oms node bin/scanApps.js",
|
||||
"prexumu": "dotenv -e .env.xumu node bin/scanApps.js",
|
||||
"view:xumu": "vue-cli-service serve --mode xumu",
|
||||
"preview:xumu": "dotenv -e .env.xumu node bin/build.js"
|
||||
"dev": "vite",
|
||||
"preview": "vite preview",
|
||||
"lib": "vite build --outDir lib --emptyOutDir&&npm unpublish --force&&npm publish",
|
||||
"lib:core": "vue-cli-service build --target lib --dest core/dist core/index.js --name vc-app-core&&npm unpublish --force&&npm publish",
|
||||
"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"
|
||||
},
|
||||
"workspaces": [
|
||||
"project/*"
|
||||
],
|
||||
"devDependencies": {
|
||||
"v-viewer": "^1.6.4",
|
||||
"vite": "^2.9.5",
|
||||
"vite-plugin-vue2": "^2.0.0",
|
||||
"vue": "^2.6.14",
|
||||
"vue-router": "^3.3.4",
|
||||
"vue-template-compiler": "^2.6.14",
|
||||
"vuex-persistedstate": "^3.2.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"@amap/amap-jsapi-loader": "^1.0.1",
|
||||
"@ckeditor/ckeditor5-vue2": "^3.0.1",
|
||||
"@jiaminghi/data-view": "^2.10.0",
|
||||
"@logicflow/core": "^1.2.1",
|
||||
"bin-ace-editor": "^3.2.0",
|
||||
"crypto-js": "^4.2.0",
|
||||
"dayjs": "^1.8.35",
|
||||
"echarts": "^5.5.1",
|
||||
"echarts-wordcloud": "^2.0.0",
|
||||
"hash.js": "^1.1.7",
|
||||
"html2canvas": "^1.4.1",
|
||||
"jspdf": "^2.5.2",
|
||||
"dvcp-dv-ui": "^2.0.1",
|
||||
"dvcp-ui": "^1.42.2",
|
||||
"element-ui": "^2.15.8",
|
||||
"mp4box": "^0.4.1",
|
||||
"print-js": "^1.0.63",
|
||||
"serialize-javascript": "^6.0.0",
|
||||
"sortablejs": "^1.12.0",
|
||||
"vue-carousel": "^0.18.0",
|
||||
"vue-cropper": "^0.6.5",
|
||||
"vue-draggable-resizable": "^2.3.0",
|
||||
"vue-qr": "^4.0.9",
|
||||
"vue-ruler-tool": "^1.2.4",
|
||||
"vue-style-loader": "^4.1.3",
|
||||
"vuedraggable": "^2.24.3"
|
||||
},
|
||||
"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",
|
||||
"dotenv-cli": "^7.4.2",
|
||||
"element-ui": "^2.15.9",
|
||||
"eslint": "^5.16.0",
|
||||
"eslint-plugin-vue": "^5.0.0",
|
||||
"image-webpack-loader": "^6.0.0",
|
||||
"inquirer": "^6.5.2",
|
||||
"mockjs": "^1.1.0",
|
||||
"node-ipc": "^9.2.1",
|
||||
"readline": "^1.3.0",
|
||||
"sass": "~1.32.6",
|
||||
"sass-loader": "^7.3.1",
|
||||
"uglifyjs-webpack-plugin": "^2.2.0",
|
||||
"vue": "^2.7.14",
|
||||
"vue-router": "^3.3.4",
|
||||
"vue-template-compiler": "^2.7.14",
|
||||
"vuex": "^3.5.1",
|
||||
"vuex-persistedstate": "^2.7.1"
|
||||
},
|
||||
"vetur": {
|
||||
"attributes": "./attributes.json"
|
||||
},
|
||||
"postcss": {
|
||||
"plugins": {
|
||||
"autoprefixer": {}
|
||||
}
|
||||
},
|
||||
"browserslist": [
|
||||
"> 1%",
|
||||
"last 2 versions",
|
||||
"not ie <= 8"
|
||||
],
|
||||
"resolutions": {
|
||||
"sass": "1.32.6"
|
||||
"sass": "^1.51.0",
|
||||
"vue-draggable-resizable": "^2.3.0"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,289 +0,0 @@
|
||||
<template>
|
||||
<ai-detail>
|
||||
<template slot="title">
|
||||
<ai-title :title="isEdit ? '编辑项目' : '添加项目'" isShowBack isShowBottomBorder @onBackClick="cancel"/>
|
||||
</template>
|
||||
<template slot="content">
|
||||
<el-form ref="form" :model="form" label-width="110px" label-position="right">
|
||||
<ai-card title="基本信息">
|
||||
<template #content>
|
||||
<div class="ai-form">
|
||||
<el-form-item label="名称" prop="name"
|
||||
:rules="[{ required: true, message: '请输入大屏项目名称', trigger: 'blur' }]">
|
||||
<el-input size="small" :maxlength="30" placeholder="请输入大屏项目名称" v-model="form.name"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="描述" style="width: 100%;" prop="description">
|
||||
<el-input size="small" :maxlength="200" :rows="5" type="textarea" style="width: 100%;"
|
||||
placeholder="请输入描述"
|
||||
v-model="form.description"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="是否开启" style="width: 100%;" prop="status">
|
||||
<el-switch
|
||||
v-model="form.status"
|
||||
active-value="1"
|
||||
inactive-value="0">
|
||||
</el-switch>
|
||||
</el-form-item>
|
||||
</div>
|
||||
</template>
|
||||
</ai-card>
|
||||
<ai-card title="大屏" v-if="isEdit">
|
||||
<template #right>
|
||||
<el-button @click="gotoDesign()" type="primary">添加大屏</el-button>
|
||||
<el-button @click="dialog=true" type="primary">定制大屏</el-button>
|
||||
</template>
|
||||
<template #content>
|
||||
<ai-table
|
||||
:tableData="tableData"
|
||||
:col-configs="colConfigs"
|
||||
:total="total"
|
||||
style="margin-top: 6px;"
|
||||
:border="true"
|
||||
row-key="id"
|
||||
:isShowPagination="false"
|
||||
@getList="() => {}">
|
||||
<el-table-column slot="options" label="状态" align="center">
|
||||
<template slot-scope="{ row }">
|
||||
<el-switch
|
||||
v-model="row.status"
|
||||
active-value="1"
|
||||
@change="() => onStatusChange(row.id)">
|
||||
</el-switch>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column slot="options" width="160px" fixed="right" label="操作" align="center">
|
||||
<template slot-scope="{ row, column, $index }">
|
||||
<div class="table-options">
|
||||
<el-button type="text" @click="toEdit(row.id, row.isCustom, row)">编辑</el-button>
|
||||
<el-button type="text" @click="toViewer(row.id)">预览</el-button>
|
||||
<el-button type="text" @click="remove($index)">删除</el-button>
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</ai-table>
|
||||
</template>
|
||||
</ai-card>
|
||||
</el-form>
|
||||
<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">
|
||||
<el-input v-model="custom.title" clearable placeholder="请填写"/>
|
||||
</el-form-item>
|
||||
<el-form-item label="选择大屏" prop="dv">
|
||||
<ai-select v-model="custom.dv" :selectList="dict.getDict('customizedDVs')"/>
|
||||
</el-form-item>
|
||||
<el-form-item label="静态数据">
|
||||
<el-input type="textarea" rows="5" v-model="custom.meta"/>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</ai-dialog>
|
||||
</template>
|
||||
<template #footer>
|
||||
<el-button @click="cancel">取消</el-button>
|
||||
<el-button type="primary" @click="confirm">提交</el-button>
|
||||
</template>
|
||||
</ai-detail>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import Layout from './viewport.vue'
|
||||
import Sortable from 'sortablejs'
|
||||
import {mapActions} from "vuex"
|
||||
|
||||
export default {
|
||||
name: 'Add',
|
||||
props: {
|
||||
instance: Function,
|
||||
dict: Object,
|
||||
urlPrefix: String
|
||||
},
|
||||
inject: {
|
||||
home: {default: ''}
|
||||
},
|
||||
components: {
|
||||
Layout
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
info: {},
|
||||
department: [],
|
||||
form: {
|
||||
name: '',
|
||||
relationLsIds: '',
|
||||
relationLsNames: '',
|
||||
status: '1',
|
||||
description: ''
|
||||
},
|
||||
screenId: '',
|
||||
query: {},
|
||||
total: 0,
|
||||
colConfigs: [
|
||||
{prop: 'title', label: '标题'},
|
||||
{prop: 'id', label: 'ID'}
|
||||
],
|
||||
tableData: [],
|
||||
id: '',
|
||||
dialog: false,
|
||||
custom: {},
|
||||
rules: {
|
||||
dv: [{required: true, message: "请选择 定制大屏"}],
|
||||
title: [{required: true, message: "请输入 大屏标题"}],
|
||||
},
|
||||
config: {
|
||||
backgroundImage: []
|
||||
}
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
isEdit: v => !!v.$route.query.id
|
||||
},
|
||||
created() {
|
||||
this.dict.load('customizedDVs')
|
||||
this.getInfo().then(() => this.$route.params?.id && this.onChange(this.$route.params))
|
||||
},
|
||||
methods: {
|
||||
...mapActions(['closePage']),
|
||||
getInfo() {
|
||||
let {id} = this.$route.query
|
||||
if (!id) return Promise.reject()
|
||||
return this.instance.post(`${this.urlPrefix}/appdiylargescreen/queryLargeScreenProjectDetailById?id=${id}`).then(res => {
|
||||
if (res?.data) {
|
||||
this.form = {
|
||||
...res.data
|
||||
}
|
||||
if (res.data.relationLsIds) {
|
||||
this.tableData = res.data.lsList.map(v => {
|
||||
let conf = JSON.parse(v.config || '') || {}
|
||||
return {
|
||||
id: v.id,
|
||||
title: v.title,
|
||||
dv: conf.custom || '',
|
||||
meta: JSON.stringify(conf.meta),
|
||||
isCustom: !!conf.custom,
|
||||
status: v.status
|
||||
}
|
||||
})
|
||||
this.total = res.data.lsList.length
|
||||
this.$nextTick(() => {
|
||||
this.rowDrop()
|
||||
})
|
||||
}
|
||||
}
|
||||
})
|
||||
},
|
||||
onStatusChange(id) {
|
||||
this.instance.post(`${this.urlPrefix}/appdiylargescreen/enableLargeScreen?id=${id}`).then(res => {
|
||||
if (res.code === 0) {
|
||||
this.$message.success('操作成功')
|
||||
}
|
||||
})
|
||||
},
|
||||
rowDrop() {
|
||||
const tbody = document.querySelector('.el-table__body-wrapper tbody')
|
||||
const _this = this
|
||||
Sortable.create(tbody, {
|
||||
onEnd({newIndex, oldIndex}) {
|
||||
const currRow = _this.tableData.splice(oldIndex, 1)[0]
|
||||
_this.tableData.splice(newIndex, 0, currRow)
|
||||
}
|
||||
})
|
||||
},
|
||||
toViewer(id) {
|
||||
this.$router.push({query: {id}, hash: "#preview"})
|
||||
},
|
||||
onChange(e) {
|
||||
const ids = this.tableData.map(v => v.id)
|
||||
if (ids.indexOf(e.id) < 0) {
|
||||
this.tableData.push({
|
||||
title: e.title,
|
||||
id: e.id,
|
||||
status: '1'
|
||||
})
|
||||
} else {
|
||||
const index = this.tableData.findIndex(v => v.id === e.id)
|
||||
this.$set(this.tableData[index], 'title', e.title)
|
||||
}
|
||||
this.$nextTick(() => {
|
||||
if (this.$route.query.id) {
|
||||
const ids = this.tableData.map(v => v.id).join(',')
|
||||
const names = this.tableData.map(v => v.name).join(',')
|
||||
this.instance.post(`${this.urlPrefix}/appdiylargescreen/addOrUpdateLargeScreenProject`, {
|
||||
...this.form,
|
||||
relationLsIds: ids,
|
||||
relationLsNames: names
|
||||
})
|
||||
}
|
||||
})
|
||||
},
|
||||
gotoDesign(did) {
|
||||
const {id} = this.$route.query
|
||||
this.$router.push({hash: "#design", query: {id, did, name: this.form.name}})
|
||||
},
|
||||
toEdit(id, isCustom, form) {
|
||||
if (!isCustom) {
|
||||
this.gotoDesign(id)
|
||||
} else {
|
||||
this.dialog = true
|
||||
this.custom = form
|
||||
}
|
||||
},
|
||||
|
||||
remove(index) {
|
||||
this.tableData.splice(index, 1)
|
||||
},
|
||||
|
||||
confirm() {
|
||||
this.$refs.form.validate((valid) => {
|
||||
if (valid) {
|
||||
const ids = this.tableData.map(v => v.id).join(',')
|
||||
const names = this.tableData.map(v => v.name).join(',')
|
||||
this.instance.post(`${this.urlPrefix}/appdiylargescreen/addOrUpdateLargeScreenProject`, {
|
||||
...this.form,
|
||||
relationLsIds: ids,
|
||||
relationLsNames: names
|
||||
}).then(res => {
|
||||
if (res.code == 0) {
|
||||
this.$message.success('提交成功')
|
||||
|
||||
this.home && this.home.refreshDvOptions && this.home.refreshDvOptions()
|
||||
setTimeout(() => {
|
||||
this.cancel()
|
||||
}, 600)
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
cancel() {
|
||||
this.closePage()
|
||||
this.$router.push({})
|
||||
},
|
||||
|
||||
handleCustomizedDV() {
|
||||
this.$refs.CustomDVFrom.validate(v => {
|
||||
if (v) {
|
||||
this.instance.post(`${this.urlPrefix}/appdiylargescreen/addOrUpdateLargeScreen`, {
|
||||
config: JSON.stringify({
|
||||
custom: this.custom.dv,
|
||||
meta: JSON.parse(this.custom.meta?.replace(/\\n/g, '') || null)
|
||||
}),
|
||||
status: 1,
|
||||
id: this.custom.id,
|
||||
title: this.custom.title,
|
||||
}).then(res => {
|
||||
if (res?.code == 0 && res?.data) {
|
||||
this.$message.success('保存成功')
|
||||
this.onChange(res.data)
|
||||
this.dialog = false
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
</style>
|
||||
@@ -1,83 +0,0 @@
|
||||
<template>
|
||||
<section class="AppDesigner">
|
||||
<component :is="currentPage" v-bind="$props"/>
|
||||
</section>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import List from './List.vue'
|
||||
import Add from './Add.vue'
|
||||
import SourceData from './SourceData.vue'
|
||||
import Preview from "./preview.vue";
|
||||
import DesignDashboard from "./viewport.vue";
|
||||
|
||||
export default {
|
||||
name: 'AppDesigner',
|
||||
label: '大屏设计',
|
||||
components: {DesignDashboard, Preview, List, Add, SourceData},
|
||||
props: {
|
||||
instance: Function,
|
||||
dict: Object,
|
||||
permissions: Function,
|
||||
urlPrefix: {
|
||||
type: String,
|
||||
default: '/app'
|
||||
}
|
||||
},
|
||||
|
||||
computed: {
|
||||
currentPage() {
|
||||
const {hash} = this.$route
|
||||
return hash == "#sourceData" ? SourceData :
|
||||
hash == "#add" ? Add :
|
||||
hash == "#preview" ? Preview :
|
||||
hash == "#design" ? DesignDashboard : List
|
||||
},
|
||||
tabs() {
|
||||
return [
|
||||
{label: '大屏列表', name: 'FormList', comp: List, permission: ''}
|
||||
].filter(() => {
|
||||
return true
|
||||
})
|
||||
}
|
||||
},
|
||||
|
||||
data() {
|
||||
return {
|
||||
currIndex: '0',
|
||||
componentName: '',
|
||||
params: {},
|
||||
areaId: '',
|
||||
isShowDetail: false
|
||||
}
|
||||
},
|
||||
|
||||
methods: {
|
||||
onChange(data) {
|
||||
if (data.type === 'list') {
|
||||
this.componentName = 'List'
|
||||
this.isShowDetail = false
|
||||
this.params = data.params
|
||||
}
|
||||
|
||||
if (data.type === 'add') {
|
||||
this.componentName = 'Add'
|
||||
this.isShowDetail = true
|
||||
this.params = data.params
|
||||
}
|
||||
|
||||
if (data.type === 'SourceData') {
|
||||
this.componentName = 'SourceData'
|
||||
this.isShowDetail = true
|
||||
this.params = data.params
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.AppDesigner {
|
||||
height: 100%;
|
||||
}
|
||||
</style>
|
||||
@@ -1,167 +0,0 @@
|
||||
<template>
|
||||
<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')">
|
||||
</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">
|
||||
</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" :dict="dict">
|
||||
<el-table-column slot="options" width="160px" fixed="right" label="操作" align="center">
|
||||
<template slot-scope="{ row }">
|
||||
<div class="table-options">
|
||||
<el-button type="text" @click="toEdit(row.id)">编辑</el-button>
|
||||
<el-button type="text" @click="copy(row.id)">复制</el-button>
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</ai-table>
|
||||
<ai-dialog
|
||||
: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' }]">
|
||||
<el-input size="small" placeholder="请输入名称" v-model="form.name"></el-input>
|
||||
</el-form-item>
|
||||
</div>
|
||||
</el-form>
|
||||
</ai-dialog>
|
||||
</template>
|
||||
</ai-list>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
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: '状态', dict:"cwpStatus"},
|
||||
{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
|
||||
},
|
||||
|
||||
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(() => {
|
||||
this.loading = false
|
||||
})
|
||||
},
|
||||
toEdit(id) {
|
||||
this.$router.push({hash: "#add", query: {id}})
|
||||
},
|
||||
toAddData() {
|
||||
this.$router.push({hash: "#sourceData"})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@@ -1,460 +0,0 @@
|
||||
<template>
|
||||
<ai-detail>
|
||||
<template slot="title">
|
||||
<ai-title title="数据源" isShowBack isShowBottomBorder @onBackClick="cancel">
|
||||
</ai-title>
|
||||
</template>
|
||||
<template slot="content">
|
||||
<ai-card title="数据源列表">
|
||||
<template #right>
|
||||
<el-button type="primary" @click="isShow = true">添加数据源</el-button>
|
||||
</template>
|
||||
<template #content>
|
||||
<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">
|
||||
</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">
|
||||
<el-table-column slot="options" width="160px" fixed="right" label="操作" align="center">
|
||||
<template slot-scope="{ row }">
|
||||
<div class="table-options">
|
||||
<el-button type="text" @click="toEdit(row)">编辑</el-button>
|
||||
<el-button type="text" @click="remove(row.id)">删除</el-button>
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</ai-table>
|
||||
</template>
|
||||
</ai-card>
|
||||
<ai-dialog
|
||||
: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">
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="类型" style="width: 100%;" prop="dataRange" :rules="[{ required: true, message: '请选择数据范围', trigger: 'change' }]">
|
||||
<el-radio-group v-model="form.type">
|
||||
<el-radio label="0">村微应用</el-radio>
|
||||
<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-input
|
||||
: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-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">
|
||||
</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-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-input
|
||||
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-option
|
||||
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">
|
||||
</el-option>
|
||||
</el-select>
|
||||
<el-input size="small" style="width: 165px;" placeholder="请输入别名" v-model="item.alias"></el-input>
|
||||
</div>
|
||||
<el-button type="danger" v-if="index > 0" @click="removeConfig('statisticsConfigs', index)">删除</el-button>
|
||||
</div>
|
||||
</el-form-item>
|
||||
</div>
|
||||
|
||||
<el-form-item style="width: 100%;" v-if="form.type === '0'">
|
||||
<el-button type="primary" @click="add('statisticsConfigs')">添加统计项</el-button>
|
||||
</el-form-item>
|
||||
<div v-if="form.type === '0'">
|
||||
<el-form-item :label="'分组' + index" style="width: 100%;" v-for="(item, index) in form.groupConfigs" :key="'groupConfigs' + item.fieldName">
|
||||
<div class="form-flex">
|
||||
<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">
|
||||
</el-option>
|
||||
</el-select>
|
||||
</div>
|
||||
<el-button type="danger" @click="removeConfig('groupConfigs', index)">删除</el-button>
|
||||
</div>
|
||||
</el-form-item>
|
||||
</div>
|
||||
<el-form-item style="width: 100%;" v-if="form.type === '0'">
|
||||
<el-button type="primary" @click="add('groupConfigs')">添加分组</el-button>
|
||||
</el-form-item>
|
||||
<div v-if="form.type === '0'">
|
||||
<el-form-item :label="'统计项' + index" style="width: 100%;" v-for="(item, index) in form.orderConfigs" :key="'orderConfigs' + item.fieldName">
|
||||
<div class="form-flex">
|
||||
<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">
|
||||
</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">
|
||||
</el-option>
|
||||
</el-select>
|
||||
</div>
|
||||
<el-button type="danger" @click="removeConfig('orderConfigs', index)">删除</el-button>
|
||||
</div>
|
||||
</el-form-item>
|
||||
</div>
|
||||
<el-form-item style="width: 100%;" v-if="form.type === '0'">
|
||||
<el-button type="primary" @click="add('orderConfigs')">添加排序</el-button>
|
||||
</el-form-item>
|
||||
</div>
|
||||
</el-form>
|
||||
</ai-dialog>
|
||||
</template>
|
||||
</ai-detail>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'SourceData',
|
||||
|
||||
props: {
|
||||
instance: Function,
|
||||
dict: Object,
|
||||
params: Object,
|
||||
urlPrefix: String
|
||||
},
|
||||
|
||||
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: '类型', format: 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: '降序'
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
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.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
|
||||
|
||||
this.getList()
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
cancel() {
|
||||
this.$router.push({})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.form-flex {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
}
|
||||
</style>
|
||||
@@ -1,459 +0,0 @@
|
||||
<template>
|
||||
<div class="layout-config__group--wrapper">
|
||||
<template v-if="options.type=='map'">
|
||||
<ai-fold>
|
||||
<div slot="title" class="flex w100">
|
||||
<span class="layoutTitle fill">标记点设置</span>
|
||||
<el-button type="text" icon="iconfont iconAdd" @click="handleMapMarker()">添加</el-button>
|
||||
</div>
|
||||
<config-item v-for="(item,i) in markers" :key="i" :label="item.label">
|
||||
<el-input :value="[item.lat,item.lng].join(',')" readonly size="small"/>
|
||||
<el-button type="text" icon="el-icon-edit" @click="handleMapMarker(item,i)"/>
|
||||
<el-button type="text" icon="el-icon-delete" @click="removeMapMarker(i)"/>
|
||||
</config-item>
|
||||
</ai-fold>
|
||||
<ai-fold title="标记点连线">
|
||||
<ai-dialog-btn :modal="false" dialog-title="设置标记点连线" :customFooter="false" @confirm="savePolylines"
|
||||
@open="handleMapPolylines">
|
||||
<code-editor slot="btn" readonly :value="JSON.stringify(options.staticData.polylines, null, 2)" lang="json"
|
||||
theme="github" width="100%" height="250" placeholder="测试默认值"/>
|
||||
<el-button class="m-center" type="text" @click="handleMapPolylineDoc" :closable="false">
|
||||
点击查看连线设置参考文档
|
||||
</el-button>
|
||||
<code-editor v-model="json" lang="json" theme="github" width="100%" height="440"/>
|
||||
</ai-dialog-btn>
|
||||
</ai-fold>
|
||||
</template>
|
||||
<template v-else-if="isPlot">
|
||||
<ai-fold v-for="(chart,i) in options.charts" :key="i">
|
||||
<div slot="title" class="flex w100">
|
||||
<span class="layoutTitle fill" v-text="chart.title"/>
|
||||
<el-button type="text" icon="el-icon-delete" @click="options.charts.splice(i,1)"/>
|
||||
</div>
|
||||
<config-item label="图表名">
|
||||
<el-input size="small" v-model="chart.title"/>
|
||||
</config-item>
|
||||
<config-item label="图表模板">
|
||||
<chart-picker v-model="chart.chart"/>
|
||||
</config-item>
|
||||
<datasource-picker v-model="chart.ds" :instance="instance" class="mar-b10"
|
||||
@input="chart={...chart,...chart.ds},$emit('change',options)"/>
|
||||
<config-item label="数据维度" v-if="chart.dataType !== 'staticData'">
|
||||
<code-editor v-model="chart.djson" lang="json" theme="github" width="100%" height="100"
|
||||
placeholder="参照echarts配置数据维度,为一个数组,数组的第一个值为维度值"
|
||||
@change="v=>chart.dimensions=JSON.parse(v)"/>
|
||||
</config-item>
|
||||
</ai-fold>
|
||||
<el-button type="text" icon="el-icon-plus" @click="options.charts.push({title:'新图表'})">添加图表</el-button>
|
||||
</template>
|
||||
<template v-else-if="options.type=='monitorCarousel'">
|
||||
<config-item label="监控列表">
|
||||
<el-button type="text" icon="el-icon-plus" @click="options.list.push({})"/>
|
||||
</config-item>
|
||||
<el-table size="mini" :data="options.list" border :row-style="{backgroundColor:'transparent'}">
|
||||
<el-table-column label="监控类型">
|
||||
<template v-slot="{row}">
|
||||
<ai-select size="mini" v-model="row.monitorType" :select-list="monitorTypes"/>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="监控地址">
|
||||
<template v-slot="{row}">
|
||||
<el-input v-if="['hik','dahua'].includes(row.monitorType)" size="mini" v-model="row.src" clearable/>
|
||||
<div v-else-if="['cmcc','slw'].includes(row.monitorType)">
|
||||
<el-input size="mini" v-model="row.api" clearable placeholder="请输入监控列表接口"/>
|
||||
<ai-select v-model="row.did" :instance="instance" @change="handleMonitor(row)" size="mini"
|
||||
:prop="{label:'name'}" :condition="e=>!!e.name&&!!e.id" class="mar-t8" :action="row.api"/>
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column width="60px" label="操作">
|
||||
<template v-slot="{row,i}">
|
||||
<el-button type="text" @click="$confirm('是否删除该监控?').then(()=>options.list.splice(i,1))">删除
|
||||
</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</template>
|
||||
<div class="layout-config__group" v-else-if="['hik','dahua'].includes(options.monitorType)">
|
||||
<h2>基础设置</h2>
|
||||
<config-item label="视频地址">
|
||||
<el-input size="mini" v-model="options.src"/>
|
||||
</config-item>
|
||||
</div>
|
||||
<div class="layout-config__group" v-else>
|
||||
<h2>基础设置</h2>
|
||||
<datasource-picker :options="options" :instance="instance" @input="$emit('change',options)"/>
|
||||
</div>
|
||||
<div class="layout-config__group" v-if="isTable">
|
||||
<h2>表格设置</h2>
|
||||
<code-editor v-model="json" theme="github" width="100%" height="440"
|
||||
placeholder="参照dvScrollBoard设置表格"
|
||||
@change="v=>options.tableConfig=JSON.parse(v)"/>
|
||||
</div>
|
||||
<div v-if="options.dataType!='staticData'&&options.type=='monitor'&&['cmcc','slw'].includes(options.monitorType)"
|
||||
class="layout-config__group">
|
||||
<h2>字段设置</h2>
|
||||
<config-item label="监控视频">
|
||||
<el-select size="mini" v-model="options.moniterId" placeholder="请选择监控视频" @change="onMoniterId">
|
||||
<el-option
|
||||
v-for="(item, index) in monitorList"
|
||||
:key="index"
|
||||
:label="item.name"
|
||||
:value="item.id">
|
||||
</el-option>
|
||||
</el-select>
|
||||
</config-item>
|
||||
</div>
|
||||
<div v-if="options.dataType!='staticData'&& keys.length &&!['table','monitor','map','plot'].includes(options.type)"
|
||||
class="layout-config__group">
|
||||
<h2>字段设置</h2>
|
||||
<config-item label="X轴设置">
|
||||
<el-select size="mini" v-model="options.dataX" placeholder="请选择X轴" @change="onChooseChange">
|
||||
<el-option
|
||||
v-for="(item, index) in keys"
|
||||
:key="index"
|
||||
:label="item"
|
||||
:value="item">
|
||||
</el-option>
|
||||
</el-select>
|
||||
</config-item>
|
||||
<config-item label="Y轴设置">
|
||||
<el-select size="mini" multiple :multiple-limit="options.type.indexOf('pie') > -1 ? 1 : 100"
|
||||
v-model="options.dataY" collapse-tags placeholder="请选择Y轴"
|
||||
@change="onChooseChange">
|
||||
<el-option
|
||||
v-for="(item, index) in keys"
|
||||
:key="index"
|
||||
:label="item"
|
||||
:value="item">
|
||||
</el-option>
|
||||
</el-select>
|
||||
</config-item>
|
||||
</div>
|
||||
<ai-dialog class="layout-config__edit" v-model="showMapEditor" title="设置地图标记点" append-to-body
|
||||
@close="form={}" @confirm="saveMarker">
|
||||
<el-form :model="form" size="small" ref="mapMarker" label-width="120px">
|
||||
<el-form-item label="标记点名称" :rules="{required:true,message:'请填写标记点名称'}">
|
||||
<el-input placeholder="用于地图上展示对标记点的文字标签" v-model="form.label" clearable/>
|
||||
</el-form-item>
|
||||
<el-form-item label="标记点图标">
|
||||
<el-input placeholder="用于地图上展示对标记点的显示图标" v-model="form.icon" clearable/>
|
||||
</el-form-item>
|
||||
<div flex>
|
||||
<el-form-item class="fill" label="经度" :rules="{required:true,message:'请填写标记点经度'}">
|
||||
<el-input v-model="form.lng" clearable placeholder="小数点位保留至少6位数"/>
|
||||
</el-form-item>
|
||||
<el-form-item class="fill" label="纬度" :rules="{required:true,message:'请填写标记点纬度'}">
|
||||
<el-input v-model="form.lat" clearable placeholder="小数点位保留至少6位数"/>
|
||||
</el-form-item>
|
||||
</div>
|
||||
<el-form-item label="弹窗内容">
|
||||
<ai-editor v-model="form.infoWindowHtml" :instance="instance"/>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</ai-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import CodeEditor from 'bin-ace-editor'
|
||||
import 'brace/mode/json'
|
||||
import 'brace/snippets/json';
|
||||
import 'brace/theme/github';
|
||||
import 'brace/theme/monokai';
|
||||
import AiDialogBtn from "dui/packages/layout/AiDialogBtn.vue";
|
||||
import AiFold from "dui/packages/layout/AiFold.vue";
|
||||
import ChartPicker from "./chartPicker.vue";
|
||||
import {monitorTypes} from "../config";
|
||||
import ConfigItem from "./configItem.vue";
|
||||
import DatasourcePicker from "./datasourcePicker.vue";
|
||||
import AiSelect from "dui/packages/basic/AiSelect.vue";
|
||||
import {DvCompData} from "dui/dv";
|
||||
|
||||
export default {
|
||||
name: 'dataConfig',
|
||||
model: {
|
||||
prop: "options",
|
||||
event: "change"
|
||||
},
|
||||
props: {
|
||||
options: Object,
|
||||
instance: Function,
|
||||
dict: Object,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
dataTypes: Object.entries(DvCompData.types).map(e => ({id: e[0], label: e[1]})),
|
||||
json: "",
|
||||
keys: [],
|
||||
monitorList: [],
|
||||
list: [],
|
||||
showMapEditor: false,
|
||||
form: {},
|
||||
datasource: {},
|
||||
monitorTypes
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
markers: v => v.options.staticData?.markers || [],
|
||||
isTable: v => v.options.type == 'table',
|
||||
isPlot: v => v.options.type == 'plot'
|
||||
},
|
||||
components: {
|
||||
AiSelect,
|
||||
DatasourcePicker,
|
||||
ConfigItem,
|
||||
ChartPicker,
|
||||
AiFold,
|
||||
AiDialogBtn,
|
||||
CodeEditor,
|
||||
},
|
||||
created() {
|
||||
if (this.options.type == "map" && Array.isArray(this.options.staticData)) {//处理历史数据,并更新最新数据结构
|
||||
const values = this.$copy(this.options)
|
||||
values.staticData = {markers: this.$copy(this.options.staticData)}
|
||||
this.$emit("change", values)
|
||||
} else if (this.isTable) {
|
||||
this.json = JSON.stringify(this.options.tableConfig)
|
||||
} else if (this.options.type == "monitorCarousel") {
|
||||
const {list = []} = this.options
|
||||
this.$set(this.options, 'list', list)
|
||||
} else if (this.isPlot) {
|
||||
this.options.charts = this.options.charts.map(e => ({...e, ds: e}))
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
if ((this.options.dataY && this.options.dataY.length && this.options.dataX) || this.options.type === 'monitor') {
|
||||
const api = this.options.dataType === 'apiData' ? this.options.api : `/app/appdiylargescreen/statisticsByLsid?id=${this.options.sourceDataId}`
|
||||
this.instance.post(api).then(res => {
|
||||
if (res.code == 0) {
|
||||
if (res.data.length && this.options.type !== 'monitor') {
|
||||
this.list = res.data
|
||||
this.keys = Object.keys(res.data[0])
|
||||
|
||||
this.$nextTick(() => {
|
||||
this.onChooseChange()
|
||||
})
|
||||
} else if (this.options.type === 'monitor') {
|
||||
this.monitorList = res.data
|
||||
|
||||
if (this.options.src) {
|
||||
const obj = res.data.filter(v => this.options.title === v.name)
|
||||
|
||||
if (obj.length) {
|
||||
this.options.src = obj[0].url
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
onMoniterId(e) {
|
||||
this.instance.post(`/app/appzyvideoequipment/getWebSdkUrl?deviceId=${e}`).then(res => {
|
||||
if (res.code == 0) {
|
||||
this.options.src = JSON.parse(res.data).url
|
||||
}
|
||||
})
|
||||
},
|
||||
handleMonitor(row) {
|
||||
this.instance.post(`/app/appzyvideoequipment/getWebSdkUrl?deviceId=${row.did}`).then(res => {
|
||||
if (res.code == 0) {
|
||||
this.$set(row, 'src', JSON.parse(res.data).url)
|
||||
}
|
||||
})
|
||||
},
|
||||
onChooseChange() {
|
||||
let arr = []
|
||||
if (this.options.dataX && this.options.dataY.length) {
|
||||
this.list.forEach(item => {
|
||||
let obj = {}
|
||||
this.options.dataY.forEach(v => {
|
||||
obj[v] = item[v]
|
||||
})
|
||||
arr.push({
|
||||
[this.options.dataX]: item[this.options.dataX],
|
||||
...obj
|
||||
})
|
||||
})
|
||||
this.options[this.options.dataType] = arr
|
||||
}
|
||||
},
|
||||
handleMapMarker(v = {}, index) {
|
||||
this.form = this.$copy({...v, index})
|
||||
this.showMapEditor = true
|
||||
},
|
||||
saveMarker() {
|
||||
this.$refs.mapMarker.validate().then(() => {
|
||||
const i = this.$copy(this.form.index)
|
||||
delete this.form.index
|
||||
if (i > -1) {
|
||||
this.options.staticData.markers.splice(i, 1, this.form)
|
||||
} else this.options.staticData.markers.push(this.form)
|
||||
this.showMapEditor = false
|
||||
})
|
||||
},
|
||||
removeMapMarker(i) {
|
||||
this.$confirm("是否要删除该标记点").then(() => {
|
||||
this.options.staticData.markers.splice(i, 1)
|
||||
})
|
||||
},
|
||||
savePolylines() {
|
||||
this.$set(this.options.staticData, 'polylines', JSON.parse(this.json))
|
||||
},
|
||||
handleMapPolylines() {
|
||||
this.json = JSON.stringify(this.options.staticData.polylines || [{path: [[31.547706, 107.224325], [31.552456, 107.201185]]}])
|
||||
},
|
||||
handleMapPolylineDoc() {
|
||||
window.open('https://lbs.amap.com/api/javascript-api-v2/documentation#polyline')
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.el-dialog__body {
|
||||
.jsoneditor-vue {
|
||||
height: 480px;
|
||||
|
||||
.jsoneditor-poweredBy {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.ai-dialog__wrapper {
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.layout-config__group--wrapper {
|
||||
|
||||
:deep(.layout-config__group) {
|
||||
padding: 10px 10px 20px;
|
||||
border-bottom: 1px solid #000000;
|
||||
|
||||
&:last-child {
|
||||
border: none;
|
||||
}
|
||||
|
||||
|
||||
& > h2 {
|
||||
margin-bottom: 20px;
|
||||
color: #FFFFFF;
|
||||
font-size: 15px;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.layoutTitle {
|
||||
color: #FFFFFF;
|
||||
font-size: 15px;
|
||||
font-weight: 700;
|
||||
}
|
||||
}
|
||||
|
||||
:deep(.layout-config__item) {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
margin-bottom: 10px;
|
||||
|
||||
&:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
label {
|
||||
flex-shrink: 0;
|
||||
width: 60px;
|
||||
color: #FFFFFF;
|
||||
font-size: 12px;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.el-select .el-tag {
|
||||
color: #fff;
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
.el-input__icon {
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.el-switch__label {
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.el-select {
|
||||
width: 100%;
|
||||
|
||||
&:last-child {
|
||||
margin-right: 0;
|
||||
}
|
||||
|
||||
input {
|
||||
background: #262C33;
|
||||
font-size: 12px;
|
||||
color: #fff;
|
||||
border: 1px solid #030411;
|
||||
}
|
||||
|
||||
.el-input__icon {
|
||||
color: #fff;
|
||||
}
|
||||
}
|
||||
|
||||
:deep(.el-collapse) {
|
||||
height: 18px;
|
||||
}
|
||||
}
|
||||
|
||||
.el-icon-delete {
|
||||
color: #f46;
|
||||
}
|
||||
|
||||
.el-button--text + .el-button--text {
|
||||
margin-left: 0;
|
||||
}
|
||||
|
||||
input {
|
||||
background: #262C33;
|
||||
font-size: 12px;
|
||||
color: #fff;
|
||||
border: 1px solid #030411;
|
||||
}
|
||||
|
||||
.layout-config__item--right {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: flex-end;
|
||||
text-align: right;
|
||||
margin-left: 30px;
|
||||
}
|
||||
|
||||
.el-table {
|
||||
background-color: transparent;
|
||||
|
||||
tr {
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
.el-table__cell {
|
||||
color: white;
|
||||
background-color: #1D2127 !important;
|
||||
|
||||
input:disabled {
|
||||
background-color: transparent;
|
||||
border-color: transparent;
|
||||
color: white;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
&:last-of-type {
|
||||
border-left: 1px solid #fff;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
</style>
|
||||
@@ -1,91 +0,0 @@
|
||||
<template>
|
||||
<section class="chartPicker">
|
||||
<ai-dialog-btn :modal="false" dialog-title="选择图表模板" :customFooter="false"
|
||||
@confirm="handleConfirm" @open="handleOpenDialog">
|
||||
<template #btn>
|
||||
<img class="pointer thumb" v-if="current.thumb" :src="current.thumb"/>
|
||||
<el-button v-else type="text">选择图表</el-button>
|
||||
</template>
|
||||
<div class="charts">
|
||||
<div class="item pointer" v-for="(tpl,i) in tpls" :key="i" :class="{selected:selected==tpl.type}"
|
||||
@click="selected=tpl.type">
|
||||
<img :src="tpl.thumb"/>
|
||||
<div v-text="tpl.label"/>
|
||||
</div>
|
||||
</div>
|
||||
</ai-dialog-btn>
|
||||
</section>
|
||||
</template>
|
||||
<script>
|
||||
import AiDialogBtn from "dui/packages/layout/AiDialogBtn";
|
||||
import {chartTpl} from "../config";
|
||||
|
||||
export default {
|
||||
name: "chartPicker",
|
||||
components: {AiDialogBtn},
|
||||
model: {
|
||||
prop: "value",
|
||||
event: "input"
|
||||
},
|
||||
props: {
|
||||
value: String,
|
||||
tpls: {default: () => chartTpl.map(e => e.list).flat()}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
selected: null
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
current: v => v.tpls.find(e => e.type == v.value) || {}
|
||||
},
|
||||
watch: {
|
||||
value(v) {
|
||||
v && this.$emit("config", this.$echartTpls[v])
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
handleConfirm() {
|
||||
this.$emit("input", this.selected)
|
||||
},
|
||||
handleOpenDialog() {
|
||||
this.selected = this.$copy(this.value)
|
||||
}
|
||||
},
|
||||
}
|
||||
</script>
|
||||
<style scoped lang="scss">
|
||||
.chartPicker {
|
||||
text-align: left;
|
||||
|
||||
.pointer {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.thumb {
|
||||
width: 200px;
|
||||
height: 90px;
|
||||
}
|
||||
|
||||
.charts {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr 1fr 1fr 1fr;
|
||||
gap: 8px;
|
||||
|
||||
.item {
|
||||
text-align: center;
|
||||
padding: 2px;
|
||||
border: 2px solid transparent;
|
||||
|
||||
& > img {
|
||||
width: 100%;
|
||||
height: 90px;
|
||||
}
|
||||
|
||||
&.selected, &:hover {
|
||||
border-color: #46f;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -1,89 +0,0 @@
|
||||
<template>
|
||||
<section class="componentConfig">
|
||||
<div class="layout-right__content--wrapper">
|
||||
<div class="layout-config__group">
|
||||
<h2>基础设置</h2>
|
||||
<div class="layout-config__item">
|
||||
<label>图表尺寸</label>
|
||||
<div class="layout-config__item--right">
|
||||
<el-input-number size="mini" :min="0" v-model="config.width" controls-position="right"/>
|
||||
<el-input-number size="mini" :min="0" v-model="config.height" controls-position="right"/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layout-config__item">
|
||||
<label>图表位置</label>
|
||||
<div class="layout-config__item--right">
|
||||
<el-input-number size="mini" :min="0" v-model="config.left" controls-position="right"/>
|
||||
<el-input-number size="mini" :min="0" v-model="config.top" controls-position="right"/>
|
||||
</div>
|
||||
</div>
|
||||
<config-item label="內边距">
|
||||
<el-input size="mini" v-model="config.padding" clearable placeholder="请输入符合css的padding合法值"/>
|
||||
</config-item>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layout-right__content--wrapper">
|
||||
<div class="layout-config__group">
|
||||
<h2>组件设置</h2>
|
||||
<config-extra v-model="config"/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layout-right__content--wrapper">
|
||||
<div class="layout-config__group">
|
||||
<h2>弹窗设置</h2>
|
||||
<config-item label="标题">
|
||||
<el-input size="mini" clearable placeholder="请输入弹窗标题" v-model="config.dialogTitle"/>
|
||||
</config-item>
|
||||
<config-item label="内容" v-if="!['table','AiDvTable','AiDvMap','linkageMap'].includes(config.type)">
|
||||
<ai-dialog-btn dialog-title="弹窗内容" text="打开编辑器" :modal="false">
|
||||
<ai-editor clearable placeholder="请输入弹窗内容" v-model="config.dialogContent" :instance="instance"/>
|
||||
</ai-dialog-btn>
|
||||
</config-item>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import ConfigItem from "./configItem";
|
||||
import ConfigExtra from "./configExtra.vue";
|
||||
|
||||
export default {
|
||||
name: 'componentConfig',
|
||||
components: {ConfigExtra, ConfigItem},
|
||||
props: {
|
||||
config: {default: () => ({})},
|
||||
instance: Function,
|
||||
dict: Object,
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.componentConfig {
|
||||
.table-config {
|
||||
& > div {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
width: 232px;
|
||||
|
||||
:deep( .el-select ) {
|
||||
width: 80px;
|
||||
}
|
||||
|
||||
.el-select {
|
||||
width: 100%;
|
||||
|
||||
.el-input {
|
||||
width: 100%;
|
||||
|
||||
:deep( input ) {
|
||||
width: 80px
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -1,239 +0,0 @@
|
||||
<script>
|
||||
import GroupItem from "./groupItem";
|
||||
import ConfigItem from "./configItem";
|
||||
import ChartPicker from "./chartPicker";
|
||||
import JsonEditor from "./jsonEditor";
|
||||
import {layers, monitorTypes} from "../config";
|
||||
import AiDvSummary from "dui/dv/layout/AiDvSummary/AiDvSummary";
|
||||
|
||||
export default {
|
||||
name: "configExtra",
|
||||
components: {JsonEditor, ChartPicker, ConfigItem, GroupItem},
|
||||
props: ['config'],
|
||||
model: {
|
||||
prop: 'config',
|
||||
event: 'input'
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
borderList: ['border0', 'border1', 'border2', 'border3', 'border4', 'border5', 'border6', 'border7', 'border8', 'border9', 'border10',
|
||||
'border11', 'border12', 'border13', 'border14', 'border15'],//边框待选项
|
||||
layers, monitorTypes,
|
||||
tableStatus: [
|
||||
{label: '是', value: '1'},
|
||||
{label: '否', value: '0'}
|
||||
],
|
||||
positionList: [
|
||||
{label: "左上", id: "lt"},
|
||||
{label: "右上", id: "rt"},
|
||||
{label: "左下", id: "lb"},
|
||||
{label: "右下", id: "rb"}
|
||||
],
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
summaryOps: () => Object.keys(AiDvSummary.components).map(e => ({label: e, id: e})),
|
||||
values: v => v.config?.[v.config?.dataType] || v.config.data
|
||||
},
|
||||
watch: {
|
||||
values: {
|
||||
immediate: true, deep: true,
|
||||
handler() {
|
||||
if (this.config.type === 'AiDvTable') {
|
||||
this.config.config = this.values?.map((v, i) => {
|
||||
return {
|
||||
color: this.config.config?.[i]?.color || '',
|
||||
width: this.config.config?.[i]?.width || '',
|
||||
align: this.config.config?.[i]?.align || '',
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<section class="configExtra">
|
||||
<config-item label="标题">
|
||||
<el-input v-model="config.summaryTitle" size="mini" v-if="config.display === 'summary2'" placeholder="请输入标题"/>
|
||||
<el-input v-else v-model="config.title" size="mini" placeholder="请输入标题"/>
|
||||
</config-item>
|
||||
<config-item label="边框" v-if="config.type !== 'display'">
|
||||
<el-select size="mini" v-model="config.border" placeholder="请选择边框" clearable>
|
||||
<el-option
|
||||
v-for="(item, index) in borderList"
|
||||
:key="index"
|
||||
:label="item"
|
||||
:value="item">
|
||||
</el-option>
|
||||
</el-select>
|
||||
</config-item>
|
||||
<config-item label="图表模板">
|
||||
<chart-picker v-model="config.type" :tpls="layers" @input="v=>config.echartOps=$echartTpls[v]"/>
|
||||
</config-item>
|
||||
<template v-if="/(AiDvMap|linkageMap)/.test(config.type)">
|
||||
<config-item label="地图数据(geoJSON)">
|
||||
<el-input v-model="config.geoJson" size="mini" clearable placeholder="请输入geoJson的URL地址"/>
|
||||
</config-item>
|
||||
</template>
|
||||
<template v-if="/linkageMap/.test(config.type)">
|
||||
<config-item v-for="(item,i) in config.summaryConfigs" :key="i" :label="`统计${i+1}`">
|
||||
<ai-select placeholder="请选择位置" v-model="item.pos" :select-list="positionList" size="mini"/>
|
||||
<ai-select placeholder="请选择类型" v-model="item.display" :select-list="summaryOps" size="mini"/>
|
||||
</config-item>
|
||||
</template>
|
||||
<template v-if="/tabs/.test(config.type)">
|
||||
<group-item v-for="(tab,i) in values" :key="i" :label="i">
|
||||
<group-item v-for="(comp,j) in tab" :key="j" :label="comp.name">
|
||||
<config-extra v-model="tab[j]"/>
|
||||
</group-item>
|
||||
</group-item>
|
||||
</template>
|
||||
<template v-if="/Chart/.test(config.type)">
|
||||
<config-item label="图表配置项" top-label>
|
||||
<json-editor v-model="config.echartOps"/>
|
||||
</config-item>
|
||||
</template>
|
||||
<config-item label="视频地址" v-if="config.type === 'video'">
|
||||
<el-input v-model="config.src" size="mini"/>
|
||||
</config-item>
|
||||
<config-item label="图片URL" v-if="config.type=='img'">
|
||||
<el-input v-model="config.src" size="mini" clearable placeholder="请输入图片URL"/>
|
||||
</config-item>
|
||||
<config-item label="视频类型" v-if="config.type === 'monitor'">
|
||||
<ai-select size="mini" v-model="config.monitorType" :select-list="monitorTypes"/>
|
||||
</config-item>
|
||||
<config-item label="样式" v-if="config.type === 'AiRanking'">
|
||||
<el-select size="mini" v-model="config.subType" placeholder="请选择样式" clearable>
|
||||
<el-option label="样式1" value="Ranking1"></el-option>
|
||||
<el-option label="样式2" value="Ranking2"></el-option>
|
||||
<el-option label="样式3" value="Ranking3"></el-option>
|
||||
</el-select>
|
||||
</config-item>
|
||||
<template v-if="config.type === 'table' || config.type === 'AiDvTable'">
|
||||
<config-item label="显示排名">
|
||||
<el-select size="mini" v-model="config.isShowIndex" placeholder="请选择" clearable>
|
||||
<el-option
|
||||
v-for="(item, index) in tableStatus"
|
||||
:key="index"
|
||||
:label="item.label"
|
||||
:value="item.value">
|
||||
</el-option>
|
||||
</el-select>
|
||||
</config-item>
|
||||
<config-item label="斑马纹" v-if="config.type === 'AiDvTable'">
|
||||
<el-select size="mini" v-model="config.stripe" placeholder="请选择" clearable>
|
||||
<el-option
|
||||
label="是"
|
||||
value="1">
|
||||
</el-option>
|
||||
<el-option
|
||||
label="否"
|
||||
value="0">
|
||||
</el-option>
|
||||
</el-select>
|
||||
</config-item>
|
||||
<config-item label="简易样式" v-if="config.type === 'AiDvTable'">
|
||||
<el-select size="mini" v-model="config.simple" placeholder="请选择" clearable>
|
||||
<el-option
|
||||
label="是"
|
||||
value="1">
|
||||
</el-option>
|
||||
<el-option
|
||||
label="否"
|
||||
value="0">
|
||||
</el-option>
|
||||
</el-select>
|
||||
</config-item>
|
||||
<config-item label="表格行数" v-if="config.type !== 'AiDvTable'">
|
||||
<el-input-number size="mini" style="width: 232px" :min="0" v-model="config.rowNum" controls-position="right"/>
|
||||
</config-item>
|
||||
<config-item v-if="config.type === 'AiDvTable'" v-for="(item, i) in config.config" :key="i" :label="`第${i+1}列`">
|
||||
<el-select size="mini" style="width: 80px;" v-model="item.align" placeholder="请选择" clearable>
|
||||
<el-option label="居中" value="center"></el-option>
|
||||
<el-option label="居左" value="left"></el-option>
|
||||
<el-option label="居右" value="right"></el-option>
|
||||
</el-select>
|
||||
<el-color-picker v-model="item.color" class="mar-h10" size="mini"/>
|
||||
<el-input-number v-model="item.width" label="描述文字" controls-position="right" size="mini"/>
|
||||
</config-item>
|
||||
</template>
|
||||
<template v-if="config.type === 'map'">
|
||||
<div class="layout-config__item">
|
||||
<label>遮罩层</label>
|
||||
<div class="layout-config__item--right">
|
||||
<el-select size="mini" v-model="config.mask" placeholder="请选择" clearable>
|
||||
<el-option label="是" value="1"></el-option>
|
||||
<el-option label="否" value="2"></el-option>
|
||||
</el-select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layout-config__item">
|
||||
<label>地图图层</label>
|
||||
<div class="layout-config__item--right">
|
||||
<el-select size="mini" v-model="config.layers" placeholder="请选择" clearable>
|
||||
<el-option label="地图" value="vector"/>
|
||||
<el-option label="卫星" value="satellite"/>
|
||||
</el-select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layout-config__item">
|
||||
<label>选择地区</label>
|
||||
<div class="layout-config__item--right">
|
||||
<AiAreaGet :instance="instance" :valueLevel="3" v-model="config.areaId" placeholder="地图展示的中心"/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layout-config__item">
|
||||
<label>限制地区</label>
|
||||
<div class="layout-config__item--right">
|
||||
<ai-select v-model="config.limitArea" :selectList="dict.getDict('yesOrNo')"/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layout-config__item">
|
||||
<label>显示标签</label>
|
||||
<div class="layout-config__item--right">
|
||||
<ai-select v-model="config.alwaysShow" :selectList="dict.getDict('yesOrNo')"/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layout-config__item">
|
||||
<label>展示光轨</label>
|
||||
<div class="layout-config__item--right">
|
||||
<ai-select v-model="config.pulseLines" :selectList="dict.getDict('yesOrNo')"/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layout-config__item layout-config__item--input">
|
||||
<label>地图样式</label>
|
||||
<div class="layout-config__item--right">
|
||||
<el-input size="mini" v-model="config.mapStyle" clearable placeholder="请输入地图样式ID,从UI处获取.."/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layout-config__item layout-config__item--input">
|
||||
<label>3D地图</label>
|
||||
<div class="layout-config__item--right">
|
||||
<ai-select v-model="config.is3d" :selectList="dict.getDict('yesOrNo')"/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layout-config__item layout-config__item--input" v-if="config.is3d==1">
|
||||
<label>3D环绕</label>
|
||||
<div class="layout-config__item--right">
|
||||
<ai-select v-model="config.is3dAround" :selectList="dict.getDict('yesOrNo')"/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layout-config__item layout-config__item--input">
|
||||
<label>显示图例</label>
|
||||
<div class="layout-config__item--right">
|
||||
<ai-select v-model="config.showPingchangMapLegend" :selectList="dict.getDict('yesOrNo')"/>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<config-item label="数据汇总" v-if="config.type === 'summary'">
|
||||
<ai-select size="mini" v-model="config.display" placeholder="请选择类型" :select-list="summaryOps"/>
|
||||
</config-item>
|
||||
</section>
|
||||
</template>
|
||||
|
||||
<style scoped lang="scss">
|
||||
|
||||
</style>
|
||||
@@ -1,111 +0,0 @@
|
||||
<template>
|
||||
<section class="configItem" :class="{topLabel}">
|
||||
<label :class="{bold}" v-text="label"/>
|
||||
<div class="content fill">
|
||||
<slot v-if="$slots.default"/>
|
||||
<div v-else-if="value" v-html="value"/>
|
||||
</div>
|
||||
</section>
|
||||
</template>
|
||||
<script>
|
||||
export default {
|
||||
name: "configItem",
|
||||
props: {
|
||||
label: String,
|
||||
value: {default: null},
|
||||
topLabel: Boolean,
|
||||
bold: Boolean
|
||||
},
|
||||
}
|
||||
</script>
|
||||
<style scoped lang="scss">
|
||||
.configItem {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
margin-bottom: 10px;
|
||||
|
||||
|
||||
&:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
& > label {
|
||||
flex-shrink: 0;
|
||||
width: 60px;
|
||||
color: #FFFFFF;
|
||||
font-size: 12px;
|
||||
text-align: right;
|
||||
|
||||
&.bold {
|
||||
font-weight: bold;
|
||||
}
|
||||
}
|
||||
|
||||
.el-select .el-tag {
|
||||
color: #fff;
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
.el-input__icon {
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.el-switch__label {
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.el-select, .ai-select {
|
||||
width: 100%;
|
||||
|
||||
&:last-child {
|
||||
margin-right: 0;
|
||||
}
|
||||
|
||||
input {
|
||||
background: #262C33;
|
||||
font-size: 12px;
|
||||
color: #fff;
|
||||
border: 1px solid #030411;
|
||||
}
|
||||
|
||||
.el-input__icon {
|
||||
color: #fff;
|
||||
}
|
||||
}
|
||||
|
||||
:deep(.el-collapse) {
|
||||
height: 18px;
|
||||
}
|
||||
|
||||
:deep(.content) {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: flex-end;
|
||||
text-align: right;
|
||||
margin-left: 27px;
|
||||
|
||||
input, textarea {
|
||||
background: #262C33;
|
||||
font-size: 12px;
|
||||
color: #fff;
|
||||
border: 1px solid #030411;
|
||||
}
|
||||
}
|
||||
|
||||
&.topLabel {
|
||||
flex-direction: column;
|
||||
align-items: normal;
|
||||
|
||||
& > label {
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.content {
|
||||
flex-shrink: 0;
|
||||
width: 100%;
|
||||
margin-left: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -1,119 +0,0 @@
|
||||
<template>
|
||||
<section class="datasourcePicker">
|
||||
<config-item label="数据类型">
|
||||
<ai-select v-model="source.dataType" placeholder="请选择数据类型" :select-list="dataTypes"/>
|
||||
</config-item>
|
||||
<div class="codeEditor" v-if="['htmlData'].includes(source.dataType)">
|
||||
<ai-dialog-btn :modal="false" dialog-title="编辑器" :customFooter="false"
|
||||
@confirm="changeData(JSON.parse(content))" @open="content=contentstr">
|
||||
<code-editor slot="btn" readonly :value="contentstr" :lang="dataLang" theme="github" width="100%" height="250"/>
|
||||
<code-editor v-model="content" :lang="dataLang" theme="github" width="100%" height="440" wrap/>
|
||||
</ai-dialog-btn>
|
||||
</div>
|
||||
<template v-else-if="source.dataType === 'staticData'">
|
||||
<config-item label="设置数据" topLabel>
|
||||
<json-editor v-model="options.staticData" mainMenuBar/>
|
||||
</config-item>
|
||||
</template>
|
||||
<config-item v-else-if="source.dataType === 'dynamicData'" label="数据源">
|
||||
<ai-select v-model="source.sourceDataId" placeholder="请选择数据源" :instance="instance"
|
||||
:prop="{label:'description'}" @change="changeData"
|
||||
action="/app/appdiylargescreen/allDatasourceByPage"/>
|
||||
</config-item>
|
||||
<config-item label="接口地址" v-else-if="source.dataType === 'apiData'">
|
||||
<el-input size="small" v-model="source.api" @change="changeData" placeholder="请输入数据接口URL"/>
|
||||
</config-item>
|
||||
</section>
|
||||
</template>
|
||||
<script>
|
||||
import AiDialogBtn from "dui/packages/layout/AiDialogBtn.vue";
|
||||
import ConfigItem from "./configItem.vue";
|
||||
import CodeEditor from 'bin-ace-editor'
|
||||
import 'brace/mode/json'
|
||||
import 'brace/snippets/json';
|
||||
import 'brace/theme/github';
|
||||
import 'brace/theme/monokai';
|
||||
import JsonEditor from "./jsonEditor.vue";
|
||||
import {DvCompData} from "dui/dv";
|
||||
|
||||
export default {
|
||||
name: "datasourcePicker",
|
||||
components: {JsonEditor, ConfigItem, AiDialogBtn, CodeEditor},
|
||||
model: {
|
||||
event: "input",
|
||||
prop: "options"
|
||||
},
|
||||
props: {
|
||||
options: Object,
|
||||
instance: Function
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
dataTypes: Object.entries(DvCompData.types).map(e => ({id: e[0], label: e[1]})),
|
||||
content: "",
|
||||
loading: false,
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
contentstr: v => JSON.stringify(v.options.staticData),
|
||||
dataLang: v => v.options.dataType == 'htmlData' ? 'html' : 'json',
|
||||
source: {
|
||||
set(v) {
|
||||
this.$emit("input", v)
|
||||
},
|
||||
get() {
|
||||
return this.options
|
||||
}
|
||||
},
|
||||
staticDataOps() {
|
||||
const columnProp = "name", ops = {colConfigs: [], tableData: []}
|
||||
if (Array.isArray(this.options.staticData)) {
|
||||
const columns = []
|
||||
ops.colConfigs = []
|
||||
this.options.staticData.map((row, i) => {
|
||||
const prop = `c${i || ""}`
|
||||
ops.colConfigs.push({label: row[columnProp] || row.key, prop})
|
||||
Object.entries(row).map(([k, v]) => {
|
||||
if (/^v/.test(k) && k != "value") {
|
||||
const item = ops.tableData[k.substring(1) || 0] || {}
|
||||
item[prop] = v
|
||||
ops.tableData[k.substring(1) || 0] = item
|
||||
} else if (![columnProp, 'key'].includes(k)) {
|
||||
const index = columns.findIndex(e => k == e)
|
||||
if (index > -1) {
|
||||
const item = ops.tableData[index] || {}
|
||||
item[prop] = v
|
||||
ops.tableData[index] = item
|
||||
} else {
|
||||
columns.push(k)
|
||||
const newIndex = columns.length - 1
|
||||
const item = ops.tableData[newIndex] || {}
|
||||
item[prop] = v
|
||||
ops.tableData[newIndex] = item
|
||||
}
|
||||
}
|
||||
})
|
||||
})
|
||||
ops.tableData = ops.tableData.map(e => ({...e, $cellEdit: false}))
|
||||
}
|
||||
return ops
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
changeData(sdata) {
|
||||
this.source.dataType == 'staticData' ? this.source.staticData = sdata :
|
||||
new DvCompData(this.source, this.instance).getData().then(data => {
|
||||
this.source[this.source.dataType] = data
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style scoped lang="scss">
|
||||
.datasourcePicker {
|
||||
.codeEditor {
|
||||
position: relative;
|
||||
padding-left: 10px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -1,32 +0,0 @@
|
||||
<script>
|
||||
export default {
|
||||
name: "groupItem",
|
||||
props: ['label']
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<section class="groupItem">
|
||||
<h2 v-if="label" v-text="label"/>
|
||||
<slot/>
|
||||
</section>
|
||||
</template>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.groupItem {
|
||||
padding: 10px 10px 20px;
|
||||
border-bottom: 1px solid #000000;
|
||||
|
||||
&:last-child {
|
||||
border: none;
|
||||
}
|
||||
|
||||
|
||||
& > h2 {
|
||||
margin-bottom: 20px;
|
||||
color: #FFFFFF;
|
||||
font-size: 15px;
|
||||
font-weight: 700;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -1,98 +0,0 @@
|
||||
<script>
|
||||
export default {
|
||||
name: "jsonEditor",
|
||||
model: {
|
||||
event: "input",
|
||||
prop: "value"
|
||||
},
|
||||
props: {
|
||||
value: {default: () => ({})}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
editor: null,
|
||||
fullscreen: false
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
value(v) {
|
||||
const content = this.editor.get()
|
||||
if (v && content && JSON.stringify(v) != JSON.stringify(content)) {
|
||||
this.editor?.set(v)
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
init() {
|
||||
const {JSONEditor} = window
|
||||
if (!this.editor && JSONEditor) {
|
||||
const {mode, search, mainMenuBar, navigationBar} = this.$attrs
|
||||
this.editor = new JSONEditor(this.$el, {
|
||||
modes: ['code', 'form', 'tree'],
|
||||
language: 'zh-CN', mode, search, mainMenuBar, navigationBar, statusBar: true,
|
||||
onChange: () => {
|
||||
this.$emit("input", this.editor.get())
|
||||
},
|
||||
}, this.value)
|
||||
} else setTimeout(() => this.init(), 500)
|
||||
const fullscreenBtn = this.$el.querySelector(".fullscreenBtn")
|
||||
if (!fullscreenBtn) {
|
||||
const btn = document.createElement("div")
|
||||
btn.className = "fullscreenBtn el-icon-full-screen"
|
||||
btn.onclick = evt => {
|
||||
evt.stopPropagation()
|
||||
this.fullscreen = !this.fullscreen
|
||||
}
|
||||
this.$el.appendChild(btn)
|
||||
}
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.init()
|
||||
},
|
||||
beforeDestroy() {
|
||||
this.editor?.destroy()
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<section class="jsoneditor" @contextmenu.stop :class="{fullscreen}"/>
|
||||
</template>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.jsoneditor {
|
||||
position: relative;
|
||||
|
||||
&.fullscreen {
|
||||
position: fixed;
|
||||
left: 50%;
|
||||
top: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
width: 80vw;
|
||||
height: 80vh;
|
||||
z-index: 202403221146;
|
||||
}
|
||||
|
||||
:deep(.ace-jsoneditor) {
|
||||
font-size: 14px !important;
|
||||
}
|
||||
|
||||
:deep(.fullscreenBtn) {
|
||||
position: absolute;
|
||||
z-index: 202403221132;
|
||||
right: 6px;
|
||||
top: 0;
|
||||
height: 35px;
|
||||
color: white;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
cursor: pointer;
|
||||
|
||||
&:hover {
|
||||
color: rgba(white, .6);
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -1,16 +1,22 @@
|
||||
<template>
|
||||
<section class="preview">
|
||||
<ai-dv-wrapper :views="[{label: '返回'}]" :theme="config.theme" @change="handleBack" v-if="screenId" :title="info.name" :background="bgImg" :titleSize="config.titleSize">
|
||||
<ai-dv-viewer :urlPrefix="urlPrefix" :instance="instance" :dict="dict" :id="screenId"/>
|
||||
<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 {mapActions} from "vuex"
|
||||
import AppGigscreenViewer from "../../viewer/AppGigscreenViewer";
|
||||
|
||||
export default {
|
||||
name: "preview",
|
||||
components: {AppGigscreenViewer},
|
||||
props: {
|
||||
instance: Function,
|
||||
dict: Object,
|
||||
@@ -21,8 +27,7 @@ export default {
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
screenId: v => v.$route.query.id,
|
||||
bgImg: v => v.config.theme == 1 ? 'https://cdn.cunwuyun.cn/dvcp/dv/img/dj_bg.png' : (v.config.backgroundImage?.[0]?.url || "")
|
||||
screenId: v => v.$route.query.id
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
@@ -31,19 +36,14 @@ export default {
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
...mapActions(['closePage']),
|
||||
getDvData() {
|
||||
let {id} = this.$route.query
|
||||
this.instance.post(`/app/appdiylargescreen/queryLargeScreenDetailById?id=${id}`).then(res => {
|
||||
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
|
||||
}
|
||||
})
|
||||
},
|
||||
handleBack() {
|
||||
this.$router.back()
|
||||
this.closePage()
|
||||
}
|
||||
},
|
||||
created() {
|
||||
@@ -1,794 +0,0 @@
|
||||
/**
|
||||
* 大屏设计资产库,模板设置中心
|
||||
*
|
||||
*/
|
||||
export const chartTpl = [{
|
||||
label: '柱状图', type: 'bar', list: [{
|
||||
code: 'widget-linechart',
|
||||
type: 'barChart1',
|
||||
label: '柱状图1',
|
||||
title: '柱状图',
|
||||
border: 'border6',
|
||||
icon: 'icontext_box',
|
||||
value: '',
|
||||
thumb: 'https://cdn.cunwuyun.cn/dvcp/dv/tpl/bar1.png',
|
||||
width: 500,
|
||||
sourceDataId: '',
|
||||
height: 300,
|
||||
dataX: '',
|
||||
zIndex: 1,
|
||||
dataY: [],
|
||||
top: 0,
|
||||
left: 0,
|
||||
api: '',
|
||||
apiData: [],
|
||||
dataType: 'staticData',
|
||||
staticData: [{name: '阿斯达', v1: 23}, {name: '水电费', v1: 12}, {name: '凡哥', v1: 67}, {name: '党费', v1: 98}],
|
||||
config: 'barChart1',
|
||||
dynamicData: []
|
||||
}, {
|
||||
code: 'widget-linechart',
|
||||
type: 'barChart2',
|
||||
label: '柱状图2',
|
||||
icon: 'icontext_box',
|
||||
value: '',
|
||||
title: '柱状图2',
|
||||
width: 500,
|
||||
border: 'border6',
|
||||
sourceDataId: '',
|
||||
height: 300,
|
||||
thumb: 'https://cdn.cunwuyun.cn/dvcp/dv/tpl/bar2.png',
|
||||
dataX: '',
|
||||
dataY: [],
|
||||
top: 0,
|
||||
zIndex: 1,
|
||||
left: 0,
|
||||
dataType: 'staticData',
|
||||
api: '',
|
||||
apiData: [],
|
||||
staticData: [{name: '阿斯达', v1: 23}, {name: '水电费', v1: 12}, {name: '凡哥', v1: 67}, {name: '党费', v1: 98}],
|
||||
config: 'barChart2',
|
||||
dynamicData: []
|
||||
}, {
|
||||
code: 'widget-linechart',
|
||||
type: 'barChart3',
|
||||
label: '柱状图3',
|
||||
title: '柱状图3',
|
||||
icon: 'icontext_box',
|
||||
value: '',
|
||||
width: 500,
|
||||
sourceDataId: '',
|
||||
height: 300,
|
||||
thumb: 'https://cdn.cunwuyun.cn/dvcp/dv/tpl/bar3.png',
|
||||
dataX: '',
|
||||
dataY: [],
|
||||
border: 'border6',
|
||||
top: 0,
|
||||
left: 0,
|
||||
zIndex: 1,
|
||||
dataType: 'staticData',
|
||||
api: '',
|
||||
apiData: [],
|
||||
staticData: [{name: '阿斯达', v1: 23}, {name: '水电费', v1: 12}, {name: '凡哥', v1: 67}, {name: '党费', v1: 98}],
|
||||
config: 'barChart3',
|
||||
dynamicData: []
|
||||
}, {
|
||||
code: 'widget-linechart',
|
||||
type: 'barChart5',
|
||||
label: '柱状图4',
|
||||
title: '柱状图4',
|
||||
icon: 'icontext_box',
|
||||
value: '',
|
||||
width: 500,
|
||||
sourceDataId: '',
|
||||
height: 300,
|
||||
dataX: '',
|
||||
dataY: [],
|
||||
zIndex: 1,
|
||||
thumb: 'https://cdn.cunwuyun.cn/dvcp/dv/tpl/bar5.png',
|
||||
top: 0,
|
||||
left: 0,
|
||||
border: 'border6',
|
||||
api: '',
|
||||
apiData: [],
|
||||
dataType: 'staticData',
|
||||
staticData: [{name: '阿斯达', v1: 23}, {name: '水电费', v1: 12}, {name: '凡哥', v1: 67}, {name: '党费', v1: 98}],
|
||||
config: 'barChart5',
|
||||
dynamicData: []
|
||||
}, {
|
||||
code: 'widget-linechart',
|
||||
type: 'barChart7',
|
||||
label: '柱状图5',
|
||||
title: '柱状图5',
|
||||
icon: 'icontext_box',
|
||||
value: '',
|
||||
width: 500,
|
||||
sourceDataId: '',
|
||||
height: 300,
|
||||
thumb: 'https://cdn.cunwuyun.cn/dvcp/dv/tpl/bar7.png',
|
||||
dataX: '',
|
||||
zIndex: 1,
|
||||
dataY: [],
|
||||
top: 0,
|
||||
left: 0,
|
||||
api: '',
|
||||
apiData: [],
|
||||
dataType: 'staticData',
|
||||
staticData: [{name: '阿斯达', v1: 23}, {name: '水电费', v1: 12}, {name: '凡哥', v1: 67}, {name: '党费', v1: 98}],
|
||||
config: 'barChart7',
|
||||
dynamicData: []
|
||||
}, {
|
||||
code: 'widget-linechart',
|
||||
type: 'barChart8',
|
||||
label: '柱状图6',
|
||||
title: '柱状图6',
|
||||
icon: 'icontext_box',
|
||||
value: '',
|
||||
width: 500,
|
||||
sourceDataId: '',
|
||||
border: 'border6',
|
||||
height: 300,
|
||||
thumb: 'https://cdn.cunwuyun.cn/dvcp/dv/tpl/bar8.png',
|
||||
dataX: '',
|
||||
dataY: [],
|
||||
zIndex: 1,
|
||||
top: 0,
|
||||
left: 0,
|
||||
api: '',
|
||||
apiData: [],
|
||||
dataType: 'staticData',
|
||||
staticData: [{name: '阿斯达', v1: 23}, {name: '水电费', v1: 12}, {name: '凡哥', v1: 67}, {name: '党费', v1: 98}],
|
||||
config: 'barChart8',
|
||||
dynamicData: []
|
||||
}, {
|
||||
code: 'widget-linechart',
|
||||
type: 'barChart9',
|
||||
label: '柱状图7',
|
||||
title: '柱状图7',
|
||||
border: 'border6',
|
||||
icon: 'icontext_box',
|
||||
value: '',
|
||||
width: 500,
|
||||
thumb: 'https://cdn.cunwuyun.cn/dvcp/dv/tpl/bar9.png',
|
||||
sourceDataId: '',
|
||||
height: 300,
|
||||
dataX: '',
|
||||
dataY: [],
|
||||
zIndex: 1,
|
||||
top: 0,
|
||||
left: 0,
|
||||
api: '',
|
||||
apiData: [],
|
||||
dataType: 'staticData',
|
||||
staticData: [{name: '阿斯达', v1: 23}, {name: '水电费', v1: 12}, {name: '凡哥', v1: 67}, {name: '党费', v1: 98}],
|
||||
config: 'barChart9',
|
||||
dynamicData: []
|
||||
}, {
|
||||
type: 'barChart10',
|
||||
label: '柱状图8',
|
||||
title: '柱状图8',
|
||||
border: 'border13',
|
||||
width: 500,
|
||||
thumb: 'https://cdn.cunwuyun.cn/dvcp/dv/tpl/bar10.png',
|
||||
height: 300,
|
||||
dataType: 'staticData',
|
||||
staticData: [{name: '阿斯达', v1: 23}, {name: '水电费', v1: 12}],
|
||||
config: 'barChart10'
|
||||
},
|
||||
]
|
||||
}, {
|
||||
label: '折线图', type: 'line', list: [{
|
||||
code: 'widget-linechart',
|
||||
type: 'lineChart1',
|
||||
label: '折线图1',
|
||||
title: '折线图1',
|
||||
border: 'border6',
|
||||
icon: 'icontext_box',
|
||||
value: '',
|
||||
width: 500,
|
||||
height: 300,
|
||||
top: 0,
|
||||
left: 0,
|
||||
zIndex: 1,
|
||||
api: '',
|
||||
apiData: [],
|
||||
thumb: 'https://cdn.cunwuyun.cn/dvcp/dv/tpl/line1.png',
|
||||
dataX: '',
|
||||
dataY: [],
|
||||
dataType: 'staticData',
|
||||
staticData: [{name: '阿斯达', v1: 23, v2: 33}, {name: '水电费', v1: 12, v2: 34}, {
|
||||
name: '凡哥',
|
||||
v1: 67,
|
||||
v2: 25
|
||||
}, {name: '党费', v1: 98, v2: 85}],
|
||||
config: 'lineChart1',
|
||||
sourceDataId: '',
|
||||
dynamicData: []
|
||||
}, {
|
||||
code: 'widget-linechart',
|
||||
type: 'lineChart2',
|
||||
label: '折线图2',
|
||||
title: '折线图2',
|
||||
border: 'border6',
|
||||
icon: 'icontext_box',
|
||||
value: '',
|
||||
width: 500,
|
||||
thumb: 'https://cdn.cunwuyun.cn/dvcp/dv/tpl/line2.png',
|
||||
height: 300,
|
||||
top: 0,
|
||||
left: 0,
|
||||
dataX: '',
|
||||
dataY: [],
|
||||
zIndex: 1,
|
||||
api: '',
|
||||
apiData: [],
|
||||
dataType: 'staticData',
|
||||
staticData: [{name: '阿斯达', v1: 23, v2: 33}, {name: '水电费', v1: 12, v2: 34}, {
|
||||
name: '凡哥',
|
||||
v1: 67,
|
||||
v2: 25
|
||||
}, {name: '党费', v1: 98, v2: 85}],
|
||||
config: 'lineChart2',
|
||||
sourceDataId: '',
|
||||
dynamicData: []
|
||||
}, {
|
||||
code: 'widget-linechart',
|
||||
type: 'lineChart3',
|
||||
label: '折线图3',
|
||||
title: '折线图3',
|
||||
icon: 'icontext_box',
|
||||
border: 'border6',
|
||||
value: '',
|
||||
width: 500,
|
||||
height: 300,
|
||||
zIndex: 1,
|
||||
thumb: 'https://cdn.cunwuyun.cn/dvcp/dv/tpl/line3.png',
|
||||
top: 0,
|
||||
left: 0,
|
||||
dataX: '',
|
||||
dataY: [],
|
||||
api: '',
|
||||
apiData: [],
|
||||
dataType: 'staticData',
|
||||
staticData: [{name: '阿斯达', v1: 23, v2: 33}, {name: '水电费', v1: 12, v2: 34}, {
|
||||
name: '凡哥',
|
||||
v1: 67,
|
||||
v2: 25
|
||||
}, {name: '党费', v1: 98, v2: 85}],
|
||||
config: 'lineChart3',
|
||||
sourceDataId: '',
|
||||
dynamicData: []
|
||||
}, {
|
||||
code: 'widget-linechart',
|
||||
type: 'lineChart4',
|
||||
label: '折线图4',
|
||||
title: '折线图4',
|
||||
icon: 'icontext_box',
|
||||
value: '',
|
||||
border: 'border6',
|
||||
width: 500,
|
||||
height: 300,
|
||||
zIndex: 1,
|
||||
thumb: 'https://cdn.cunwuyun.cn/dvcp/dv/tpl/line4.png',
|
||||
top: 0,
|
||||
left: 0,
|
||||
dataX: '',
|
||||
dataY: [],
|
||||
api: '',
|
||||
apiData: [],
|
||||
dataType: 'staticData',
|
||||
staticData: [{name: '阿斯达', v1: 23, v2: 33}, {name: '水电费', v1: 12, v2: 34}, {
|
||||
name: '凡哥',
|
||||
v1: 67,
|
||||
v2: 25
|
||||
}, {name: '党费', v1: 98, v2: 85}],
|
||||
config: 'lineChart4',
|
||||
sourceDataId: '',
|
||||
dynamicData: []
|
||||
}, {
|
||||
code: 'widget-linechart',
|
||||
type: 'lineChart5',
|
||||
label: '折线图5',
|
||||
title: '折线图5',
|
||||
icon: 'icontext_box',
|
||||
value: '',
|
||||
border: 'border6',
|
||||
width: 500,
|
||||
height: 300,
|
||||
zIndex: 1,
|
||||
top: 0,
|
||||
left: 0,
|
||||
dataX: '',
|
||||
thumb: 'https://cdn.cunwuyun.cn/dvcp/dv/tpl/line5.png',
|
||||
dataY: [],
|
||||
api: '',
|
||||
apiData: [],
|
||||
dataType: 'staticData',
|
||||
staticData: [{name: '阿斯达', v1: 23, v2: 33}, {name: '水电费', v1: 12, v2: 34}, {
|
||||
name: '凡哥',
|
||||
v1: 67,
|
||||
v2: 25
|
||||
}, {name: '党费', v1: 98, v2: 85}],
|
||||
config: 'lineChart5',
|
||||
sourceDataId: '',
|
||||
dynamicData: []
|
||||
}]
|
||||
},
|
||||
{
|
||||
label: '饼图', type: 'pie', list: [{
|
||||
code: 'widget-linechart',
|
||||
type: 'pieChart2',
|
||||
config: 'pieChart2',
|
||||
label: '饼图',
|
||||
title: '饼图',
|
||||
icon: 'icontext_box',
|
||||
value: '',
|
||||
border: 'border6',
|
||||
width: 500,
|
||||
height: 300,
|
||||
zIndex: 1,
|
||||
top: 0,
|
||||
left: 0,
|
||||
thumb: 'https://cdn.cunwuyun.cn/dvcp/dv/tpl/pie.png',
|
||||
dataX: '',
|
||||
dataY: [],
|
||||
api: '',
|
||||
apiData: [],
|
||||
dataType: 'staticData',
|
||||
staticData: [{name: '阿斯达', v1: 23, v2: 33}, {name: '水电费', v1: 12, v2: 34}, {
|
||||
name: '凡哥',
|
||||
v1: 67,
|
||||
v2: 25
|
||||
}, {name: '党费', v1: 98, v2: 85}],
|
||||
sourceDataId: '',
|
||||
dynamicData: []
|
||||
}, {
|
||||
code: 'widget-linechart',
|
||||
type: 'pieChart1',
|
||||
label: '饼图',
|
||||
title: '饼图',
|
||||
icon: 'icontext_box',
|
||||
value: '',
|
||||
border: 'border6',
|
||||
width: 500,
|
||||
height: 300,
|
||||
zIndex: 1,
|
||||
top: 0,
|
||||
left: 0,
|
||||
thumb: 'https://cdn.cunwuyun.cn/dvcp/dv/tpl/pie.png',
|
||||
dataX: '',
|
||||
dataY: [],
|
||||
api: '',
|
||||
apiData: [],
|
||||
dataType: 'staticData',
|
||||
staticData: [{name: '阿斯达', v1: 23, v2: 33}, {name: '水电费', v1: 12, v2: 34}, {
|
||||
name: '凡哥',
|
||||
v1: 67,
|
||||
v2: 25
|
||||
}, {name: '党费', v1: 98, v2: 85}],
|
||||
config: 'pieChart1',
|
||||
sourceDataId: '',
|
||||
dynamicData: []
|
||||
}, {
|
||||
code: 'widget-linechart',
|
||||
type: 'pieChart3',
|
||||
label: '饼图',
|
||||
title: '饼图',
|
||||
icon: 'icontext_box',
|
||||
value: '',
|
||||
border: 'border6',
|
||||
width: 500,
|
||||
height: 300,
|
||||
zIndex: 1,
|
||||
top: 0,
|
||||
left: 0,
|
||||
thumb: 'https://cdn.cunwuyun.cn/dvcp/dv/tpl/pie.png',
|
||||
dataX: '',
|
||||
dataY: [],
|
||||
api: '',
|
||||
apiData: [],
|
||||
dataType: 'staticData',
|
||||
staticData: [{name: '阿斯达', v1: 23, v2: 33}, {name: '水电费', v1: 12, v2: 34}, {
|
||||
name: '凡哥',
|
||||
v1: 67,
|
||||
v2: 25
|
||||
}, {name: '党费', v1: 98, v2: 85}],
|
||||
config: 'pieChart3',
|
||||
sourceDataId: '',
|
||||
dynamicData: []
|
||||
}, {
|
||||
type: 'summary',
|
||||
label: '进度饼图',
|
||||
title: '进度饼图',
|
||||
border: 'border15',
|
||||
display: 'processPie',
|
||||
width: 500,
|
||||
height: 300,
|
||||
zIndex: 1,
|
||||
top: 0,
|
||||
left: 0,
|
||||
thumb: 'https://cdn.cunwuyun.cn/dvcp/dv/tpl/processPieChart.png',
|
||||
dataType: 'staticData',
|
||||
staticData: {name: '综合调处率', label: "累计调解成功", v1: 23, totalLabel: "累计排查受理", total: 33},
|
||||
},]
|
||||
}, {
|
||||
label: '关系图', type: 'graph', list: [{
|
||||
type: "graphChart1",
|
||||
label: "气泡图", title: "气泡图", border: 'border15',
|
||||
width: 500,
|
||||
height: 300,
|
||||
top: 0,
|
||||
left: 0,
|
||||
dataType: 'staticData',
|
||||
staticData: [],
|
||||
thumb: 'https://cdn.cunwuyun.cn/dvcp/dv/tpl/graphChart1.png',
|
||||
}]
|
||||
}]
|
||||
const maps = [{
|
||||
type: 'map',
|
||||
label: '地图',
|
||||
display: 'map',
|
||||
width: 840,
|
||||
height: 534,
|
||||
left: 0,
|
||||
top: 0,
|
||||
mask: '2',
|
||||
pulseLines: '1',
|
||||
mapStyle: "e51987628aee5206d4c9ca8c6e98b4f7",
|
||||
areaId: '',
|
||||
zIndex: 1,
|
||||
apiData: [],
|
||||
dataType: 'staticData',
|
||||
dynamicData: [],
|
||||
staticData: [{
|
||||
label: '中卫慧通', lng: 117.1339399, lat: 36.7190487,
|
||||
}],
|
||||
api: '',
|
||||
thumb: 'https://cdn.cunwuyun.cn/dvcp/dv/tpl/map.png',
|
||||
is3dAround: '0',
|
||||
limitArea: '0',
|
||||
layers: 'vector'
|
||||
}, {
|
||||
type: 'AiDvMap',
|
||||
label: 'echart地图',
|
||||
display: 'map',
|
||||
width: 840,
|
||||
height: 534,
|
||||
left: 0,
|
||||
top: 0,
|
||||
mask: '2',
|
||||
pulseLines: '1',
|
||||
mapStyle: "e51987628aee5206d4c9ca8c6e98b4f7",
|
||||
areaId: '',
|
||||
zIndex: 1,
|
||||
apiData: [],
|
||||
dataType: 'staticData',
|
||||
dynamicData: [],
|
||||
staticData: [{
|
||||
label: '中卫慧通', lng: 117.1339399, lat: 36.7190487,
|
||||
}],
|
||||
api: '',
|
||||
thumb: 'https://cdn.cunwuyun.cn/dvcp/dv/tpl/map.png',
|
||||
is3dAround: '0',
|
||||
limitArea: '0',
|
||||
}, {type: "linkageMap", label: "联动地图", width: 800, height: 964, top: 0, left: 560, thumb: "https://cdn.cunwuyun.cn/dvcp/dv/tpl/linkageMap.png", dataType: 'staticData'}]
|
||||
const customHtml = {
|
||||
label: "HTML块", type: "html", list: [{
|
||||
type: 'html',
|
||||
label: '自定义HTML',
|
||||
title: '自定义HTML',
|
||||
border: 'border0',
|
||||
width: 500,
|
||||
height: 300,
|
||||
top: 0,
|
||||
left: 0,
|
||||
thumb: 'https://cdn.cunwuyun.cn/dvcp/dv/tpl/pie.png',
|
||||
html: `<div style="width: 100%;height: 100%;background: #fff;text-align: center;line-height: 300px;font-size: 20px;color: #000;">自定义HTML</div>`
|
||||
}]
|
||||
}
|
||||
const tables = [{
|
||||
type: 'table',
|
||||
label: '表格',
|
||||
title: '表格',
|
||||
border: 'border6',
|
||||
width: 650,
|
||||
height: 400,
|
||||
zIndex: 1,
|
||||
thumb: 'https://cdn.cunwuyun.cn/dvcp/dv/tpl/table.png',
|
||||
dataX: '',
|
||||
dataY: [],
|
||||
rowNum: 7,
|
||||
isShowIndex: '1',
|
||||
sourceDataId: '',
|
||||
api: '',
|
||||
apiData: [],
|
||||
dataType: 'staticData',
|
||||
dynamicData: [],
|
||||
staticData: [{name: '列1', v: 23, v2: 3}, {name: '列2', v: 12, v2: 4}, {name: '列2', v: 12, v2: 4}]
|
||||
}, {
|
||||
type: 'AiDvTable',
|
||||
label: '新版表格',
|
||||
title: '新版表格',
|
||||
border: 'border6',
|
||||
width: 650,
|
||||
height: 400,
|
||||
zIndex: 1,
|
||||
thumb: 'https://cdn.cunwuyun.cn/dvcp/dv/tpl/table.png',
|
||||
dataX: '',
|
||||
dataY: [],
|
||||
rowNum: 7,
|
||||
stripe: '1',
|
||||
isShowIndex: '1',
|
||||
sourceDataId: '',
|
||||
api: '',
|
||||
config: [{
|
||||
width: '', color: '', align: ''
|
||||
}, {
|
||||
width: '', color: '', align: ''
|
||||
}, {
|
||||
width: '', color: '', align: ''
|
||||
}],
|
||||
apiData: [],
|
||||
dataType: 'staticData',
|
||||
dynamicData: [],
|
||||
staticData: [{name: '列1', v: 23, v2: 3}, {name: '列2', v: 12, v2: 4}, {name: '列2', v: 12, v2: 4}]
|
||||
}, {
|
||||
type: 'AiRanking',
|
||||
label: '排行榜',
|
||||
title: '排行榜',
|
||||
border: 'border6',
|
||||
width: 523,
|
||||
height: 400,
|
||||
zIndex: 1,
|
||||
thumb: 'https://cdn.cunwuyun.cn/dvcp/dv/tpl/table.png',
|
||||
dataX: '',
|
||||
dataY: [],
|
||||
rowNum: 7,
|
||||
subType: 'Ranking1',
|
||||
stripe: '1',
|
||||
isShowIndex: '1',
|
||||
sourceDataId: '',
|
||||
api: '',
|
||||
apiData: [],
|
||||
dataType: 'staticData',
|
||||
dynamicData: [],
|
||||
staticData: [{name: '列1', value: 23}, {name: '列2', value: 12}, {name: '列2', value: 12}]
|
||||
}]
|
||||
const layouts = [
|
||||
{
|
||||
type: 'display',
|
||||
label: '装饰',
|
||||
display: 'display0',
|
||||
width: 840,
|
||||
height: 540,
|
||||
isZoom: false,
|
||||
zIndex: 1,
|
||||
title: '标题',
|
||||
thumb: 'https://cdn.cunwuyun.cn/dvcp/dv/tpl/display.png',
|
||||
sourceDataId: '',
|
||||
dataType: 'staticData',
|
||||
staticData: [{
|
||||
label: '个人服务办理', value: 247
|
||||
}, {
|
||||
label: '同比上月', value: 247
|
||||
}]
|
||||
}, {
|
||||
type: 'panel',
|
||||
label: '边框',
|
||||
title: '边框',
|
||||
border: 'border0',
|
||||
width: 400,
|
||||
height: 400,
|
||||
isZoom: false,
|
||||
zIndex: 1,
|
||||
thumb: 'https://cdn.cunwuyun.cn/dvcp/dv/tpl/border.png'
|
||||
}, {
|
||||
type: 'summary',
|
||||
label: '数据统计',
|
||||
display: 'summary0',
|
||||
width: 480,
|
||||
height: 240,
|
||||
zIndex: 1,
|
||||
top: 0,
|
||||
left: 0,
|
||||
dataX: '',
|
||||
dataY: [],
|
||||
summaryTitle: '',
|
||||
border: 'border3',
|
||||
sourceDataId: '',
|
||||
title: '数据统计',
|
||||
dataType: 'staticData',
|
||||
staticData: [{
|
||||
key: '个人服务办理', value: 247
|
||||
}, {
|
||||
key: '同比上月', value: 247
|
||||
}],
|
||||
dynamicData: [],
|
||||
thumb: 'https://cdn.cunwuyun.cn/dvcp/dv/tpl/total.png'
|
||||
},
|
||||
]
|
||||
const others = [
|
||||
{
|
||||
label: "图片", list: [
|
||||
{
|
||||
label: "普通图片",
|
||||
type: "img",
|
||||
width: 500,
|
||||
height: 400,
|
||||
thumb: "https://cdn.cunwuyun.cn/dvcp/dv/img/display0-bg.png"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
label: '党组织', type: 'partyOrg', list: [{
|
||||
type: 'partyOrg',
|
||||
label: '党组织',
|
||||
width: 840,
|
||||
height: 800,
|
||||
zIndex: 1,
|
||||
top: 0,
|
||||
left: 0,
|
||||
dataX: '',
|
||||
dataY: [],
|
||||
title: '党组织',
|
||||
border: 'border3',
|
||||
sourceDataId: '',
|
||||
dataType: 'staticData',
|
||||
staticData: [{
|
||||
key: '个人服务办理', value: 247
|
||||
}, {
|
||||
key: '同比上月', value: 247
|
||||
}],
|
||||
dynamicData: [],
|
||||
thumb: 'https://cdn.cunwuyun.cn/dvcp/dv/tpl/total.png'
|
||||
}]
|
||||
}, {
|
||||
label: '轮播图', list: [{
|
||||
type: 'swiper',
|
||||
label: '轮播图',
|
||||
width: 400,
|
||||
height: 300,
|
||||
zIndex: 1,
|
||||
border: 'border2',
|
||||
dataType: 'staticData',
|
||||
staticData: [{
|
||||
img: 'https://cdn.cunwuyun.cn/dvcp/dv/tpl/pie.png', title: '湖羊', content: `歙县众城湖羊养殖专业合作社
|
||||
徐晓红 - 18273645627
|
||||
歙县郑村镇唐跃村碉墅`
|
||||
}],
|
||||
thumb: 'https://cdn.cunwuyun.cn/dvcp/dv/tpl/swiper.png'
|
||||
}, {
|
||||
type: 'swiper',
|
||||
label: '轮播图(点指示器)',
|
||||
width: 800,
|
||||
height: 358,
|
||||
zIndex: 1,
|
||||
border: 'border14',
|
||||
dataType: 'staticData',
|
||||
staticData: [{
|
||||
content: `歙县众城湖羊养殖专业合作社
|
||||
徐晓红 - 18273645627
|
||||
歙县郑村镇唐跃村碉墅`
|
||||
}, {
|
||||
content: `歙县众城湖羊养殖专业合作社
|
||||
徐晓红 - 18273645627
|
||||
歙县郑村镇唐跃村碉墅`
|
||||
},],
|
||||
thumb: 'https://cdn.cunwuyun.cn/dvcp/dv/tpl/swiper.png',
|
||||
dotIndicator: true
|
||||
}]
|
||||
}, {
|
||||
label: '视频播放器', type: 'video', list: [{
|
||||
type: 'video',
|
||||
label: '视频播放器',
|
||||
width: 400,
|
||||
height: 300,
|
||||
zIndex: 1,
|
||||
src: '',
|
||||
border: 'border2',
|
||||
thumb: 'https://cdn.cunwuyun.cn/dvcp/dv/tpl/swiper.png'
|
||||
}]
|
||||
}, {
|
||||
label: '视频监控', list: [
|
||||
{
|
||||
type: 'monitor',
|
||||
label: '视频监控',
|
||||
src: '',
|
||||
width: 480,
|
||||
height: 240,
|
||||
zIndex: 1,
|
||||
top: 0,
|
||||
left: 0,
|
||||
title: '',
|
||||
moniterId: '',
|
||||
monitorType: 'cmcc',
|
||||
api: '/app/appzyvideoequipment/list2',
|
||||
border: 'border2',
|
||||
sourceDataId: '',
|
||||
dataType: 'staticData',
|
||||
staticData: '',
|
||||
dynamicData: '',
|
||||
thumb: 'https://cdn.cunwuyun.cn/dvcp/dv/tpl/video.png'
|
||||
},
|
||||
{
|
||||
type: "monitorCarousel",
|
||||
label: "视频轮播",
|
||||
width: 480,
|
||||
height: 480,
|
||||
zIndex: 1,
|
||||
title: "视频轮播",
|
||||
thumb: "https://cdn.cunwuyun.cn/dvcp/dv/tpl/video.png"
|
||||
}
|
||||
]
|
||||
}, customHtml]
|
||||
const components = [{
|
||||
label: '图表', list: [...chartTpl, {
|
||||
label: "多维图", type: "plot", list: [{
|
||||
type: 'plot',
|
||||
label: '多维图表',
|
||||
title: '多维图表',
|
||||
border: 'border0',
|
||||
width: 500,
|
||||
height: 300,
|
||||
top: 0,
|
||||
left: 0,
|
||||
thumb: 'https://cdn.cunwuyun.cn/dvcp/dv/tpl/pie.png',
|
||||
charts: [{
|
||||
title: "饼状图统计",
|
||||
chart: "pieChart2",
|
||||
dataType: 'staticData',
|
||||
data: [{name: '阿斯达', v1: 23, v2: 33}, {name: '水电费', v1: 12, v2: 34}, {
|
||||
name: '凡哥',
|
||||
v1: 67,
|
||||
v2: 25
|
||||
}, {name: '党费', v1: 98, v2: 85}]
|
||||
}],
|
||||
|
||||
}]
|
||||
}]
|
||||
},
|
||||
{label: '表格', list: tables},
|
||||
{
|
||||
label: "样式", list: [...layouts, {
|
||||
type: "tabs", label: "TAB页签", border: "border13", width: 480,
|
||||
height: 240, thumb: 'https://cdn.cunwuyun.cn/dvcp/dv/tpl/tabs.png', top: 0, left: 0,
|
||||
dataType: 'staticData', staticData: {}, title: "TAB页签"
|
||||
}]
|
||||
},
|
||||
{label: '地图', list: maps}, {
|
||||
type: 'ai3d', label: "3D", list: [{
|
||||
label: "3D楼栋", type: 'building', list: [{
|
||||
type: 'building1',
|
||||
label: "楼栋模型1",
|
||||
width: 840,
|
||||
height: 800,
|
||||
zIndex: 1,
|
||||
title: "楼栋模型1",
|
||||
thumb: 'https://cdn.cunwuyun.cn/dvcp/dv/tpl/total.png'
|
||||
}]
|
||||
}]
|
||||
}, {
|
||||
label: "AI", list: [{
|
||||
type: "aiAssist",
|
||||
label: "AI助手",
|
||||
width: 134,
|
||||
height: 140,
|
||||
zIndex: 1,
|
||||
title: "AI助手",
|
||||
thumb: "https://cdn.cunwuyun.cn/dvcp/dv/aiIcon.png"
|
||||
}]
|
||||
}, {
|
||||
label: '其他', list: others
|
||||
}]
|
||||
export const layers = [...chartTpl.map(e => e.list), maps, tables, layouts, ...others.map(e => e.list)].flat()
|
||||
export {components}
|
||||
|
||||
/**
|
||||
* 监控类型
|
||||
*/
|
||||
export const monitorTypes = [
|
||||
{dictName: "中国移动", dictValue: "cmcc"},
|
||||
{dictName: "海康威视", dictValue: "hik"},
|
||||
{dictName: "大华", dictValue: "dahua"},
|
||||
{dictName: "视联网", dictValue: "slw"},
|
||||
]
|
||||
@@ -1,133 +0,0 @@
|
||||
<template>
|
||||
<section class="AppCentralTaskDV">
|
||||
<!-- <ai-dv-background :src="bgImage"/>-->
|
||||
<div class="coreTask">
|
||||
<div class="leftBox">
|
||||
<div class="boxTitle">{{ coreTaskData.titleText }}</div>
|
||||
<dv-scroll-board v-if="refresh" :config="coreTaskData"/>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {scrollBoard} from '@jiaminghi/data-view'
|
||||
import bgImage from './assets/centralTask/bg.png'
|
||||
import Vue from "vue";
|
||||
|
||||
Vue.use(scrollBoard)
|
||||
export default {
|
||||
name: "AppCentralTaskDV",
|
||||
label: "数据大屏-重点工作",
|
||||
props: {
|
||||
nav: {default: () => ({})}
|
||||
},
|
||||
inject: {
|
||||
dv: {default: ""}
|
||||
},
|
||||
computed: {
|
||||
coreTaskData() {
|
||||
return {
|
||||
headerHeight: 52,
|
||||
header: ['基层组织建设', "社区治理", "便民服务效能", "城市管理"],
|
||||
headerBGC: 'rgba(0, 113, 255, 0.5)',
|
||||
oddRowBGC: "rgba(5, 65, 139, 0.5)",
|
||||
evenRowBGC: "rgba(5, 65, 139, 0.5)",
|
||||
waitTime: 6000,
|
||||
align: ["center", "start", "center", "center"],
|
||||
rowNum: 5,
|
||||
...this.nav.data,
|
||||
}
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {bgImage, refresh: true}
|
||||
},
|
||||
watch: {
|
||||
nav: {
|
||||
deep: true,
|
||||
handler() {
|
||||
this.refresh = false
|
||||
this.$nextTick(() => this.refresh = true)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.AppCentralTaskDV {
|
||||
height: 100%;
|
||||
padding: 0 0 60px;
|
||||
box-sizing: border-box;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
.coreTask {
|
||||
flex: 1;
|
||||
min-height: 0;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 53px;
|
||||
margin-top: 56px;
|
||||
|
||||
.leftBox {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background-image: url("./assets/centralTask/box.png");
|
||||
background-size: 100% 100%;
|
||||
background-repeat: no-repeat;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
padding: 0 40px 42px;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
}
|
||||
|
||||
.boxTitle {
|
||||
height: 68px;
|
||||
width: 534px;
|
||||
background-image: url("./assets/centralTask/titleBox.png");
|
||||
text-align: center;
|
||||
font-size: 22px;
|
||||
font-weight: 400;
|
||||
color: #71F8FF;
|
||||
transform: translateY(-32px);
|
||||
line-height: 68px;
|
||||
}
|
||||
|
||||
:deep( .dv-scroll-board ){
|
||||
width: 100%;
|
||||
flex: 1;
|
||||
min-height: 0;
|
||||
border-radius: 6px;
|
||||
overflow: hidden;
|
||||
|
||||
.header {
|
||||
color: #9FDBFB;
|
||||
font-size: 20px;
|
||||
|
||||
.header-item {
|
||||
text-align: center;
|
||||
border: 1px solid #054596;
|
||||
}
|
||||
}
|
||||
|
||||
.row-item {
|
||||
color: #68F0FC;
|
||||
font-size: 18px;
|
||||
overflow: hidden;
|
||||
|
||||
.ceil {
|
||||
border: 1px solid #054596;
|
||||
border-top: none;
|
||||
position: relative;
|
||||
line-height: 30px;
|
||||
white-space: normal;
|
||||
padding: 20px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -1,479 +0,0 @@
|
||||
<template>
|
||||
<section class="AppGovInteractionDV">
|
||||
<el-row type="flex" justify="space-between" align="bottom">
|
||||
<div flex class="framePane column top">
|
||||
<div class="titlePane" v-text="'事件内容'"/>
|
||||
<div class="fill">
|
||||
<dv-scroll-board :config="topLeftData"/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="centerTopPane" id="centerTopPane">
|
||||
<b class="title gradientFont">事件统计</b>
|
||||
<el-row type="flex" justify="space-between" align="middle"
|
||||
v-for="(row,i) in topCenterData" :key="i">
|
||||
<div class="dataPane" v-for="(op,j) in row" :key="j">
|
||||
<span class="gradientFont" v-text="op.label"/>
|
||||
<dv-digital-flop class="gradientFont" :config="op.v1"/>
|
||||
</div>
|
||||
</el-row>
|
||||
</div>
|
||||
<div flex class="framePane column top">
|
||||
<div class="titlePane" v-text="'政务微信群'"/>
|
||||
<div class="totalPane" flex>
|
||||
<div class="dataPanel fill" flex v-for="(op,i) in rightTopData.total" :key="i">
|
||||
<span v-text="op.label"/>
|
||||
<b v-text="op.v1"/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="fill">
|
||||
<ai-echart class="chart" :data="rightTopData.list" :ops="rightTopData.ops"/>
|
||||
</div>
|
||||
</div>
|
||||
</el-row>
|
||||
<div flex class="gap fill">
|
||||
<div flex class="framePane fill column" v-for="c in charts" :key="c.id">
|
||||
<div class="titlePane" v-text="c.label"/>
|
||||
<div class="fill">
|
||||
<ai-echart class="chart" :data="chartData[c.id]" :ops="c.ops"/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {digitalFlop, scrollBoard} from '@jiaminghi/data-view'
|
||||
import Vue from "vue";
|
||||
|
||||
Vue.use(digitalFlop)
|
||||
Vue.use(scrollBoard)
|
||||
|
||||
export default {
|
||||
name: "AppGovInteractionDV",
|
||||
label: "数据大屏-政民互动",
|
||||
props: {
|
||||
instance: Function
|
||||
},
|
||||
computed: {
|
||||
topCenterData() {
|
||||
let meta = [
|
||||
[{label: "待受理", name: 'pending'}, {label: "累计上报", name: 'total_case'}],
|
||||
[{label: "办理中", name: 'processing'}, {label: "累计受理", name: 'total_accepted'}],
|
||||
[{label: "今日上报", name: "added_today"}, {label: "累计办结", name: 'total_solved'}],
|
||||
[{label: "今日办结", name: 'solved_today'}, {label: "累计办结率", name: 'total_solved_percent'}],
|
||||
]
|
||||
return meta.map(e => e.map(s => {
|
||||
let v1 = {
|
||||
number: [this.meta.residentCategoryReport?.[s.name] || 0],
|
||||
style: {
|
||||
fontFamily: 'dineng',
|
||||
fontWeight: 'bold',
|
||||
fontSize: 40,
|
||||
gradientType: 'linear',
|
||||
gradientColor: ['#fff', '#fff', '#6BC7FF'],
|
||||
gradientParams: [0, 0, 0, 40],
|
||||
gradientWith: 'fill',
|
||||
gradientStops: [0, .18, 1]
|
||||
}
|
||||
}
|
||||
if (s.name == 'total_solved_percent') {
|
||||
v1 = {
|
||||
...v1,
|
||||
number: [v1.number * 100], content: '{nt}%'
|
||||
}
|
||||
}
|
||||
return {...s, v1}
|
||||
}))
|
||||
},
|
||||
topLeftData() {
|
||||
let statusColor = {
|
||||
0: 'doing',
|
||||
1: 'done',
|
||||
2: 'pending',
|
||||
},
|
||||
statusLabel = {
|
||||
0: '处理中',
|
||||
1: '已处理'
|
||||
},
|
||||
list = this.meta.residentOrderList?.map(e => {
|
||||
let status = e.process_list.slice(-1)?.[0]?.status
|
||||
return {
|
||||
...e, status, statusLabel: statusLabel[status]
|
||||
}
|
||||
})
|
||||
return {
|
||||
oddRowBGC: 'transparent',
|
||||
evenRowBGC: 'transparent',
|
||||
rowNum: 10,
|
||||
data: list?.map(e => [`
|
||||
<div flex class="eventItem">
|
||||
<span class="tag ${statusColor[e.status]}">${e.statusLabel}</span>
|
||||
<div class="fill">${e.desc}</div>
|
||||
</div>`]) || []
|
||||
}
|
||||
},
|
||||
rightTopData() {
|
||||
let obj = this.meta.groupMap?.list || {},
|
||||
list = Object.keys(obj).map(e => {
|
||||
let {total, increase, decrease} = obj?.[e],
|
||||
time = this.$moment(e).format('MM-DD')
|
||||
return {time, total, increase, decrease}
|
||||
})
|
||||
return {
|
||||
total: [
|
||||
{label: '群聊总数', v1: this.meta.groupMap?.groupSum || 0},
|
||||
{label: '群成员数', v1: this.meta.groupMap?.today?.total || 0},
|
||||
],
|
||||
ops: {
|
||||
color: ['rgba(54, 165, 255, 0.2)', 'rgba(28, 212, 68, 0.2)', 'rgba(255, 215, 109, 0.2)'],
|
||||
legend: {
|
||||
itemWidth: 16,
|
||||
itemHeight: 16,
|
||||
textStyle: {color: '#82C5FF', padding: [0, 0, 0, 8], fontSize: 14},
|
||||
icon: 'rect',
|
||||
itemGap: 40
|
||||
},
|
||||
tooltip: {},
|
||||
xAxis: {
|
||||
type: 'category', axisTick: false,
|
||||
nameGap: 20,
|
||||
axisLabel: {color: '#fff'},
|
||||
axisLine: {lineStyle: {color: '#263763'}}
|
||||
},
|
||||
// 声明一个 Y 轴,数值轴。
|
||||
yAxis: {
|
||||
nameGap: 30, minInterval: 1,
|
||||
splitLine: {lineStyle: {color: '#263763'}},
|
||||
axisLabel: {color: 'rgba(255,255,255,.8)'}
|
||||
},
|
||||
series: [
|
||||
{
|
||||
type: 'line', name: "群成员数", symbol: 'none', lineStyle: {color: '#36A5FF', borderWidth: 1},
|
||||
itemStyle: {borderColor: '#36A5FF', borderWidth: 1},
|
||||
},
|
||||
{
|
||||
type: 'line', name: "新增人数", symbol: 'none', lineStyle: {color: '#1CD444', borderWidth: 1},
|
||||
itemStyle: {borderColor: '#1CD444', borderWidth: 1},
|
||||
},
|
||||
{
|
||||
type: 'line', name: "退群人数", symbol: 'none', lineStyle: {color: '#FFD76D', borderWidth: 1},
|
||||
itemStyle: {borderColor: '#FFD76D', borderWidth: 1},
|
||||
}
|
||||
],
|
||||
grid: {left: 60, bottom: 58, right: 20}
|
||||
},
|
||||
list
|
||||
}
|
||||
},
|
||||
chartData() {
|
||||
return {
|
||||
EventType: this.meta.residentCategoryReportList?.map(e => {
|
||||
let {category_name: name, total_case, total_solved} = e
|
||||
return {name, total_case, total_solved}
|
||||
}) || [],
|
||||
EventSource: this.meta.unitReportList?.map(e => {
|
||||
let {grid_name: name, total_case, total_solved} = e
|
||||
return {name, total_case, total_solved}
|
||||
}) || []
|
||||
}
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
charts: [
|
||||
{
|
||||
label: "事件类型", id: "EventType", ops: {
|
||||
color: ['rgba(54, 165, 255, 0.2)', 'rgba(28, 212, 68, 0.2)'],
|
||||
legend: {
|
||||
itemWidth: 16,
|
||||
itemHeight: 16,
|
||||
textStyle: {color: '#82C5FF', padding: [0, 0, 0, 8], fontSize: 14},
|
||||
icon: 'rect',
|
||||
itemGap: 40
|
||||
},
|
||||
tooltip: {},
|
||||
xAxis: {
|
||||
type: 'category', nameGap: 20, axisTick: false,
|
||||
axisLabel: {color: '#fff'},
|
||||
axisLine: {lineStyle: {color: '#263763'}}
|
||||
},
|
||||
// 声明一个 Y 轴,数值轴。
|
||||
yAxis: {
|
||||
nameGap: 23, minInterval: 1,
|
||||
splitLine: {lineStyle: {color: '#263763'}},
|
||||
axisLabel: {color: 'rgba(255,255,255,.8)'}
|
||||
},
|
||||
series: [
|
||||
{
|
||||
type: 'bar',
|
||||
name: "累计受理",
|
||||
barWidth: 10,
|
||||
barGap: '20%',
|
||||
itemStyle: {borderColor: '#36A5FF', borderWidth: 1}
|
||||
},
|
||||
{
|
||||
type: 'bar',
|
||||
name: "累计办结",
|
||||
barWidth: 10,
|
||||
barGap: '20%',
|
||||
itemStyle: {borderColor: '#1CD444', borderWidth: 1}
|
||||
}
|
||||
],
|
||||
grid: {left: 40, bottom: 58, right: 20}
|
||||
}
|
||||
},
|
||||
{
|
||||
label: "上报来源", id: "EventSource", ops: {
|
||||
color: ['rgba(54, 165, 255, 0.2)', 'rgba(28, 212, 68, 0.2)'],
|
||||
legend: {
|
||||
itemWidth: 16,
|
||||
itemHeight: 16,
|
||||
textStyle: {color: '#82C5FF', padding: [0, 0, 0, 8], fontSize: 14},
|
||||
icon: 'rect',
|
||||
itemGap: 40
|
||||
},
|
||||
tooltip: {},
|
||||
xAxis: {
|
||||
type: 'category', axisTick: false,
|
||||
nameGap: 20,
|
||||
axisLabel: {color: '#fff'},
|
||||
axisLine: {lineStyle: {color: '#263763'}}
|
||||
},
|
||||
// 声明一个 Y 轴,数值轴。
|
||||
yAxis: {
|
||||
nameGap: 30, minInterval: 1,
|
||||
splitLine: {lineStyle: {color: '#263763'}},
|
||||
axisLabel: {color: 'rgba(255,255,255,.8)'}
|
||||
},
|
||||
series: [
|
||||
{
|
||||
type: 'line', name: "事件数", symbol: 'none', lineStyle: {color: '#36A5FF', borderWidth: 1},
|
||||
itemStyle: {borderColor: '#36A5FF', borderWidth: 1, show: false},
|
||||
areaStyle: {
|
||||
color: {
|
||||
type: 'linear', x2: 0, y2: 1, colorStops: [
|
||||
{offset: 0, color: 'rgba(37, 161, 255, 0.5)'}, {offset: 1, color: 'rgba(37, 161, 255, 0)'}]
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
type: 'line', name: "办理数", symbol: 'none', lineStyle: {color: '#1CD444', borderWidth: 1},
|
||||
itemStyle: {borderColor: '#1CD444', borderWidth: 1, show: false},
|
||||
areaStyle: {
|
||||
color: {
|
||||
type: 'linear', x2: 0, y2: 1, colorStops: [
|
||||
{offset: 0, color: 'rgba(37, 206, 55, 0.5)'}, {offset: 1, color: 'rgba(37, 206, 55, 0)'}]
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
grid: {left: 40, bottom: 58, right: 20}
|
||||
}
|
||||
},
|
||||
],
|
||||
meta: {},
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
getData() {
|
||||
this.instance.post("/app/statistics/governmentPeople/queryResidentReport").then(res => {
|
||||
if (res?.data) this.meta = res.data
|
||||
})
|
||||
},
|
||||
},
|
||||
created() {
|
||||
this.getData()
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.AppGovInteractionDV {
|
||||
height: 100%;
|
||||
padding: 6px 0 10px;
|
||||
gap: 20px;
|
||||
font-size: 16px;
|
||||
color: #82C5FF;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
|
||||
:deep( .eventItem ){
|
||||
width: 100%;
|
||||
color: #82C5FF;
|
||||
|
||||
& > .fill {
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
}
|
||||
|
||||
:deep( .communityEvent ){
|
||||
list-style-type: circle;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
height: 40px;
|
||||
line-height: 40px;
|
||||
padding-left: 1px;
|
||||
color: #82C5FF;
|
||||
}
|
||||
|
||||
:deep( .tag ){
|
||||
padding: 0 10px;
|
||||
border-radius: 4px;
|
||||
margin-right: 10px;
|
||||
font-size: 14px;
|
||||
line-height: 28px;
|
||||
color: #fff;
|
||||
box-sizing: border-box;
|
||||
|
||||
&.doing {
|
||||
background-image: radial-gradient(rgba(#1B1BD6, .4), #208FFF);
|
||||
}
|
||||
|
||||
&.pending {
|
||||
background-image: radial-gradient(rgba(#FF9333, .4), #FFE959);
|
||||
}
|
||||
|
||||
&.done {
|
||||
background-image: radial-gradient(rgba(#1BD622, .4), #2CFF7C);
|
||||
}
|
||||
}
|
||||
|
||||
.centerTopPane {
|
||||
background-image: url("./assets/govInteraction/globe_map.png");
|
||||
background-repeat: no-repeat;
|
||||
background-size: 100% 100%;
|
||||
height: 540px;
|
||||
width: 940px;
|
||||
flex-shrink: 0;
|
||||
position: relative;
|
||||
padding: 30px 50px 50px;
|
||||
box-sizing: border-box;
|
||||
|
||||
.title {
|
||||
font-size: 60px;
|
||||
position: absolute;
|
||||
left: 50%;
|
||||
top: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
}
|
||||
|
||||
:deep( .gradientFont ){
|
||||
background-image: linear-gradient(180deg, #FFFFFF 0%, #FFFFFF 18%, #6BC7FF 100%);
|
||||
-webkit-background-clip: text;
|
||||
-webkit-text-fill-color: transparent;
|
||||
}
|
||||
|
||||
.el-row {
|
||||
&:first-of-type, &:last-of-type {
|
||||
margin: 0 110px;
|
||||
}
|
||||
}
|
||||
|
||||
:deep( .dataPane ){
|
||||
width: 122px;
|
||||
height: 114px;
|
||||
background-image: url("./assets/govInteraction/kuaikuai.png");
|
||||
background-repeat: no-repeat;
|
||||
background-size: 100% 80px;
|
||||
background-position: bottom center;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
font-weight: bold;
|
||||
|
||||
& > b {
|
||||
font-size: 50px;
|
||||
line-height: 50px;
|
||||
|
||||
span {
|
||||
font-weight: normal;
|
||||
font-size: 32px;
|
||||
}
|
||||
}
|
||||
|
||||
& > span {
|
||||
font-size: 18px;
|
||||
line-height: 18px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.framePane {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: rgba(7, 11, 35, 0.4);
|
||||
border: 1px solid #14345F;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
&.top {
|
||||
width: 440px;
|
||||
height: 520px;
|
||||
}
|
||||
|
||||
& > .fill {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
padding: 20px;
|
||||
box-sizing: border-box;
|
||||
overflow-y: auto;
|
||||
}
|
||||
}
|
||||
|
||||
.titlePane {
|
||||
width: 100%;
|
||||
background-image: url("./assets/govInteraction/title.png");
|
||||
background-repeat: no-repeat;
|
||||
background-size: 309px 100%;
|
||||
height: 60px;
|
||||
padding-left: 30px;
|
||||
color: #fff;
|
||||
font-weight: bold;
|
||||
font-size: 20px;
|
||||
line-height: 48px;
|
||||
}
|
||||
|
||||
.chart {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.el-image {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.totalPane {
|
||||
width: 100%;
|
||||
|
||||
.dataPanel {
|
||||
height: 60px;
|
||||
background: linear-gradient(270deg, rgba(119, 169, 255, 0.1) 0%, rgba(66, 112, 255, 0.25) 100%);
|
||||
border-radius: 4px;
|
||||
padding: 0 10px;
|
||||
font-size: 16px;
|
||||
justify-content: space-between;
|
||||
margin-left: 20px;
|
||||
|
||||
& > span {
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
& > b {
|
||||
font-size: 24px;
|
||||
color: #fff;
|
||||
font-family: Arial-BoldMT, Arial, serif;
|
||||
}
|
||||
|
||||
&:last-of-type {
|
||||
margin-right: 20px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
</style>
|
||||
@@ -1,848 +0,0 @@
|
||||
<template>
|
||||
<div class="griddv">
|
||||
<div class="left">
|
||||
<div class="griddv-title">
|
||||
<h2>网格列表</h2>
|
||||
</div>
|
||||
<div class="griddv-tree">
|
||||
<el-tree
|
||||
:data="treeList"
|
||||
:props="defaultProps"
|
||||
@node-click="handleNodeClick"
|
||||
node-key="id"
|
||||
ref="tree"
|
||||
default-expand-all
|
||||
:expand-on-click-node="false"
|
||||
highlight-current>
|
||||
</el-tree>
|
||||
</div>
|
||||
</div>
|
||||
<div class="middle" :class="[girdLevel == '2' ? 'middle-active' : '']" ref="container" v-loading="isLoading"
|
||||
element-loading-background="rgba(0, 0, 0, 0.5)">
|
||||
<div
|
||||
ref="middleTree"
|
||||
id="tree"
|
||||
class="tree"
|
||||
:style="{left: x, top: y, transform: `scale(${scale}) translate(-50%, -50%) `, 'transform-origin': `${0} ${0}`}">
|
||||
<ai-okr-tree ref="VueOkrTree" v-if="chartData.length"
|
||||
:data="chartData"
|
||||
node-key="id"
|
||||
show-collapsable
|
||||
aniamte
|
||||
animate-name="okr-fade-in-linear"
|
||||
:render-content="renderContent"
|
||||
default-expand-all/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="right">
|
||||
<div class="right-top">
|
||||
<div class="griddv-title">
|
||||
<h2>网格内人员情况</h2>
|
||||
</div>
|
||||
<div class="right-chart">
|
||||
<ai-echart
|
||||
style="height: 100%; width: 100%;"
|
||||
:data="userInfo"
|
||||
:ops="barChart1">
|
||||
</ai-echart>
|
||||
</div>
|
||||
</div>
|
||||
<div class="right-bottom">
|
||||
<div class="griddv-title">
|
||||
<h2>事件上报情况</h2>
|
||||
</div>
|
||||
<div class="right-chart">
|
||||
<ai-echart
|
||||
style="height: 100%; width: 100%;"
|
||||
:data="eventInfo"
|
||||
:ops="pieChart2">
|
||||
</ai-echart>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<el-dialog :visible.sync="isShowInfo" width="640px" :close-on-click-modal="false" :modal-append-to-body="false">
|
||||
<template slot="title">
|
||||
<h2>家庭信息</h2>
|
||||
<img src="./assets/grid/close.png" @click="isShowInfo = false">
|
||||
</template>
|
||||
<div class="grid-info">
|
||||
<div class="grid-info__title">
|
||||
<h2>家庭地址</h2>
|
||||
<span>{{ residentInfo.currentAreaName }}</span>
|
||||
</div>
|
||||
<ai-table
|
||||
style="width: 558px"
|
||||
:tableData="tableData"
|
||||
:col-configs="colConfigs"
|
||||
:total="total"
|
||||
:isShowPagination="false"
|
||||
:current.sync="search.current"
|
||||
:size.sync="search.size"
|
||||
@getList="() => {}">
|
||||
</ai-table>
|
||||
</div>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {barChart1, pieChart2} from "./components/chartOps"
|
||||
|
||||
export default {
|
||||
name: 'AppGridDV',
|
||||
label: '网格数据大屏',
|
||||
props: {
|
||||
instance: Function,
|
||||
dict: Object,
|
||||
},
|
||||
|
||||
data() {
|
||||
return {
|
||||
isLoading: false,
|
||||
treeList: [],
|
||||
search: {
|
||||
size: 100,
|
||||
current: 1
|
||||
},
|
||||
barChart1,
|
||||
userInfo: [],
|
||||
eventInfo: [],
|
||||
pieChart2,
|
||||
total: 0,
|
||||
isShowInfo: false,
|
||||
defaultProps: {
|
||||
children: 'girdList',
|
||||
label: 'girdName',
|
||||
},
|
||||
colConfigs: [
|
||||
{prop: 'name', label: '姓名', align: 'center', width: 120},
|
||||
{
|
||||
prop: 'householdRelation',
|
||||
label: '与户主关系',
|
||||
align: 'center',
|
||||
render: (h, {row}) => {
|
||||
return h('span', {
|
||||
style: {
|
||||
color: row.householdName === '1' ? '#1DE94D' : '#A8D7F3'
|
||||
}
|
||||
}, row.householdName === '1' ? '户主' : (this.dict.getLabel('householdRelation', row.householdRelation) || '-'))
|
||||
},
|
||||
format: v => this.dict.getLabel('householdRelation', v)
|
||||
},
|
||||
{
|
||||
prop: 'idNumber',
|
||||
label: '身份证号',
|
||||
align: 'center',
|
||||
width: 220,
|
||||
format: v => v ? v.replace(/^(\d{10})\d{4}(.{4}$)/g, `$1${Array(5).join('*')}$2`) : '-'
|
||||
},
|
||||
{prop: 'phone', label: '联系方式', align: 'center'}
|
||||
],
|
||||
girdId: '',
|
||||
residentInfo: {},
|
||||
tableData: [],
|
||||
chartData: [],
|
||||
girdLevel: '0',
|
||||
scale: 1,
|
||||
x: '50%',
|
||||
y: '50%',
|
||||
offsetX: 0,
|
||||
offsetY: 0,
|
||||
defaultUrl: 'https://cdn.cunwuyun.cn/dvcp/dv/avatar.png'
|
||||
}
|
||||
},
|
||||
|
||||
created() {
|
||||
this.dict.load('householdRelation')
|
||||
this.getTreeList()
|
||||
this.getGirdInfo()
|
||||
},
|
||||
|
||||
mounted() {
|
||||
this.bindEvent()
|
||||
},
|
||||
|
||||
destroyed() {
|
||||
document.querySelector('body').removeEventListener('mousewheel', this.onMousewheel)
|
||||
document.querySelector('body').removeEventListener('mouseup', this.onMouseUp)
|
||||
document.querySelector('body').removeEventListener('mousedown', this.onMousedown)
|
||||
document.querySelector('body').removeEventListener('mousemove', this.onMouseMove)
|
||||
},
|
||||
|
||||
methods: {
|
||||
bindEvent() {
|
||||
document.querySelector('body').addEventListener('mousewheel', this.onMousewheel, true)
|
||||
|
||||
document.querySelector('body').addEventListener('mouseup', this.onMouseUp, true)
|
||||
document.querySelector('body').addEventListener('mousedown', this.onMousedown, true)
|
||||
document.querySelector('body').addEventListener('mousemove', this.onMouseMove, true)
|
||||
},
|
||||
|
||||
onMousewheel(event) {
|
||||
if (!event) return false
|
||||
const elClass = event.target.className
|
||||
if (elClass === 'tree' || elClass === 'middle' || (elClass && (elClass.indexOf('chart') > -1 || elClass.indexOf('user') > -1))) {
|
||||
var dir = event.deltaY > 0 ? 'Up' : 'Down'
|
||||
if (dir === 'Up') {
|
||||
this.scale = this.scale - 0.2 <= 0.1 ? 0.1 : this.scale - 0.2
|
||||
} else {
|
||||
this.scale = this.scale + 0.2
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
},
|
||||
|
||||
onMousedown(e) {
|
||||
const elClass = e.target.className
|
||||
if ((elClass && (elClass.indexOf('chart') > -1 || elClass.indexOf('user') > -1))) {
|
||||
const left = document.querySelector('#tree').offsetLeft
|
||||
const top = document.querySelector('#tree').offsetTop
|
||||
this.isMove = true
|
||||
this.offsetX = e.clientX - left
|
||||
this.offsetY = e.clientY - top
|
||||
}
|
||||
},
|
||||
|
||||
onMouseMove(e) {
|
||||
if (!this.isMove) return
|
||||
|
||||
this.x = (e.clientX - this.offsetX) + 'px'
|
||||
this.y = (e.clientY - this.offsetY) + 'px'
|
||||
},
|
||||
|
||||
onMouseUp() {
|
||||
this.isMove = false
|
||||
},
|
||||
|
||||
debounce(func, wait = 1000) {
|
||||
let timeout
|
||||
return function (event) {
|
||||
clearTimeout(timeout)
|
||||
timeout = setTimeout(() => {
|
||||
func.call(this, event)
|
||||
}, wait)
|
||||
}
|
||||
},
|
||||
|
||||
handleNodeClick(e) {
|
||||
this.girdLevel = e.girdLevel
|
||||
this.isLoading = true
|
||||
this.getGirdInfo(e.id, e.girdLevel)
|
||||
this.getStatisticsInfo(e.id)
|
||||
},
|
||||
|
||||
getStatisticsInfo(id) {
|
||||
this.instance.post(`/app/appgirdmemberinfo/girdMemberAndResidentStatistic?girdId=${id}`).then((res) => {
|
||||
if (res.code == 0) {
|
||||
this.userInfo = [
|
||||
{
|
||||
'name': '网格长',
|
||||
'人数': res.data['网格长'] || 0
|
||||
},
|
||||
{
|
||||
'name': '网格员',
|
||||
'人数': res.data['网格员'] || 0
|
||||
},
|
||||
{
|
||||
'name': '责任家庭数',
|
||||
'人数': res.data['责任家庭数'] || 0
|
||||
}
|
||||
]
|
||||
}
|
||||
})
|
||||
|
||||
this.instance.post(`/app/appclapeventinfo/clapEventStatistic?girdId=${id}`).then((res) => {
|
||||
if (res.code == 0) {
|
||||
this.eventInfo = Object.keys(res.data).map(v => {
|
||||
return {
|
||||
'事件类型': v,
|
||||
v1: res.data[v]
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
renderContent(h, node) {
|
||||
return h('div', {
|
||||
class: 'userlist-container'
|
||||
}, [h('div', {
|
||||
class: `userlist ${node.data.label === '子节点' ? 'last-level' : ''} ${node.data.girdLevel > 1 ? 'userlist-wrapper' : ''} userlist-${node.data.girdLevel}`
|
||||
}, node.data.userList.map(v => {
|
||||
return h('div', {
|
||||
class: `user-item user-item-${v.girdLevel}`
|
||||
}, [h('img', {
|
||||
class: 'user-img',
|
||||
attrs: {
|
||||
src: v.photo || this.defaultUrl
|
||||
},
|
||||
on: {
|
||||
dragstart: e => {
|
||||
e.preventDefault()
|
||||
e.stopPropagation()
|
||||
return false
|
||||
}
|
||||
}
|
||||
}), h('p', {
|
||||
class: 'user-p',
|
||||
attrs: {
|
||||
title: v.label,
|
||||
'data-id': v.id
|
||||
},
|
||||
on: {
|
||||
click: () => {
|
||||
if (node.data.label === '子节点') {
|
||||
this.getResidentInfo(v.id)
|
||||
}
|
||||
}
|
||||
}
|
||||
}, v.label), h('span', {
|
||||
class: 'user-span',
|
||||
style: {
|
||||
display: v.girdLevel === '2' ? 'block' : 'none',
|
||||
fontSize: v.girdLevel === '2' ? '12px' : ''
|
||||
}
|
||||
}, v.checkType ? (v.checkType === '1' ? '网格员' : '网格长') : '-')])
|
||||
})), h('div', {
|
||||
class: 'user-gridName',
|
||||
style: {
|
||||
display: node.data.label === '子节点' ? 'none' : 'block',
|
||||
color: 'rgba(255, 255, 255, 0.8)',
|
||||
fontSize: '12px',
|
||||
margin: '4px 0'
|
||||
}
|
||||
}, node.data.label)])
|
||||
},
|
||||
|
||||
getResidentInfo(id) {
|
||||
this.isLoading = true
|
||||
this.instance.post(`/app/appresident/detail?id=${id}`).then((res) => {
|
||||
if (res.code == 0) {
|
||||
this.residentInfo.resident = res.data
|
||||
this.tableData = res.data.family || []
|
||||
this.isShowInfo = true
|
||||
}
|
||||
|
||||
this.isLoading = false
|
||||
})
|
||||
},
|
||||
|
||||
autoScale() {
|
||||
const treeWidth = this.$refs.middleTree.offsetWidth
|
||||
const containerWidth = this.$refs.container.offsetWidth
|
||||
this.scale = treeWidth < containerWidth ? 1 : containerWidth / treeWidth
|
||||
this.x = '50%'
|
||||
this.y = '50%'
|
||||
},
|
||||
|
||||
getGirdInfo(id) {
|
||||
this.instance.post(`/app/appgirdinfo/listAllGirdAndMemberByTop?id=${id || ''}`).then((res) => {
|
||||
if (res.code == 0) {
|
||||
const chartData = this.formatList([res.data])
|
||||
this.chartData = chartData
|
||||
|
||||
this.$nextTick(() => {
|
||||
if (id) {
|
||||
this.getUserList(id, chartData[0].id)
|
||||
} else {
|
||||
this.isLoading = false
|
||||
this.autoScale()
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
getUserList(id, parentId) {
|
||||
this.instance.post(`/app/appgirdmemberresident/listByGirdMember`, null, {
|
||||
params: {
|
||||
size: 1000,
|
||||
girdId: id
|
||||
}
|
||||
}).then(res => {
|
||||
if (res.code == 0) {
|
||||
const userList = res.data.records.map(v => {
|
||||
return {
|
||||
...v,
|
||||
isLast: true,
|
||||
label: v.name
|
||||
}
|
||||
})
|
||||
|
||||
this.isLoading = false
|
||||
|
||||
if (!userList.length) {
|
||||
this.autoScale()
|
||||
return false
|
||||
}
|
||||
|
||||
const node = this.$refs.VueOkrTree.getNode(parentId)
|
||||
this.$refs.VueOkrTree.append({
|
||||
id: new Date().getTime(),
|
||||
label: '子节点',
|
||||
userList: userList || []
|
||||
}, node)
|
||||
this.$nextTick(() => {
|
||||
this.autoScale()
|
||||
})
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
formatList(list) {
|
||||
return list.map(item => {
|
||||
let userList = []
|
||||
const girdMemberManageList = item.girdMemberManageList ? item.girdMemberManageList.map(v => {
|
||||
return {
|
||||
...v,
|
||||
label: v.name,
|
||||
id: v.id,
|
||||
checkType: '2',
|
||||
girdName: item.girdName,
|
||||
girdLevel: item.girdLevel,
|
||||
isUser: true
|
||||
}
|
||||
}) : []
|
||||
const girdMemberList = item.girdMemberList ? item.girdMemberList.map(v => {
|
||||
return {
|
||||
...v,
|
||||
label: v.name,
|
||||
id: v.id,
|
||||
checkType: '1',
|
||||
girdName: item.girdName,
|
||||
girdLevel: item.girdLevel,
|
||||
isUser: true
|
||||
}
|
||||
}) : []
|
||||
|
||||
if (this.girdLevel === '2' && item.girdLevel === '2' && girdMemberList.length) {
|
||||
userList = girdMemberManageList
|
||||
item.girdList = [{
|
||||
girdLevel: '2',
|
||||
id: item.id,
|
||||
isUser: false,
|
||||
userList: girdMemberList,
|
||||
label: item.girdName,
|
||||
children: []
|
||||
}]
|
||||
} else {
|
||||
userList = [...girdMemberManageList, ...girdMemberList]
|
||||
}
|
||||
if (!userList.length) {
|
||||
userList = [{
|
||||
label: '-',
|
||||
id: item.id,
|
||||
girdLevel: item.girdLevel,
|
||||
girdName: item.girdName
|
||||
}]
|
||||
}
|
||||
|
||||
const obj = {
|
||||
label: item.girdName,
|
||||
id: `${new Date().getTime()}-${item.id}`,
|
||||
girdLevel: item.girdLevel,
|
||||
isUser: false,
|
||||
userList: userList,
|
||||
children: item.girdList || []
|
||||
}
|
||||
|
||||
if (obj.children && obj.children.length && this.girdLevel !== '2') {
|
||||
obj.children = this.formatList(obj.children)
|
||||
}
|
||||
|
||||
return obj
|
||||
})
|
||||
},
|
||||
|
||||
getTreeList() {
|
||||
this.instance.post('/app/appgirdinfo/listAll').then((res) => {
|
||||
if (res.code == 0) {
|
||||
this.treeList = [...res.data]
|
||||
|
||||
this.$nextTick(() => {
|
||||
this.$refs.tree.setCurrentKey(res.data[0].id)
|
||||
this.getStatisticsInfo(res.data[0].id)
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.griddv {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
height: 100%;
|
||||
user-select: none;
|
||||
|
||||
::-webkit-scrollbar {
|
||||
width: 6px;
|
||||
}
|
||||
|
||||
::-webkit-scrollbar-track {
|
||||
border-radius: 5px;
|
||||
background: rgba(93, 163, 255, 0.1);
|
||||
}
|
||||
|
||||
::-webkit-scrollbar-thumb {
|
||||
border-radius: 5px;
|
||||
background: rgba(173, 208, 255, 0.5);
|
||||
}
|
||||
|
||||
.grid-info {
|
||||
width: 100%;
|
||||
|
||||
.grid-info__title {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-bottom: 20px;
|
||||
|
||||
h2, span {
|
||||
color: #fff;
|
||||
font-size: 14px;
|
||||
font-weight: 500;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
:deep( .el-dialog__body ){
|
||||
padding: 10px 40px 30px;
|
||||
|
||||
.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;
|
||||
}
|
||||
|
||||
.el-table th, .el-table tr {
|
||||
color: #fff;
|
||||
font-size: 14px;
|
||||
background-color: rgba(28, 39, 65, 0.9);
|
||||
}
|
||||
|
||||
.el-table__row--striped, .el-table--striped .el-table__body tr.el-table__row--striped td {
|
||||
background-color: transparent !important;
|
||||
}
|
||||
|
||||
.el-table__header-wrapper {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.el-table--enable-row-hover .el-table__body tr:hover > td, .el-table-filter {
|
||||
background-color: transparent;
|
||||
}
|
||||
}
|
||||
|
||||
:deep( .el-dialog ){
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
margin: 0 !important;
|
||||
transform: translate(-50%, -50%);
|
||||
background: rgba(2, 13, 43, 0.9);
|
||||
box-shadow: 0px 2px 10px 0px rgba(0, 0, 0, 0.5), inset 0px 0px 10px 0px #2C7CFF;
|
||||
border: 1px solid #2D65C9;
|
||||
|
||||
.el-dialog__header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
background: transparent;
|
||||
box-shadow: none;
|
||||
|
||||
h2 {
|
||||
color: #fff;
|
||||
font-size: 18px;
|
||||
}
|
||||
|
||||
img {
|
||||
cursor: pointer;
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
|
||||
&:hover {
|
||||
opacity: 0.6;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.el-dialog__headerbtn {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
:deep( .userlist-container ){
|
||||
.userlist {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 10px;
|
||||
background: rgba(76, 166, 255, 0.1);
|
||||
border: 1px solid rgba(255, 255, 255, 0.2);
|
||||
|
||||
.user-item {
|
||||
margin-right: 10px;
|
||||
color: #fff;
|
||||
font-size: 0;
|
||||
|
||||
&:last-child {
|
||||
margin-right: 0;
|
||||
}
|
||||
|
||||
img {
|
||||
width: 58px;
|
||||
height: 80px;
|
||||
object-fit: cover;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
p {
|
||||
max-width: 120px;
|
||||
margin: 4px 0 0 0;
|
||||
font-size: 19px;
|
||||
text-align: center;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
span {
|
||||
display: block;
|
||||
max-width: 120px;
|
||||
font-size: 17px;
|
||||
color: #9DD3FF;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
&.user-item-0 {
|
||||
img {
|
||||
width: 86px;
|
||||
height: 120px;
|
||||
}
|
||||
}
|
||||
|
||||
&.user-item-2 {
|
||||
p {
|
||||
line-height: 14px;
|
||||
font-size: 12px;
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
|
||||
span {
|
||||
line-height: 14px;
|
||||
}
|
||||
|
||||
img {
|
||||
width: 40px;
|
||||
height: 56px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&.userlist-2 {
|
||||
justify-content: space-between;
|
||||
max-width: 130px;
|
||||
flex-wrap: wrap;
|
||||
padding-bottom: 0;
|
||||
width: fit-content;
|
||||
margin: 0 auto;
|
||||
|
||||
.user-item {
|
||||
width: 48px;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
margin-bottom: 10px;
|
||||
|
||||
&:nth-of-type(2n) {
|
||||
margin-right: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&.last-level {
|
||||
flex-wrap: wrap;
|
||||
max-width: 690px;
|
||||
font-size: 0;
|
||||
background: rgba(0, 0, 0, 0.1);
|
||||
border: 1px solid rgba(255, 255, 255, 0.2);
|
||||
padding: 12px 12px 0 12px;
|
||||
box-sizing: border-box;
|
||||
|
||||
.user-item {
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
|
||||
img {
|
||||
display: none;
|
||||
}
|
||||
|
||||
p {
|
||||
padding: 8px;
|
||||
font-size: 12px;
|
||||
background: #0B477D;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
span {
|
||||
display: none !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
* {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.griddv-title {
|
||||
display: flex;
|
||||
width: 320px;
|
||||
height: 62px;
|
||||
background-image: url(assets/grid/title-bg.png);
|
||||
background-size: 100% 100%;
|
||||
|
||||
h2 {
|
||||
width: 100%;
|
||||
height: 50px;
|
||||
line-height: 50px;
|
||||
padding-left: 24px;
|
||||
font-weight: 600;
|
||||
font-size: 20px;
|
||||
letter-spacing: 1px;
|
||||
color: #fff;
|
||||
}
|
||||
}
|
||||
|
||||
& > div {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.right {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
flex-direction: column;
|
||||
width: 440px;
|
||||
margin-left: 20px;
|
||||
|
||||
& > div {
|
||||
flex: 1;
|
||||
width: 100%;
|
||||
padding-bottom: 20px;
|
||||
background: rgba(7, 11, 35, 0.4);
|
||||
border: 1px solid #2D50B5;
|
||||
box-sizing: border-box;
|
||||
|
||||
.right-chart {
|
||||
height: calc(100% - 82px);
|
||||
padding: 0 20px;
|
||||
}
|
||||
|
||||
&:last-child {
|
||||
margin-top: 20px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.middle {
|
||||
position: relative;
|
||||
flex: 1;
|
||||
margin-left: 20px;
|
||||
background: rgba(7, 11, 35, 0.4);
|
||||
border: 1px solid #2D50B5;
|
||||
overflow: hidden;
|
||||
|
||||
#tree {
|
||||
display: flex;
|
||||
position: absolute;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
left: 50%;
|
||||
top: 50%;
|
||||
padding: 20px;
|
||||
overflow: hidden;
|
||||
width: max-content;
|
||||
height: 300%;
|
||||
}
|
||||
|
||||
:deep( .org-chart-container ){
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
|
||||
.org-chart-node-children:before, .org-chart-node:after, .org-chart-node:last-child:before,
|
||||
.org-chart-node.is-leaf:before {
|
||||
border-radius: 0;
|
||||
border-color: #9CD7FF !important;
|
||||
}
|
||||
|
||||
.vertical .org-chart-node:after, .vertical .org-chart-node:before {
|
||||
border-radius: 0;
|
||||
border-color: #9CD7FF !important;
|
||||
}
|
||||
|
||||
.org-chart-node-label-inner {
|
||||
padding: 0 !important;
|
||||
}
|
||||
|
||||
.org-chart-node-btn {
|
||||
margin-left: 0;
|
||||
transform: translateX(-50%);
|
||||
}
|
||||
|
||||
.org-chart-node {
|
||||
// max-width: 500px;
|
||||
}
|
||||
}
|
||||
|
||||
:deep( .org-chart-node-children ){
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
}
|
||||
}
|
||||
|
||||
.left {
|
||||
width: 320px;
|
||||
background: rgba(7, 11, 35, 0.4);
|
||||
border: 1px solid #2D50B5;
|
||||
|
||||
.griddv-tree {
|
||||
height: calc(100% - 62px);
|
||||
overflow-y: auto;
|
||||
margin: 0 8px;
|
||||
padding-bottom: 8px;
|
||||
}
|
||||
|
||||
:deep( .el-tree ){
|
||||
background: transparent;
|
||||
|
||||
.el-tree-node__expand-icon {
|
||||
color: #eaeff9;
|
||||
}
|
||||
|
||||
.el-tree-node__expand-icon.is-leaf {
|
||||
color: transparent;
|
||||
}
|
||||
|
||||
.el-tree-node__content {
|
||||
height: 32px;
|
||||
color: #eaeff9;
|
||||
font-size: 14px;
|
||||
user-select: none;
|
||||
font-weight: normal !important;
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
.is-current > .el-tree-node__content, .el-tree-node__content:hover {
|
||||
background: linear-gradient(270deg, #4895D9 0%, #2D52CA 100%);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -1,812 +0,0 @@
|
||||
<template>
|
||||
<div style="height:100%;" class="AppHouseMapDv">
|
||||
<div class="map">
|
||||
<div id="map" ref="rootmap" @click="hidePopup"/>
|
||||
<div class="community-info" v-show="isShowInfo">
|
||||
<div class="community-info__close" title="关闭" @click="info = {}, isShowInfo = false,chooseBuildId=''">
|
||||
<i class="iconClean iconfont"></i>
|
||||
</div>
|
||||
<div class="community-info__header">
|
||||
<h2 v-if="!info.name">{{ info.createAddress }}</h2>
|
||||
<h2 v-if="info.name">{{ info.homesteadAddress }}</h2>
|
||||
<div>{{ info.lng }},{{ info.lat }}</div>
|
||||
</div>
|
||||
<div class="community-info__wrapper" v-if="info.name">
|
||||
<h2>户主信息</h2>
|
||||
<div class="community-info__item">
|
||||
<label>所属村</label>
|
||||
<span>{{ info.areaName }}</span>
|
||||
</div>
|
||||
<div class="community-info__item">
|
||||
<label>姓名</label>
|
||||
<span style="color:#2266FF;">{{ info.name }}</span>
|
||||
</div>
|
||||
<div class="community-info__item">
|
||||
<label>联系电话</label>
|
||||
<span style="color:#2266FF;">{{ info.phone }}</span>
|
||||
</div>
|
||||
<div class="community-info__item">
|
||||
<label>性别</label>
|
||||
<span>{{ info.sex == 1 ? '男' : '女' }}</span>
|
||||
</div>
|
||||
<div class="community-info__item">
|
||||
<label>年龄</label>
|
||||
<span>{{ info.age }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="community-info__wrapper" v-if="info.name">
|
||||
<h2>宅基地信息</h2>
|
||||
<div class="community-info__item">
|
||||
<label>住宅建筑面积</label>
|
||||
<span>{{ info.liveBuildingArea }}m²</span>
|
||||
</div>
|
||||
<div class="community-info__item">
|
||||
<label>建筑层数</label>
|
||||
<span>{{ info.buildingFloorNumber }}层</span>
|
||||
</div>
|
||||
<div class="community-info__item">
|
||||
<label>建筑高度</label>
|
||||
<span>{{ info.buildingHeight }}m</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="community-info__wrapper" v-if="!info.name">
|
||||
<h2>房屋信息</h2>
|
||||
<div class="community-info__item">
|
||||
<label>所属社区</label>
|
||||
<span>{{ info.areaName }}</span>
|
||||
</div>
|
||||
<div class="community-info__item">
|
||||
<label>所属小区</label>
|
||||
<span>{{ info.communityName }}</span>
|
||||
</div>
|
||||
<div class="community-info__item">
|
||||
<label>房屋类型</label>
|
||||
<span>{{ dict.getLabel("communityBuildingType", info.buildingType) }}</span>
|
||||
</div>
|
||||
<div class="community-info__item">
|
||||
<label>楼长姓名</label>
|
||||
<span>{{ info.managerName }}</span>
|
||||
</div>
|
||||
<div class="community-info__item">
|
||||
<label>楼长电话</label>
|
||||
<span>{{ info.managerPhone }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import AMapLoader from '@amap/amap-jsapi-loader'
|
||||
import {mapState} from 'vuex'
|
||||
|
||||
export default {
|
||||
name: 'AppHouseMapDv',
|
||||
label: '房屋地图',
|
||||
provide() {
|
||||
return {
|
||||
root: this
|
||||
}
|
||||
},
|
||||
props: {
|
||||
instance: Function,
|
||||
dict: Object
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
map: null,
|
||||
mapLib: null,
|
||||
community: '',
|
||||
areaData: {},
|
||||
isShowInfo: false,
|
||||
areaId: '',
|
||||
areaName: '',
|
||||
list: [],
|
||||
info: {},
|
||||
resident: null,
|
||||
satellite: null,
|
||||
zoom: 11,
|
||||
chooseBuildId: '',
|
||||
buildList: [],
|
||||
searchList: [],
|
||||
house: null,
|
||||
center: [],
|
||||
type: '',
|
||||
showStatistics: false
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
...mapState(['user'])
|
||||
},
|
||||
|
||||
watch: {
|
||||
community: {
|
||||
deep: true,
|
||||
handler() {
|
||||
this.debounce(this.search, 500)
|
||||
}
|
||||
},
|
||||
|
||||
showStatistics: {
|
||||
deep: true,
|
||||
handler() {
|
||||
this.debounce(this.getCorpLocation, 500)
|
||||
}
|
||||
},
|
||||
},
|
||||
|
||||
created() {
|
||||
this.dict.load('householdRelation', 'communityBuildingType')
|
||||
},
|
||||
|
||||
mounted() {
|
||||
this.areaId = this.user.info.areaId
|
||||
this.areaName = this.user.info.areaName
|
||||
this.getCorpLocation()
|
||||
},
|
||||
|
||||
methods: {
|
||||
getCorpLocation() {
|
||||
if (this.showStatistics) {
|
||||
return
|
||||
}
|
||||
this.instance.post("/app/appdvcpconfig/getCorpLocation").then(res => {
|
||||
if (res.code == 0) {
|
||||
this.initMap(res.data)
|
||||
}
|
||||
})
|
||||
},
|
||||
changeZoom(isAdd) {
|
||||
const zoom = isAdd ? this.map.getZoom() + 1 : this.map.getZoom() - 1
|
||||
this.map.setZoom(zoom, false, 600)
|
||||
},
|
||||
|
||||
getBuildInfo(id, type) {
|
||||
var url = `/app/apphomesteadinfo/queryDetailById?id=${id}`
|
||||
if (type == 0) {
|
||||
url = `/app/appcommunityhouseinfo/queryDetailByIdWithBuilding?buildId=${id}`
|
||||
}
|
||||
this.instance.post(url).then(res => {
|
||||
if (res.code === 0) {
|
||||
if (type == 1) {
|
||||
this.info = res.data
|
||||
} else {
|
||||
this.info = res.data.build
|
||||
this.resident = null;
|
||||
}
|
||||
this.$nextTick(() => {
|
||||
this.isShowInfo = true
|
||||
})
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
chooseCommunity(item) {
|
||||
if (item.name) { //宅基地
|
||||
if (!item.lng || !item.lat) {
|
||||
return this.$message.error('未获取到该房屋坐标信息')
|
||||
} else {
|
||||
this.map.setZoomAndCenter(18, [item.lng, item.lat], false, 600)
|
||||
this.info = item
|
||||
this.$nextTick(() => {
|
||||
this.isShowSearch = false
|
||||
this.isShowInfo = true
|
||||
})
|
||||
}
|
||||
|
||||
} else { //楼栋
|
||||
this.instance.post(`/app/appcommunityhouseinfo/queryDetailByIdWithBuilding`, null, {
|
||||
params: {
|
||||
buildId: item.buildingId,
|
||||
houseId: item.id,
|
||||
residentId: item.residentId
|
||||
}
|
||||
}).then(res => {
|
||||
if (res.code === 0) {
|
||||
if (!res.data.build?.lng || !res.data.build?.lat) {
|
||||
this.isShowInfo = true
|
||||
this.isShowSearch = false
|
||||
this.info = res.data.build;
|
||||
return this.$message.error('未获取到该房屋坐标信息')
|
||||
} else {
|
||||
this.chooseBuildId = res.data.build.id
|
||||
this.house = res.data.house
|
||||
this.resident = res.data.resident;
|
||||
}
|
||||
|
||||
this.map.setZoomAndCenter(18, [res.data.build?.lng, res.data.build?.lat], false, 600)
|
||||
this.info = res.data.build
|
||||
this.$nextTick(() => {
|
||||
this.isShowSearch = false
|
||||
this.isShowInfo = true
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
},
|
||||
|
||||
toCenter() {
|
||||
this.map.setZoomAndCenter(this.zoom, this.center, false, 600)
|
||||
},
|
||||
|
||||
renderClusterMarker(context) {
|
||||
let el = `<div class="polymeric">
|
||||
<div class="polymeric-container">
|
||||
<p>${context.count}</p>
|
||||
</div>
|
||||
</div>`
|
||||
let {mapLib: AMap} = this
|
||||
let offset = new AMap.Pixel(-9, -9)
|
||||
context.marker.setContent(el)
|
||||
context.marker.setOffset(offset)
|
||||
context.marker.lnglat = context.clusterData[0].lnglat
|
||||
|
||||
context.marker.on('click', e => {
|
||||
this.map.setZoomAndCenter(this.map.getZoom() + 2, e.target.lnglat, false, 500)
|
||||
})
|
||||
},
|
||||
|
||||
renderMarker(context) {
|
||||
const buildId = context.data[0].id
|
||||
let el = ''
|
||||
var urlType = ''
|
||||
if (context.data[0].communityName == context.data[0].buildingNumber) { //宅基地
|
||||
urlType = 1
|
||||
el = `<div id="buildId-${buildId}" class="mark ${buildId === this.chooseBuildId ? 'mark-active' : ''}">
|
||||
<div class="mark-contaienr">
|
||||
<span>${context.data[0].areaName}</span>
|
||||
<span>${context.data[0].communityName}</span>
|
||||
</div>
|
||||
</div>`
|
||||
} else {
|
||||
urlType = 0
|
||||
el = `<div id="buildId-${buildId}" class="mark ${buildId === this.chooseBuildId ? 'mark-active' : ''}">
|
||||
<div class="mark-contaienr">
|
||||
<span>${context.data[0].communityName}</span>
|
||||
<span>${context.data[0].buildingNumber}栋</span>
|
||||
</div>
|
||||
</div>`
|
||||
}
|
||||
|
||||
context.marker.setContent(el);
|
||||
context.marker.setAnchor("center")
|
||||
context.marker.id = `${buildId}`
|
||||
context.marker.lnglat = context.data[0].lnglat
|
||||
context.marker.urlType = urlType
|
||||
|
||||
context.marker.on('click', e => {
|
||||
this.chooseBuildId = e.target.id
|
||||
this.getBuildInfo(e.target.id, e.target.urlType)
|
||||
context.marker.setContent(el);
|
||||
document.querySelectorAll('.mark').forEach(el => {
|
||||
el.classList.remove('mark-active')
|
||||
})
|
||||
document.querySelector(`#buildId-${e.target.id}`).classList.add('mark-active')
|
||||
})
|
||||
},
|
||||
|
||||
addMakert(points) {
|
||||
let {mapLib: AMap} = this
|
||||
new AMap.MarkerClusterer(this.map, points, {
|
||||
gridSize: 60,
|
||||
maxZoom: 15,
|
||||
clusterByZoomChange: false,
|
||||
renderClusterMarker: this.renderClusterMarker,
|
||||
renderMarker: this.renderMarker
|
||||
})
|
||||
},
|
||||
|
||||
getCommunityList() {
|
||||
this.instance.post('/app/appcommunitybuildinginfo/listByBuilding', null, {
|
||||
params: {
|
||||
current: 1,
|
||||
size: 1000000
|
||||
}
|
||||
}).then(res => {
|
||||
if (res.code === 0) {
|
||||
this.buildList = res.data
|
||||
const points = res.data.map(item => {
|
||||
return {
|
||||
lnglat: [item.lng, item.lat],
|
||||
id: item.id,
|
||||
corpId: item.corpId,
|
||||
areaName: item.areaName,
|
||||
buildingNumber: item.name || item.buildingNumber,
|
||||
communityName: item.name || item.communityName,
|
||||
}
|
||||
})
|
||||
|
||||
this.addMakert(points)
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
hidePopup() {
|
||||
this.isShowArea = false
|
||||
this.isShowSearch = false
|
||||
},
|
||||
|
||||
initMap({lng, lat}) {
|
||||
this.center = [lng, lat];
|
||||
AMapLoader.load({
|
||||
key: '54a02a43d9828a8f9cd4f26fe281e74e',
|
||||
version: '2.0',
|
||||
plugins: ['AMap.ToolBar', 'AMap.Scale', 'AMap.MouseTool', 'AMap.MarkerClusterer'],
|
||||
AMapUI: {
|
||||
version: '1.1',
|
||||
plugins: []
|
||||
}
|
||||
}).then((AMap) => {
|
||||
this.mapLib = AMap
|
||||
this.map = new AMap.Map('map', {
|
||||
resizeEnable: true,
|
||||
zooms: [6, 20],
|
||||
center: [lng, lat],
|
||||
zoom: this.zoom,
|
||||
mapStyle: 'amap://styles/40f6fba77127e061a058f670433a67ec'
|
||||
})
|
||||
this.satellite = new AMap.TileLayer.Satellite()
|
||||
this.getCommunityList()
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.map {
|
||||
:deep( .amap-logo), :deep( .amap-copyright ){
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
:deep( .amap-icon ){
|
||||
width: 40px !important;
|
||||
height: 40px !important;
|
||||
|
||||
img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.community-info__star {
|
||||
margin-top: 4px;
|
||||
margin-bottom: 8px;
|
||||
|
||||
.community-info__star--content {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
height: 36px;
|
||||
padding: 0 12px;
|
||||
color: #666666;
|
||||
font-size: 12px;
|
||||
|
||||
span {
|
||||
flex: 1;
|
||||
text-align: center;
|
||||
|
||||
&:first-child {
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
&:last-child {
|
||||
text-align: right;
|
||||
}
|
||||
}
|
||||
|
||||
&:nth-of-type(2n) {
|
||||
background: #fff;
|
||||
}
|
||||
}
|
||||
|
||||
.community-info__star--tab {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
height: 36px;
|
||||
padding: 0 12px;
|
||||
user-select: none;
|
||||
background: #fff;
|
||||
|
||||
span {
|
||||
height: 100%;
|
||||
line-height: 36px;
|
||||
color: #999999;
|
||||
font-size: 12px;
|
||||
font-weight: 700;
|
||||
cursor: pointer;
|
||||
border-bottom: 2px solid transparent;
|
||||
|
||||
&:first-child {
|
||||
margin-right: 16px;
|
||||
}
|
||||
|
||||
&.star-active {
|
||||
color: #2266FF;
|
||||
border-bottom: 2px solid #2266FF;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.community-info__item--imgs {
|
||||
display: block !important;
|
||||
height: auto !important;
|
||||
|
||||
label {
|
||||
height: 36px;
|
||||
line-height: 36px;
|
||||
}
|
||||
|
||||
.community-info__item--img {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
flex-wrap: wrap;
|
||||
padding-bottom: 10px;
|
||||
overflow: hidden;
|
||||
|
||||
img {
|
||||
width: 69px;
|
||||
height: 69px;
|
||||
margin-right: 4px;
|
||||
margin-bottom: 4px;
|
||||
cursor: pointer;
|
||||
|
||||
&:nth-of-type(4n) {
|
||||
margin-right: 0;
|
||||
}
|
||||
|
||||
&:last-child {
|
||||
margin-right: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.map {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
overflow: hidden;
|
||||
|
||||
:deep( .ol-zoom ){
|
||||
display: none !important;
|
||||
top: inherit !important;
|
||||
bottom: 0.5em !important;
|
||||
}
|
||||
|
||||
div {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
#map {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.community {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
position: relative;
|
||||
height: 28px;
|
||||
padding: 0 10px;
|
||||
background: #0F8F64;
|
||||
border-radius: 26px;
|
||||
color: #fff;
|
||||
font-size: 12px;
|
||||
cursor: pointer;
|
||||
|
||||
&.color1 {
|
||||
background: #2266FF;
|
||||
|
||||
em:after {
|
||||
border-top-color: #2266FF !important;
|
||||
}
|
||||
}
|
||||
|
||||
&.color2 {
|
||||
background: #F46159;
|
||||
|
||||
em:after {
|
||||
border-top-color: #F46159 !important;
|
||||
}
|
||||
}
|
||||
|
||||
em {
|
||||
position: absolute;
|
||||
bottom: -6px;
|
||||
left: 50%;
|
||||
transform: translate(-50%, 0);
|
||||
|
||||
&::after {
|
||||
position: absolute;
|
||||
bottom: -6px;
|
||||
left: 0;
|
||||
width: 0;
|
||||
height: 0;
|
||||
border: 6px solid #0F8F64;
|
||||
border-bottom-color: transparent;
|
||||
border-left-color: transparent;
|
||||
border-right-color: transparent;
|
||||
transform: translate(-50%, 0);
|
||||
overflow: hidden;
|
||||
content: ' ';
|
||||
}
|
||||
}
|
||||
|
||||
i {
|
||||
padding-right: 2px;
|
||||
position: relative;
|
||||
color: #ffc928;
|
||||
font-size: 16px;
|
||||
font-style: normal;
|
||||
}
|
||||
}
|
||||
|
||||
:deep( .polymeric ){
|
||||
display: flex;
|
||||
position: relative;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 62px;
|
||||
height: 62px;
|
||||
border-radius: 50%;
|
||||
cursor: pointer;
|
||||
user-select: none;
|
||||
|
||||
&.polymeric-active {
|
||||
.polymeric-container {
|
||||
background: #F46159;
|
||||
}
|
||||
|
||||
&::after {
|
||||
background-color: #F46159;
|
||||
}
|
||||
}
|
||||
|
||||
&::after {
|
||||
position: absolute;
|
||||
z-index: -1;
|
||||
width: 62px;
|
||||
height: 62px;
|
||||
border-radius: 50%;
|
||||
-webkit-animation: warn 1s ease-out 0s infinite;
|
||||
animation: warn 1s ease-out 0s infinite;
|
||||
background-color: rgba(15, 143, 100, 1);
|
||||
transform: translate(-50%, -50%);
|
||||
content: " ";
|
||||
}
|
||||
|
||||
.polymeric-container {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
flex-direction: column;
|
||||
width: 62px;
|
||||
height: 62px;
|
||||
border-radius: 50%;
|
||||
background: rgba(15, 143, 100, 1);
|
||||
|
||||
p {
|
||||
text-align: center;
|
||||
width: 58px;
|
||||
color: #fff;
|
||||
font-size: 18px;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
p:first-child {
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
h2 {
|
||||
color: #fff;
|
||||
font-weight: normal;
|
||||
font-size: 12px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
:deep( .mark ){
|
||||
user-select: none;
|
||||
cursor: pointer;
|
||||
height: 32px;
|
||||
border-radius: 26px;
|
||||
position: relative;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
box-sizing: border-box;
|
||||
padding: 0 12px;
|
||||
background: rgba(0,39,100,0.50);
|
||||
border: 1px solid #36A5FF;
|
||||
border-radius: 30px;
|
||||
|
||||
&.mark-active {
|
||||
background: #004AC0;
|
||||
border: 1px solid transparent;
|
||||
box-shadow: inset 0 0 8px 2px #33BBFF;
|
||||
}
|
||||
|
||||
.mark-contaienr {
|
||||
color: white;
|
||||
font-size: 14px;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.arrow {
|
||||
position: absolute;
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
bottom: -21px;
|
||||
width: 0;
|
||||
height: 0;
|
||||
border: 12px solid transparent;
|
||||
border-top: 12px solid #0F8F64;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@-webkit-keyframes warn {
|
||||
0% {
|
||||
transform: scale(.5);
|
||||
opacity: 1
|
||||
}
|
||||
|
||||
30% {
|
||||
opacity: .5
|
||||
}
|
||||
|
||||
to {
|
||||
transform: scale(1.8);
|
||||
opacity: 0
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes warn {
|
||||
0% {
|
||||
transform: scale(.5);
|
||||
opacity: 1
|
||||
}
|
||||
|
||||
30% {
|
||||
opacity: .5
|
||||
}
|
||||
|
||||
to {
|
||||
transform: scale(1.4);
|
||||
opacity: 0
|
||||
}
|
||||
}
|
||||
|
||||
.community-info {
|
||||
position: absolute;
|
||||
top: 58px;
|
||||
right: 10px;
|
||||
width: 400px;
|
||||
height: calc(100% - 117px);
|
||||
overflow-y: auto;
|
||||
overflow-x: hidden;
|
||||
z-index: 111;
|
||||
border-radius: 2px;
|
||||
background: rgba(0,15,38,0.30);
|
||||
border: 1px solid #103588;
|
||||
// filter: blur(5px);
|
||||
|
||||
.community-info__close {
|
||||
position: absolute;
|
||||
right: 0;
|
||||
top: 0;
|
||||
padding: 16px 12px 0 12px;
|
||||
font-size: 16px;
|
||||
color: #fff;
|
||||
cursor: pointer;
|
||||
|
||||
&:hover {
|
||||
opacity: 0.6;
|
||||
}
|
||||
}
|
||||
|
||||
&::-webkit-scrollbar {
|
||||
width: 6px;
|
||||
height: 1px;
|
||||
}
|
||||
|
||||
&::-webkit-scrollbar-thumb {
|
||||
border-radius: 6px;
|
||||
background: rgba(144, 147, 153, .5);
|
||||
}
|
||||
|
||||
.community-info__header {
|
||||
padding: 12px 20px;
|
||||
background-image: linear-gradient(270deg, rgba(11, 158, 255, 0.2) 0%, rgba(2, 81, 227, 0.2) 100%);
|
||||
|
||||
h2 {
|
||||
max-width: 360px;
|
||||
line-height: 28px;
|
||||
margin: 0;
|
||||
color: #fff;
|
||||
font-size: 20px;
|
||||
font-weight: 600;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
div {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
color: #D2E0FF;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
span {
|
||||
display: block;
|
||||
margin-top: 4px;
|
||||
font-style: normal;
|
||||
color: #82C5FF;
|
||||
font-size: 14px;
|
||||
}
|
||||
}
|
||||
|
||||
.community-info__wrapper {
|
||||
h2 {
|
||||
margin: 20px 0 20px 20px;
|
||||
padding: 0 20px;
|
||||
font-size: 15px;
|
||||
color: #fff;
|
||||
font-weight: 600;
|
||||
background: url(https://cdn.cunwuyun.cn/dvcp/ply/title-bg.png) no-repeat;
|
||||
background-size: 169px 30px;
|
||||
background-position-y: -5px;
|
||||
background-position-x: -10px;
|
||||
}
|
||||
|
||||
.community-info__item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
margin: 0 20px;
|
||||
padding: 12px 12px;
|
||||
font-size: 14px;
|
||||
color: #fff;
|
||||
background: rgba(63, 136, 255, 0.15);
|
||||
|
||||
&:nth-of-type(2n) {
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
span {
|
||||
max-width: 70%;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
label {
|
||||
flex-shrink: 1;
|
||||
color: #82C5FF;
|
||||
}
|
||||
}
|
||||
|
||||
&.community-info__wrapper--last {
|
||||
.community-info__item {
|
||||
background: #fff;
|
||||
|
||||
&:nth-of-type(2n-1) {
|
||||
background: #fff;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.bg-fff {
|
||||
background-color: #fff !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -1,887 +0,0 @@
|
||||
<template>
|
||||
<div class="map">
|
||||
<div id="map" ref="rootmap" />
|
||||
<div class="community-info" v-show="isShowInfo">
|
||||
<div class="community-info__close" title="关闭" @click="closeInfo">
|
||||
<i class="iconClean iconfont"></i>
|
||||
</div>
|
||||
<div class="community-info__header">
|
||||
<div class="user" :style="userStyle">
|
||||
<span>{{ formatName(info.name) }}</span>
|
||||
</div>
|
||||
<h2>{{ info.name }}</h2>
|
||||
<h3>{{ info.gpsDesc }}</h3>
|
||||
<p>最后更新时间:{{ info.lastUpdateTime }}</p>
|
||||
<div class="community-info__header--status">
|
||||
<div :style="{color: info.onlineStatus === '1' ? '#2EA222' : '#F46' }">
|
||||
<i class="iconfont iconzhuangtai"></i>
|
||||
<span>设备{{ info.onlineStatus === '1' ? '在线' : '离线' }}</span>
|
||||
</div>
|
||||
<div>
|
||||
<i class="iconfont icondianliang"></i>
|
||||
<span>剩余{{ info.electricQuantity }}%</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="community-info__header--info">
|
||||
<div class="community-info__header--info-item" v-for="(item, index) in testItem" :key="item.name" v-if="index !== 0">
|
||||
<div class="left">
|
||||
<div :style="{backgroundColor: item.color}">
|
||||
<i :class="item.icon" class="iconfont"></i>
|
||||
</div>
|
||||
<span>{{ item.name }}</span>
|
||||
</div>
|
||||
<i :style="{color: (testData[index] && testData[index].abnormalStatus === '1') ? '#F46' : ''}">{{ testData[index] ? testData[index].itemValue : '-' }}{{ index === '1' ? '℃' : '' }}</i>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="community-info__wrapper">
|
||||
<div class="community-info__title">
|
||||
<h2>人员信息</h2>
|
||||
<span :style="userStatusColor">{{ userStatus }}</span>
|
||||
</div>
|
||||
<div class="community-info__item">
|
||||
<label>姓名</label>
|
||||
<span>{{ info.name}}</span>
|
||||
</div>
|
||||
<div class="community-info__item">
|
||||
<label>性别</label>
|
||||
<span>{{ info.sex === '1' ? '男' : '女' }}</span>
|
||||
</div>
|
||||
<div class="community-info__item">
|
||||
<label>年龄</label>
|
||||
<span>{{ info.age }}</span>
|
||||
</div>
|
||||
<div class="community-info__item">
|
||||
<label>所属地区</label>
|
||||
<span>{{ info.areaName }}</span>
|
||||
</div>
|
||||
<div class="community-info__item">
|
||||
<label>联系电话</label>
|
||||
<span>{{ info.phone }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import AMapLoader from '@amap/amap-jsapi-loader'
|
||||
import {mapState} from 'vuex'
|
||||
|
||||
export default {
|
||||
name: 'AppMonitorMapDv',
|
||||
label: '监护地图',
|
||||
provide() {
|
||||
return {
|
||||
root: this
|
||||
}
|
||||
},
|
||||
props: {
|
||||
instance: Function,
|
||||
dict: Object
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
map: null,
|
||||
community: '',
|
||||
isShowInfo: false,
|
||||
info: {},
|
||||
satellite: null,
|
||||
zoom: 11,
|
||||
choosedId: '',
|
||||
testItem: [{
|
||||
name: '体温',
|
||||
icon: 'icontiwen',
|
||||
color: '#6BA3DB'
|
||||
}, {
|
||||
name: '心率',
|
||||
icon: 'iconxinlv',
|
||||
color: '#72BB5C'
|
||||
}, {
|
||||
name: '血压',
|
||||
icon: 'iconxueya',
|
||||
color: '#7577CB'
|
||||
}, {
|
||||
name: '血氧',
|
||||
icon: 'iconxueyang',
|
||||
color: '#FF5656'
|
||||
}],
|
||||
testData: [],
|
||||
center: []
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
...mapState(['user']),
|
||||
|
||||
userStatus () {
|
||||
if (this.info.abnormalStatus === '2') {
|
||||
return '求助'
|
||||
}
|
||||
|
||||
if (this.info.abnormalStatus === '1') {
|
||||
return '异常'
|
||||
}
|
||||
|
||||
if (this.info.abnormalStatus === '0') {
|
||||
return '正常'
|
||||
}
|
||||
|
||||
return '-'
|
||||
},
|
||||
|
||||
userStatusColor () {
|
||||
if (this.info.abnormalStatus === '2') {
|
||||
return {
|
||||
color: '#FF69DD',
|
||||
border: '1px solid #FF69DD'
|
||||
}
|
||||
}
|
||||
|
||||
if (this.info.abnormalStatus === '1') {
|
||||
return {
|
||||
color: '#FF6969',
|
||||
border: '1px solid #FF6969'
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
color: '#22FF81',
|
||||
border: '1px solid #22FF81'
|
||||
}
|
||||
},
|
||||
|
||||
userStyle () {
|
||||
if (this.info.abnormalStatus === '2') {
|
||||
return {
|
||||
background: 'rgba(96,8,102,0.80)',
|
||||
border: '1px solid #FF69DD',
|
||||
boxShadow: '0 4px 4px 0 #000000, inset 0 0 8px 4px #C312CA'
|
||||
}
|
||||
}
|
||||
|
||||
if (this.info.abnormalStatus === '1') {
|
||||
return {
|
||||
background: 'rgba(79,14,7,0.80)',
|
||||
border: '1px solid #FF6969',
|
||||
boxShadow: '0 4px 4px 0 #000000, inset 0 0 8px 4px #C60E0E'
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
background: 'rgba(8,73,35,0.80)',
|
||||
border: '1px solid #22FF81',
|
||||
boxShadow: '0 4px 4px 0 #000000, inset 0 0 8px 4px #15BE55'
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
mounted() {
|
||||
this.getCorpLocation()
|
||||
},
|
||||
|
||||
methods: {
|
||||
getIdInfo (UUserCard, num) {
|
||||
if (num == 1) {
|
||||
var birth = UUserCard.substring(6, 10) + '-' + UUserCard.substring(10, 12) + '-' + UUserCard.substring(12, 14)
|
||||
return birth
|
||||
}
|
||||
if (num == 2) {
|
||||
if (parseInt(UUserCard.substr(16, 1)) % 2 == 1) {
|
||||
return '1'
|
||||
} else {
|
||||
return '0'
|
||||
}
|
||||
}
|
||||
|
||||
if (num == 3) {
|
||||
var myDate = new Date()
|
||||
var month = myDate.getMonth() + 1
|
||||
var day = myDate.getDate()
|
||||
var age = myDate.getFullYear() - UUserCard.substring(6, 10) - 1;
|
||||
if (UUserCard.substring(10, 12) < month || UUserCard.substring(10, 12) == month && UUserCard.substring(12, 14) <= day) {
|
||||
age ++
|
||||
}
|
||||
|
||||
return age
|
||||
}
|
||||
},
|
||||
|
||||
getCorpLocation(){
|
||||
this.instance.post("/app/appdvcpconfig/getCorpLocation").then(res=>{
|
||||
if(res.code==0){
|
||||
this.initMap(res.data);
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
getList () {
|
||||
this.instance.post(`/app/appintelligentguardianshipdevice/list`, null, {
|
||||
params: {
|
||||
size: 8000,
|
||||
current: 1
|
||||
}
|
||||
}).then(res => {
|
||||
if (res.code == 0) {
|
||||
const points = res.data.records.map(item => {
|
||||
return {
|
||||
...item,
|
||||
lnglat: [item.lng, item.lat],
|
||||
id: item.id,
|
||||
corpId: item.corpId,
|
||||
areaName:item.areaName,
|
||||
name: item.name
|
||||
}
|
||||
})
|
||||
|
||||
this.addMakert(points)
|
||||
|
||||
if (this.$route.query.id) {
|
||||
this.onTreeChange({
|
||||
type: '1',
|
||||
deviceId: this.$route.query.id,
|
||||
lng: this.$route.query.lng,
|
||||
lat: this.$route.query.lat
|
||||
})
|
||||
}
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
formatName (str) {
|
||||
if (!str) return ''
|
||||
|
||||
return str.substr(str.length - 2)
|
||||
},
|
||||
|
||||
getInfo (id) {
|
||||
this.instance.post(`/app/appintelligentguardianshipdevice/queryMonitorList?deviceId=${id}&type=1`).then(res => {
|
||||
if (res.code === 0) {
|
||||
let obj = {}
|
||||
this.testData = res.data.records.forEach(item => {
|
||||
obj[item.item] = item
|
||||
})
|
||||
|
||||
this.testData = obj
|
||||
}
|
||||
})
|
||||
this.instance.post(`/app/appintelligentguardianshipdevice/queryDetailById?id=${id}`).then(res => {
|
||||
if (res.code === 0) {
|
||||
this.info = res.data
|
||||
this.info.age = this.getIdInfo(res.data.idNumber, 3)
|
||||
this.isShowInfo = true
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
toCenter() {
|
||||
this.map.setZoomAndCenter(this.zoom, this.center, false, 600)
|
||||
},
|
||||
|
||||
renderClusterMarker(context) {
|
||||
let el = `<div class="polymeric">
|
||||
<div class="polymeric-container">
|
||||
<p>${context.count}</p>
|
||||
</div>
|
||||
</div>`
|
||||
|
||||
let offset = new AMap.Pixel(-9, -9)
|
||||
context.marker.setContent(el)
|
||||
context.marker.setOffset(offset)
|
||||
context.marker.lnglat = context.clusterData[0].lnglat
|
||||
|
||||
context.marker.on('click', e => {
|
||||
this.map.setZoomAndCenter(this.map.getZoom() + 3, e.target.lnglat, false, 500)
|
||||
})
|
||||
},
|
||||
|
||||
renderMarker(context) {
|
||||
const buildId = context.data[0].id
|
||||
|
||||
let el = `<div class="mark mark${context.data[0].abnormalStatus}" id="buildId-${buildId}">
|
||||
<div class="mark-contaienr">
|
||||
<span>${context.data[0].name}</span>
|
||||
</div>
|
||||
</div>`
|
||||
|
||||
context.marker.setContent(el);
|
||||
context.marker.setAnchor("center")
|
||||
context.marker.id = `${buildId}`
|
||||
context.marker.data = JSON.stringify(context.data[0])
|
||||
context.marker.lnglat = context.data[0].lnglat
|
||||
|
||||
context.marker.on('click', e => {
|
||||
this.choosedId = e.target.id
|
||||
this.getInfo(e.target.id)
|
||||
context.marker.setContent(el);
|
||||
document.querySelectorAll('.mark').forEach(el => {
|
||||
el.classList.remove('mark-active')
|
||||
})
|
||||
document.querySelector(`#buildId-${e.target.id}`).add('mark-active')
|
||||
this.map.setZoomAndCenter(this.map.getZoom() + 0.000000001, e.target.lnglat, false, 300)
|
||||
})
|
||||
},
|
||||
|
||||
closeInfo () {
|
||||
this.info = {}
|
||||
this.isShowInfo = false
|
||||
this.choosedId = ''
|
||||
this.map.setZoom(this.map.getZoom() + 0.0001)
|
||||
},
|
||||
|
||||
addMakert(points) {
|
||||
new AMap.MarkerClusterer(this.map, points, {
|
||||
gridSize: 60,
|
||||
maxZoom: 15,
|
||||
clusterByZoomChange: false,
|
||||
renderClusterMarker: this.renderClusterMarker,
|
||||
renderMarker: this.renderMarker
|
||||
})
|
||||
},
|
||||
|
||||
initMap({lng,lat}) {
|
||||
this.center = [lng,lat];
|
||||
AMapLoader.load({
|
||||
key: '54a02a43d9828a8f9cd4f26fe281e74e',
|
||||
version: '2.0',
|
||||
plugins: ['AMap.ToolBar', 'AMap.Scale', 'AMap.MouseTool', 'AMap.MarkerClusterer'],
|
||||
AMapUI: {
|
||||
version: '1.1',
|
||||
plugins: []
|
||||
}
|
||||
}).then((AMap) => {
|
||||
this.map = new AMap.Map('map', {
|
||||
resizeEnable: true,
|
||||
zooms: [6, 20],
|
||||
center: [lng, lat],
|
||||
zoom: this.zoom,
|
||||
mapStyle: 'amap://styles/40f6fba77127e061a058f670433a67ec'
|
||||
})
|
||||
this.satellite = new AMap.TileLayer.Satellite()
|
||||
this.getList()
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.map {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
overflow: hidden;
|
||||
|
||||
.community-info {
|
||||
position: absolute;
|
||||
top: 10px;
|
||||
right: 10px;
|
||||
width: 400px;
|
||||
max-height: calc(100% - 20px);
|
||||
overflow-y: overlay;
|
||||
overflow-x: hidden;
|
||||
z-index: 111;
|
||||
background: rgba(7,11,35,0.50);
|
||||
border: 1px solid #14345F;
|
||||
|
||||
.community-info__close {
|
||||
position: absolute;
|
||||
right: 0;
|
||||
top: 0;
|
||||
padding: 16px 12px 0 12px;
|
||||
font-size: 16px;
|
||||
color: #8899bb;
|
||||
cursor: pointer;
|
||||
|
||||
&:hover {
|
||||
opacity: 0.6;
|
||||
}
|
||||
}
|
||||
|
||||
&::-webkit-scrollbar {
|
||||
width: 6px;
|
||||
height: 1px;
|
||||
}
|
||||
|
||||
&::-webkit-scrollbar-thumb {
|
||||
border-radius: 6px;
|
||||
background: rgba(144, 147, 153, .5);
|
||||
}
|
||||
|
||||
.community-info__header {
|
||||
padding-top: 40px;
|
||||
text-align: center;
|
||||
|
||||
.user {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 50px;
|
||||
height: 50px;
|
||||
margin: 0 auto 8px;
|
||||
border-radius: 50%;
|
||||
background: #2266FF;
|
||||
|
||||
span {
|
||||
color: #fff;
|
||||
font-size: 16px;
|
||||
}
|
||||
}
|
||||
|
||||
h2 {
|
||||
line-height: 24px;
|
||||
margin-bottom: 12px;
|
||||
font-weight: Bold;
|
||||
font-size: 16px;
|
||||
color: #FFFFFF;
|
||||
}
|
||||
|
||||
h3, p {
|
||||
width: 300px;
|
||||
line-height: 22px;
|
||||
margin: 0 auto 4px;
|
||||
font-size: 13px;
|
||||
color: #82C5FF;
|
||||
text-align: center;
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
& > h3 {
|
||||
line-height: 1.4;
|
||||
color: #82C5FF;
|
||||
}
|
||||
|
||||
.community-info__header--info {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
padding: 0 20px;
|
||||
|
||||
.community-info__header--info-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
width: 174px;
|
||||
height: 56px;
|
||||
margin-bottom: 10px;
|
||||
padding: 0 12px;
|
||||
background-image: linear-gradient(270deg, rgba(119,169,255,0.20) 0%, rgba(66,112,255,0.50) 100%);
|
||||
border-radius: 4px;
|
||||
|
||||
&:nth-of-type(2n - 1) {
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
& > i {
|
||||
position: relative;
|
||||
top: 2px;
|
||||
font-style: normal;
|
||||
color: #fff;
|
||||
font-size: 16px;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.left {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
span {
|
||||
font-size: 14px;
|
||||
color: rgba(130, 197, 255, 1);
|
||||
}
|
||||
|
||||
div {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
margin-right: 8px;
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
border-radius: 50%;
|
||||
background: #6BA3DB;
|
||||
|
||||
i {
|
||||
color: #fff;
|
||||
font-size: 16px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.community-info__header--status {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
margin-bottom: 20px;
|
||||
|
||||
div {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
color: #74FF66;
|
||||
}
|
||||
|
||||
span {
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
div:first-child {
|
||||
margin-right: 20px;
|
||||
}
|
||||
|
||||
i {
|
||||
position: relative;
|
||||
margin-right: 2px;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
div:last-child {
|
||||
color: #fff;
|
||||
|
||||
span {
|
||||
font-size: 12px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.community-info__wrapper {
|
||||
padding: 0 20px 40px;
|
||||
|
||||
.community-info__title {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
margin-bottom: 20px;
|
||||
|
||||
h2 {
|
||||
position: relative;
|
||||
width: 169px;
|
||||
padding: 0 20px;
|
||||
font-size: 15px;
|
||||
color: #fff;
|
||||
font-weight: 700;
|
||||
background: url(https://cdn.cunwuyun.cn/dvcp/ply/title-bg.png) no-repeat;
|
||||
background-size: 169px 30px;
|
||||
background-position-y: -5px;
|
||||
background-position-x: -10px;
|
||||
}
|
||||
|
||||
span {
|
||||
width: 52px;
|
||||
height: 24px;
|
||||
line-height: 24px;
|
||||
color: #fff;
|
||||
font-size: 14px;
|
||||
text-align: center;
|
||||
border-radius: 12px;
|
||||
}
|
||||
}
|
||||
|
||||
.community-info__item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
height: 40px;
|
||||
padding: 0 12px;
|
||||
font-size: 12px;
|
||||
color: #fff;
|
||||
background: transparent;
|
||||
|
||||
&:nth-of-type(2n) {
|
||||
background-image: linear-gradient(270deg, rgba(119,169,255,0.20) 0%, rgba(66,112,255,0.50) 100%);
|
||||
}
|
||||
|
||||
span {
|
||||
max-width: 70%;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
label {
|
||||
flex-shrink: 1;
|
||||
color: rgba(130, 197, 255, 1);
|
||||
}
|
||||
}
|
||||
|
||||
&.community-info__wrapper--last {
|
||||
.community-info__item {
|
||||
background: #fff;
|
||||
|
||||
&:nth-of-type(2n) {
|
||||
background: #F3F6F9;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
:deep( .ol-zoom ){
|
||||
display: none !important;
|
||||
top: inherit !important;
|
||||
bottom: 0.5em !important;
|
||||
}
|
||||
|
||||
div {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
#map {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
:deep( .amap-logo), :deep( .amap-copyright ){
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
:deep( .amap-icon ){
|
||||
width: 40px !important;
|
||||
height: 40px !important;
|
||||
|
||||
img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.no-more {
|
||||
display: block;
|
||||
height: 60px;
|
||||
line-height: 60px;
|
||||
margin-top: 2px;
|
||||
text-align: center;
|
||||
font-size: 12px;
|
||||
color: #999;
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.community {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
position: relative;
|
||||
height: 28px;
|
||||
padding: 0 10px;
|
||||
background: #0F8F64;
|
||||
border-radius: 26px;
|
||||
color: #fff;
|
||||
font-size: 12px;
|
||||
cursor: pointer;
|
||||
|
||||
&.color1 {
|
||||
background: #2266FF;
|
||||
|
||||
em:after {
|
||||
border-top-color: #2266FF !important;
|
||||
}
|
||||
}
|
||||
|
||||
&.color2 {
|
||||
background: #F46159;
|
||||
|
||||
em:after {
|
||||
border-top-color: #F46159 !important;
|
||||
}
|
||||
}
|
||||
|
||||
em {
|
||||
position: absolute;
|
||||
bottom: -6px;
|
||||
left: 50%;
|
||||
transform: translate(-50%, 0);
|
||||
|
||||
&::after {
|
||||
position: absolute;
|
||||
bottom: -6px;
|
||||
left: 0;
|
||||
width: 0;
|
||||
height: 0;
|
||||
border: 6px solid #0F8F64;
|
||||
border-bottom-color: transparent;
|
||||
border-left-color: transparent;
|
||||
border-right-color: transparent;
|
||||
transform: translate(-50%, 0);
|
||||
overflow: hidden;
|
||||
content: ' ';
|
||||
}
|
||||
}
|
||||
|
||||
i {
|
||||
padding-right: 2px;
|
||||
position: relative;
|
||||
color: #ffc928;
|
||||
font-size: 16px;
|
||||
font-style: normal;
|
||||
}
|
||||
}
|
||||
|
||||
:deep( .polymeric ){
|
||||
display: flex;
|
||||
position: relative;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 62px;
|
||||
height: 62px;
|
||||
border-radius: 50%;
|
||||
cursor: pointer;
|
||||
user-select: none;
|
||||
|
||||
&.polymeric-active {
|
||||
.polymeric-container {
|
||||
background: #F46159;
|
||||
}
|
||||
|
||||
&::after {
|
||||
background-color: #F46159;
|
||||
}
|
||||
}
|
||||
|
||||
&::after {
|
||||
position: absolute;
|
||||
z-index: -1;
|
||||
width: 62px;
|
||||
height: 62px;
|
||||
border-radius: 50%;
|
||||
-webkit-animation: warn 1s ease-out 0s infinite;
|
||||
animation: warn 1s ease-out 0s infinite;
|
||||
background-color: rgba(15, 143, 100, 1);
|
||||
transform: translate(-50%, -50%);
|
||||
content: " ";
|
||||
}
|
||||
|
||||
.polymeric-container {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
flex-direction: column;
|
||||
width: 62px;
|
||||
height: 62px;
|
||||
border-radius: 50%;
|
||||
background: rgba(15, 143, 100, 1);
|
||||
|
||||
p {
|
||||
text-align: center;
|
||||
width: 58px;
|
||||
color: #fff;
|
||||
font-size: 18px;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
p:first-child{
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
h2 {
|
||||
color: #fff;
|
||||
font-weight: normal;
|
||||
font-size: 12px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
:deep( .mark){
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
position: relative;
|
||||
user-select: none;
|
||||
cursor: pointer;
|
||||
width: 56px;
|
||||
height: 56px;
|
||||
background: rgba(108,94,14,0.80);
|
||||
border: 1px solid #FFDF54;
|
||||
box-shadow: 0 4px 4px 0 #000000, inset 0 0 8px 4px #D1A818;
|
||||
border-radius: 50%;
|
||||
box-sizing: border-box;
|
||||
font-size: 14px;
|
||||
color: #FFFFFF;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
text-shadow: 0 2px 4px rgba(0,0,0,0.50);
|
||||
|
||||
&.mark0 {
|
||||
background: rgba(8,73,35,0.80);
|
||||
border: 1px solid #22FF81;
|
||||
box-shadow: 0 4px 4px 0 #000000, inset 0 0 8px 4px #15BE55;
|
||||
}
|
||||
|
||||
&.mark1 {
|
||||
background: rgba(79,14,7,0.80);
|
||||
border: 1px solid #FF6969;
|
||||
box-shadow: 0 4px 4px 0 #000000, inset 0 0 8px 4px #C60E0E;
|
||||
}
|
||||
|
||||
&.mark2 {
|
||||
background: rgba(96,8,102,0.80);
|
||||
border: 1px solid #FF69DD;
|
||||
box-shadow: 0 4px 4px 0 #000000, inset 0 0 8px 4px #C312CA;
|
||||
}
|
||||
|
||||
.mark-contaienr {
|
||||
width: 56px;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
// &.mark1::after {
|
||||
// position: absolute;
|
||||
// z-index: -1;
|
||||
// width: 100px;
|
||||
// height: 100px;
|
||||
// border-radius: 50%;
|
||||
// -webkit-animation: warn 1s ease-out 0s infinite;
|
||||
// animation: warn 1s ease-out 0s infinite;
|
||||
// background-color: #FF6969;
|
||||
// transform: translate(-50%, -50%);
|
||||
// content: " ";
|
||||
// }
|
||||
|
||||
// &.mark2::after {
|
||||
// position: absolute;
|
||||
// z-index: -1;
|
||||
// width: 100px;
|
||||
// height: 100px;
|
||||
// border-radius: 50%;
|
||||
// -webkit-animation: warn 1s ease-out 0s infinite;
|
||||
// animation: warn 1s ease-out 0s infinite;
|
||||
// background-color: #FF69DD;
|
||||
// transform: translate(-50%, -50%);
|
||||
// content: " ";
|
||||
// }
|
||||
}
|
||||
|
||||
@-webkit-keyframes warn {
|
||||
0% {
|
||||
transform: scale(.5);
|
||||
opacity: 1
|
||||
}
|
||||
|
||||
30% {
|
||||
opacity: .5
|
||||
}
|
||||
|
||||
to {
|
||||
transform: scale(1.8);
|
||||
opacity: 0
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes warn {
|
||||
0% {
|
||||
transform: scale(.5);
|
||||
opacity: 1
|
||||
}
|
||||
|
||||
30% {
|
||||
opacity: .5
|
||||
}
|
||||
|
||||
to {
|
||||
transform: scale(1.4);
|
||||
opacity: 0
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -1,505 +0,0 @@
|
||||
<template>
|
||||
<div class="map">
|
||||
<div id="map" ref="rootmap" />
|
||||
<div class="community-info" v-show="isShowInfo">
|
||||
<div class="community-info__close" title="关闭" @click="closeInfo">
|
||||
<i class="iconClean iconfont"></i>
|
||||
</div>
|
||||
<div class="community-info__header">
|
||||
<h2>{{ info.resourceName }}</h2>
|
||||
<el-tag type="success" size="small" style="margin: 6px 0;">{{ info.categoryName }}</el-tag>
|
||||
<div>{{ info.areaName }}{{ info.address }}</div>
|
||||
</div>
|
||||
<div class="community-info__wrapper">
|
||||
<div class="community-info__title">
|
||||
<h2>资源信息</h2>
|
||||
</div>
|
||||
<p>{{ info.information }}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import AMapLoader from '@amap/amap-jsapi-loader'
|
||||
import {mapState} from 'vuex'
|
||||
|
||||
export default {
|
||||
name: 'AppResourceMapDv',
|
||||
label: '资源地图',
|
||||
provide() {
|
||||
return {
|
||||
root: this
|
||||
}
|
||||
},
|
||||
props: {
|
||||
instance: Function,
|
||||
dict: Object
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
map: null,
|
||||
community: '',
|
||||
isShowInfo: false,
|
||||
info: {},
|
||||
satellite: null,
|
||||
zoom: 11,
|
||||
choosedId: '',
|
||||
center: [],
|
||||
list: []
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
...mapState(['user'])
|
||||
},
|
||||
|
||||
mounted() {
|
||||
this.getCorpLocation()
|
||||
},
|
||||
|
||||
methods: {
|
||||
getCorpLocation(){
|
||||
this.instance.post("/app/appdvcpconfig/getCorpLocation").then(res=>{
|
||||
if(res.code==0){
|
||||
this.initMap(res.data)
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
getList () {
|
||||
this.instance.post(`/app/appresourceinfo/listAll`).then(res => {
|
||||
if (res.code == 0) {
|
||||
const points = res.data.map(item => {
|
||||
return {
|
||||
...item,
|
||||
lnglat: [item.lng, item.lat],
|
||||
id: item.id,
|
||||
corpId: item.corpId,
|
||||
areaName:item.areaName,
|
||||
name: item.resourceName
|
||||
}
|
||||
})
|
||||
|
||||
this.list = points
|
||||
|
||||
this.addMakert(points)
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
getInfo (id) {
|
||||
this.info = this.list.filter(v => id === v.id)[0]
|
||||
this.isShowInfo = true
|
||||
},
|
||||
|
||||
renderClusterMarker(context) {
|
||||
let el = `<div class="polymeric">
|
||||
<div class="polymeric-container">
|
||||
<p>${context.count}</p>
|
||||
</div>
|
||||
</div>`
|
||||
|
||||
let offset = new AMap.Pixel(-9, -9)
|
||||
context.marker.setContent(el)
|
||||
context.marker.setOffset(offset)
|
||||
context.marker.lnglat = context.clusterData[0].lnglat
|
||||
|
||||
context.marker.on('click', e => {
|
||||
this.map.setZoomAndCenter(this.map.getZoom() + 3, e.target.lnglat, false, 500)
|
||||
})
|
||||
},
|
||||
|
||||
renderMarker(context) {
|
||||
const buildId = context.data[0].id
|
||||
|
||||
let el = `<div id="buildId-${buildId}" class="mark ${buildId === this.choosedId ? 'mark-active' : ''}">
|
||||
<img src="${context.data[0].categoryIcon || 'https://cdn.cunwuyun.cn/dvcp/ply/icon.png'}">
|
||||
</div>`
|
||||
|
||||
context.marker.setContent(el);
|
||||
context.marker.setAnchor("center")
|
||||
context.marker.id = `${buildId}`
|
||||
context.marker.data = JSON.stringify(context.data[0])
|
||||
context.marker.lnglat = context.data[0].lnglat
|
||||
|
||||
context.marker.on('click', e => {
|
||||
this.choosedId = e.target.id
|
||||
this.getInfo(e.target.id)
|
||||
context.marker.setContent(el);
|
||||
document.querySelectorAll('.mark').forEach(el => {
|
||||
el.classList.remove('mark-active')
|
||||
})
|
||||
document.querySelector(`#buildId-${e.target.id}`).classList.add('mark-active')
|
||||
})
|
||||
},
|
||||
|
||||
closeInfo () {
|
||||
this.info = {}
|
||||
this.isShowInfo = false
|
||||
this.choosedId = ''
|
||||
this.map.setZoom(this.map.getZoom() + 0.0001)
|
||||
},
|
||||
|
||||
addMakert(points) {
|
||||
new AMap.MarkerClusterer(this.map, points, {
|
||||
gridSize: 60,
|
||||
maxZoom: 15,
|
||||
clusterByZoomChange: false,
|
||||
renderClusterMarker: this.renderClusterMarker,
|
||||
renderMarker: this.renderMarker
|
||||
})
|
||||
},
|
||||
|
||||
initMap({lng,lat}) {
|
||||
this.center = [lng,lat];
|
||||
AMapLoader.load({
|
||||
key: '54a02a43d9828a8f9cd4f26fe281e74e',
|
||||
version: '2.0',
|
||||
plugins: ['AMap.ToolBar', 'AMap.Scale', 'AMap.MouseTool', 'AMap.MarkerClusterer'],
|
||||
AMapUI: {
|
||||
version: '1.1',
|
||||
plugins: []
|
||||
}
|
||||
}).then((AMap) => {
|
||||
this.map = new AMap.Map('map', {
|
||||
resizeEnable: true,
|
||||
zooms: [6, 20],
|
||||
center: [lng, lat],
|
||||
zoom: this.zoom,
|
||||
mapStyle: 'amap://styles/40f6fba77127e061a058f670433a67ec'
|
||||
})
|
||||
this.satellite = new AMap.TileLayer.Satellite()
|
||||
this.getList()
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.map {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
overflow: hidden;
|
||||
|
||||
.community-info__header {
|
||||
margin-bottom: 10px;
|
||||
padding: 12px 20px;
|
||||
background-image: linear-gradient(270deg, rgba(11, 158, 255, 0.2) 0%, rgba(2, 81, 227, 0.2) 100%);
|
||||
|
||||
h2 {
|
||||
max-width: 360px;
|
||||
line-height: 28px;
|
||||
margin: 0;
|
||||
color: #fff;
|
||||
font-size: 20px;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
div {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
color: #D2E0FF;
|
||||
font-size: 12px;
|
||||
}
|
||||
}
|
||||
|
||||
.community-info {
|
||||
position: absolute;
|
||||
top: 10px;
|
||||
right: 10px;
|
||||
width: 400px;
|
||||
max-height: calc(100% - 20px);
|
||||
overflow-y: overlay;
|
||||
overflow-x: hidden;
|
||||
z-index: 111;
|
||||
background: rgba(7,11,35,0.50);
|
||||
border: 1px solid #14345F;
|
||||
|
||||
.community-info__close {
|
||||
position: absolute;
|
||||
right: 0;
|
||||
top: 0;
|
||||
padding: 16px 12px 0 12px;
|
||||
font-size: 16px;
|
||||
color: #8899bb;
|
||||
cursor: pointer;
|
||||
|
||||
&:hover {
|
||||
opacity: 0.6;
|
||||
}
|
||||
}
|
||||
|
||||
&::-webkit-scrollbar {
|
||||
width: 6px;
|
||||
height: 1px;
|
||||
}
|
||||
|
||||
&::-webkit-scrollbar-thumb {
|
||||
border-radius: 6px;
|
||||
background: rgba(144, 147, 153, .5);
|
||||
}
|
||||
|
||||
.community-info__wrapper {
|
||||
padding: 0 20px 40px;
|
||||
|
||||
.community-info__title {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
margin-bottom: 20px;
|
||||
|
||||
h2 {
|
||||
position: relative;
|
||||
width: 169px;
|
||||
padding: 0 20px;
|
||||
font-size: 15px;
|
||||
color: #fff;
|
||||
font-weight: 700;
|
||||
background: url(https://cdn.cunwuyun.cn/dvcp/ply/title-bg.png) no-repeat;
|
||||
background-size: 169px 30px;
|
||||
background-position-y: -5px;
|
||||
background-position-x: -10px;
|
||||
}
|
||||
|
||||
span {
|
||||
width: 52px;
|
||||
height: 24px;
|
||||
line-height: 24px;
|
||||
color: #fff;
|
||||
font-size: 14px;
|
||||
text-align: center;
|
||||
border-radius: 12px;
|
||||
}
|
||||
}
|
||||
|
||||
p {
|
||||
line-height: 1.5;
|
||||
font-size: 14px;
|
||||
color: #82C5FF;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
:deep( .ol-zoom ){
|
||||
display: none !important;
|
||||
top: inherit !important;
|
||||
bottom: 0.5em !important;
|
||||
}
|
||||
|
||||
div {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
#map {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
:deep( .amap-logo), :deep( .amap-copyright ){
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
:deep( .amap-icon ){
|
||||
width: 40px !important;
|
||||
height: 40px !important;
|
||||
|
||||
img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.no-more {
|
||||
display: block;
|
||||
height: 60px;
|
||||
line-height: 60px;
|
||||
margin-top: 2px;
|
||||
text-align: center;
|
||||
font-size: 12px;
|
||||
color: #999;
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.community {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
position: relative;
|
||||
height: 28px;
|
||||
padding: 0 10px;
|
||||
background: #0F8F64;
|
||||
border-radius: 26px;
|
||||
color: #fff;
|
||||
font-size: 12px;
|
||||
cursor: pointer;
|
||||
|
||||
&.color1 {
|
||||
background: #2266FF;
|
||||
|
||||
em:after {
|
||||
border-top-color: #2266FF !important;
|
||||
}
|
||||
}
|
||||
|
||||
&.color2 {
|
||||
background: #F46159;
|
||||
|
||||
em:after {
|
||||
border-top-color: #F46159 !important;
|
||||
}
|
||||
}
|
||||
|
||||
em {
|
||||
position: absolute;
|
||||
bottom: -6px;
|
||||
left: 50%;
|
||||
transform: translate(-50%, 0);
|
||||
|
||||
&::after {
|
||||
position: absolute;
|
||||
bottom: -6px;
|
||||
left: 0;
|
||||
width: 0;
|
||||
height: 0;
|
||||
border: 6px solid #0F8F64;
|
||||
border-bottom-color: transparent;
|
||||
border-left-color: transparent;
|
||||
border-right-color: transparent;
|
||||
transform: translate(-50%, 0);
|
||||
overflow: hidden;
|
||||
content: ' ';
|
||||
}
|
||||
}
|
||||
|
||||
i {
|
||||
padding-right: 2px;
|
||||
position: relative;
|
||||
color: #ffc928;
|
||||
font-size: 16px;
|
||||
font-style: normal;
|
||||
}
|
||||
}
|
||||
|
||||
:deep( .polymeric ){
|
||||
display: flex;
|
||||
position: relative;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 62px;
|
||||
height: 62px;
|
||||
border-radius: 50%;
|
||||
cursor: pointer;
|
||||
user-select: none;
|
||||
|
||||
&.polymeric-active {
|
||||
.polymeric-container {
|
||||
background: #F46159;
|
||||
}
|
||||
|
||||
&::after {
|
||||
background-color: #F46159;
|
||||
}
|
||||
}
|
||||
|
||||
&::after {
|
||||
position: absolute;
|
||||
z-index: -1;
|
||||
width: 62px;
|
||||
height: 62px;
|
||||
border-radius: 50%;
|
||||
-webkit-animation: warn 1s ease-out 0s infinite;
|
||||
animation: warn 1s ease-out 0s infinite;
|
||||
background-color: rgba(15, 143, 100, 1);
|
||||
transform: translate(-50%, -50%);
|
||||
content: " ";
|
||||
}
|
||||
|
||||
.polymeric-container {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
flex-direction: column;
|
||||
width: 62px;
|
||||
height: 62px;
|
||||
border-radius: 50%;
|
||||
background: rgba(15, 143, 100, 1);
|
||||
|
||||
p {
|
||||
text-align: center;
|
||||
width: 58px;
|
||||
color: #fff;
|
||||
font-size: 18px;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
p:first-child{
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
h2 {
|
||||
color: #fff;
|
||||
font-weight: normal;
|
||||
font-size: 12px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
:deep( .mark){
|
||||
position: relative;
|
||||
user-select: none;
|
||||
width: 50px;
|
||||
height: 50px;
|
||||
border-radius: 50%;
|
||||
cursor: pointer;
|
||||
|
||||
img {
|
||||
width: 50px;
|
||||
height: 50px;
|
||||
border-radius: 50%;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
opacity: 0.8;
|
||||
}
|
||||
|
||||
&.mark-active {
|
||||
transform: scale(1.2);
|
||||
}
|
||||
}
|
||||
|
||||
@-webkit-keyframes warn {
|
||||
0% {
|
||||
transform: scale(.5);
|
||||
opacity: 1
|
||||
}
|
||||
|
||||
30% {
|
||||
opacity: .5
|
||||
}
|
||||
|
||||
to {
|
||||
transform: scale(1.8);
|
||||
opacity: 0
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes warn {
|
||||
0% {
|
||||
transform: scale(.5);
|
||||
opacity: 1
|
||||
}
|
||||
|
||||
30% {
|
||||
opacity: .5
|
||||
}
|
||||
|
||||
to {
|
||||
transform: scale(1.4);
|
||||
opacity: 0
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -1,522 +0,0 @@
|
||||
<template>
|
||||
<section class="AppVideoMonitoringDV">
|
||||
<el-row type="flex" justify="space-between" class="body">
|
||||
<div class="left-wrap column" flex>
|
||||
<div class="left-top fill">
|
||||
<label class="label">设备统计</label>
|
||||
<dv-scroll-board :header="config.header" :config="config" class="table"/>
|
||||
</div>
|
||||
<div class="left-bottom">
|
||||
<label class="label">电子地图</label>
|
||||
<ai-map :areaId="user.info.areaId"/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="center-wrap column" flex>
|
||||
<div flex style="width: 100%">
|
||||
<div :span="6" class="card fill" v-for="(item,index) in cardList" :key="index">
|
||||
<span>{{ item.label }}</span>
|
||||
<span>{{ item.value }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="center-bottom fill">
|
||||
<label class="label">视频监控</label>
|
||||
<div class="video-wrap">
|
||||
<div class="item" v-for="(item,index) in videoData.slice(0,2)"
|
||||
:key="index">
|
||||
<template v-if="flag">
|
||||
<iframe class="video" :src="item.url" allow="autoplay *; microphone *; fullscreen *"
|
||||
allowfullscreen allowtransparency="true" allowusermedia="true" frameBorder="no"></iframe>
|
||||
</template>
|
||||
<template v-else>
|
||||
<div class="video"></div>
|
||||
</template>
|
||||
<div class="info">
|
||||
<span>{{ item.name }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="video-wrap">
|
||||
<div class="item" v-for="(item,index) in videoData.slice(2,4)"
|
||||
:key="index">
|
||||
<template v-if="flag">
|
||||
<iframe class="video" :src="item.url" allow="autoplay *; microphone *; fullscreen *"
|
||||
allowfullscreen allowtransparency="true" allowusermedia="true" frameBorder="no"></iframe>
|
||||
</template>
|
||||
<template v-else>
|
||||
<div class="video"></div>
|
||||
</template>
|
||||
<div class="info">
|
||||
<span>{{ item.name }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="right-wrap column" flex>
|
||||
<div class="right-top fill">
|
||||
<label class="label">人员统计</label>
|
||||
<label class="total">人员总数
|
||||
<span>0</span>
|
||||
<span>人</span>
|
||||
</label>
|
||||
<dv-scroll-board :config="config1" class="total-table"/>
|
||||
</div>
|
||||
<div class="right-middle">
|
||||
<label class="label">动作告警统计</label>
|
||||
<div class="tag">
|
||||
<span></span>
|
||||
</div>
|
||||
<ai-echart :ops="getOpt()"/>
|
||||
<div class="info">
|
||||
今日
|
||||
<span>0</span>
|
||||
<span>次</span>
|
||||
本月
|
||||
<span>0</span>
|
||||
<span>次</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="right-bottom">
|
||||
<label class="label">声音告警统计</label>
|
||||
<div class="tag">
|
||||
<span></span>
|
||||
</div>
|
||||
<ai-echart :ops="getOpt('1')"/>
|
||||
<div class="info">
|
||||
今日
|
||||
<span style="color:#00FFDF">0</span>
|
||||
<span>次</span>
|
||||
本月
|
||||
<span style="color:#00FFDF">0</span>
|
||||
<span>次</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</el-row>
|
||||
</section>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {mapState} from "vuex";
|
||||
import Vue from "vue";
|
||||
import {scrollBoard} from "@jiaminghi/data-view";
|
||||
|
||||
Vue.use(scrollBoard)
|
||||
export default {
|
||||
name: "AppVideoMonitoringDV",
|
||||
label: "数据大屏-平安小区",
|
||||
inject: {
|
||||
dv: {default: ""}
|
||||
},
|
||||
props: {
|
||||
instance: Function
|
||||
},
|
||||
computed: {
|
||||
...mapState(['user']),
|
||||
cardList() {
|
||||
return [
|
||||
{label: "总设备数", value: "0"},
|
||||
{label: "在线设备", value: "0"},
|
||||
{label: "离线设备", value: "0"},
|
||||
{label: "设备在线率", value: "0%"},
|
||||
]
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
meta: {},
|
||||
config: {
|
||||
data: [
|
||||
],
|
||||
columnWidth: [60, 140],
|
||||
header: ["机构", "设备在线率"],
|
||||
headerBGC: '',
|
||||
headerHeight: 41,
|
||||
oddRowBGC: "",
|
||||
evenRowBGC: "",
|
||||
align: ["center", "center", "center"],
|
||||
rowNum: 10,
|
||||
index: true,
|
||||
indexHeader: "排名"
|
||||
},
|
||||
config1: {
|
||||
data: [
|
||||
['普通用户', '-'],
|
||||
['村级管理员', '-'],
|
||||
['超级管理员', '-'],
|
||||
['测试', '-'],
|
||||
],
|
||||
headerHeight: 41,
|
||||
oddRowBGC: "",
|
||||
evenRowBGC: "",
|
||||
align: ["left", "left", "right"],
|
||||
index: true,
|
||||
rowNum: 6,
|
||||
columnWidth: [50]
|
||||
},
|
||||
start: 0,
|
||||
end: 40,
|
||||
start1: 0,
|
||||
end1: 40,
|
||||
interval: null,
|
||||
videoData: [],
|
||||
flag: false,
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
jsonObj(val) {
|
||||
return JSON.parse(val || "{}")?.url
|
||||
},
|
||||
getOpt(type = "0") {
|
||||
let opt = {
|
||||
"0": {
|
||||
xData: ['2020/7/1', "2020/7/2", "2020/7/3", "2020/7/4", "2020/7/5", "2020/7/6", "2020/7/7", "2020/7/8", "2020/7/9", "2020/7/10", "2020/7/11"],
|
||||
yData: Array(11).fill(0),
|
||||
color: "#FFEA2F",
|
||||
areaStyle: 'rgba(255,234,47,0.2)',
|
||||
unit: '',
|
||||
},
|
||||
"1": {
|
||||
xData: ["1:00", "2:00", "3:00", "4:00", "5:00", "6:00", "7:00", "8:00", "9:00", "10:00"],
|
||||
yData: Array(10).fill(0),
|
||||
color: "#13B5B1",
|
||||
areaStyle: 'rgba(255,234,47,0.2)',
|
||||
unit: '次',
|
||||
},
|
||||
}
|
||||
return {
|
||||
grid: {
|
||||
top: "5%",
|
||||
left: "16%",
|
||||
right: "3%",
|
||||
bottom: "12%"
|
||||
},
|
||||
xAxis: {
|
||||
show: true,
|
||||
boundaryGap: false,
|
||||
type: 'category',
|
||||
axisLabel: {
|
||||
show: true,
|
||||
textStyle: {
|
||||
color: "#5E9CEA",
|
||||
fontSize: 12
|
||||
}
|
||||
},
|
||||
axisLine: {
|
||||
show: false
|
||||
},
|
||||
axisTick: {
|
||||
show: false
|
||||
},
|
||||
data: opt[type]["xData"]
|
||||
},
|
||||
yAxis: {
|
||||
type: 'value',
|
||||
show: true,
|
||||
axisTick: {
|
||||
show: false
|
||||
},
|
||||
axisLine: {
|
||||
show: false
|
||||
},
|
||||
splitLine: {
|
||||
show: true,
|
||||
lineStyle: {
|
||||
color: ['#103066'],
|
||||
}
|
||||
},
|
||||
axisLabel: {
|
||||
show: true,
|
||||
formatter: (val) => `${val}${opt[type]["unit"]}`,
|
||||
textStyle: {
|
||||
color: "#5E9CEA",
|
||||
fontSize: 12
|
||||
}
|
||||
},
|
||||
},
|
||||
series: [{
|
||||
symbol: "none",
|
||||
data: opt[type]["yData"],
|
||||
type: 'line',
|
||||
itemStyle: {
|
||||
normal: {
|
||||
color: opt[type]["color"],
|
||||
areaStyle: {
|
||||
color: {
|
||||
type: 'linear', x2: 0, y2: 1, colorStops: [
|
||||
{offset: 0, color: opt[type]["areaStyle"]}, {offset: 1, color: '#000000'}]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}]
|
||||
}
|
||||
},
|
||||
getWebSdkUrlForScreen() {
|
||||
this.instance.post(`/app/appzyvideoequipment/getWebSdkUrlForTianQiaoScreen`).then(res => {
|
||||
if (res.code == 0) {
|
||||
this.videoData = res.data
|
||||
this.flag = true
|
||||
}
|
||||
})
|
||||
}
|
||||
},
|
||||
beforeDestroy() {
|
||||
this.interval && clearInterval(this.interval);
|
||||
},
|
||||
mounted() {
|
||||
// this.getWebSdkUrlForScreen()
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.AppVideoMonitoringDV {
|
||||
height: 100%;
|
||||
padding: 6px 0 10px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 24px;
|
||||
|
||||
.body {
|
||||
height: 100%;
|
||||
|
||||
.left-wrap {
|
||||
width: 307px;
|
||||
height: 100%;
|
||||
|
||||
.left-top {
|
||||
width: 100%;
|
||||
background-image: url("./assets/videoMonitor/box1.png");
|
||||
background-size: 100% 100%;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
|
||||
.table {
|
||||
box-sizing: border-box;
|
||||
padding: 63px 17px 17px;
|
||||
}
|
||||
}
|
||||
|
||||
.left-bottom {
|
||||
width: 100%;
|
||||
height: 311px;
|
||||
background-image: url("./assets/videoMonitor/box2.png");
|
||||
background-size: 100% 100%;
|
||||
margin-top: 7px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
position: relative;
|
||||
|
||||
.AiMap {
|
||||
width: 274px;
|
||||
height: 247px;
|
||||
margin-top: 40px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.center-wrap {
|
||||
width: 1183px;
|
||||
height: 100%;
|
||||
|
||||
.card {
|
||||
height: 93.3px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
background-image: url("./assets/videoMonitor/card.png");
|
||||
background-size: 100% 100%;
|
||||
margin-right: 24px;
|
||||
|
||||
&:last-child {
|
||||
margin-right: 0;
|
||||
}
|
||||
|
||||
& > span:first-child {
|
||||
font-size: 20px;
|
||||
font-weight: 400;
|
||||
color: #FFFFFF;
|
||||
}
|
||||
|
||||
& > span:last-child {
|
||||
font-size: 38px;
|
||||
font-family: dineng, serif;
|
||||
font-weight: bold;
|
||||
color: #00EDFF;
|
||||
margin-left: 13px;
|
||||
}
|
||||
}
|
||||
|
||||
.center-bottom {
|
||||
width: 100%;
|
||||
height: 789px;
|
||||
background-image: url("./assets/videoMonitor/middlebox.png");
|
||||
background-size: 100% 100%;
|
||||
margin-top: 40px;
|
||||
position: relative;
|
||||
box-sizing: border-box;
|
||||
padding: 61px;
|
||||
|
||||
.video-wrap {
|
||||
width: 100%;
|
||||
height: 344px;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
margin-bottom: 12px;
|
||||
|
||||
.item {
|
||||
.video {
|
||||
width: 522px;
|
||||
height: 296px;
|
||||
object-fit: fill;
|
||||
vertical-align: bottom;
|
||||
border: 2px solid #122C7D;
|
||||
}
|
||||
|
||||
.info {
|
||||
height: 48px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
box-sizing: border-box;
|
||||
padding: 0 12px;
|
||||
background-color: #071153;
|
||||
font-size: 14px;
|
||||
color: #FFFFFF;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.right-wrap {
|
||||
width: 297px;
|
||||
height: 100%;
|
||||
|
||||
.right-top {
|
||||
width: 100%;
|
||||
height: 333px;
|
||||
background-image: url("./assets/videoMonitor/box3.png");
|
||||
background-size: 100% 100%;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
|
||||
.total {
|
||||
font-size: 16px;
|
||||
color: #979AB7;
|
||||
display: inline-block;
|
||||
margin: 65px 0 16px 23px;
|
||||
|
||||
& > span:nth-child(1) {
|
||||
font-size: 28px;
|
||||
font-family: dineng, serif;
|
||||
font-weight: bold;
|
||||
color: #01CAFF;
|
||||
}
|
||||
|
||||
& > span:nth-child(2) {
|
||||
font-size: 16px;
|
||||
color: #01CAFF;
|
||||
}
|
||||
}
|
||||
|
||||
.total-table {
|
||||
height: 200px;
|
||||
box-sizing: border-box;
|
||||
padding: 0 23px;
|
||||
}
|
||||
}
|
||||
|
||||
.right-middle, .right-bottom {
|
||||
width: 100%;
|
||||
height: 276px;
|
||||
background-image: url("./assets/videoMonitor/box4.png");
|
||||
background-size: 100% 100%;
|
||||
margin: 19px 0;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
|
||||
.tag {
|
||||
margin: 28px 18px 0 0;
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
font-size: 12px;
|
||||
color: #5E9CEA;
|
||||
|
||||
& > span {
|
||||
font-size: 12px;
|
||||
color: #FFFFFF;
|
||||
display: inline-block;
|
||||
width: 34px;
|
||||
height: 17px;
|
||||
text-align: center;
|
||||
line-height: 18px;
|
||||
margin-left: 14px;
|
||||
}
|
||||
}
|
||||
|
||||
:deep( .AiEchart ){
|
||||
width: 251px;
|
||||
height: 175px;
|
||||
margin: 11px auto 0;
|
||||
}
|
||||
|
||||
.info {
|
||||
font-size: 12px;
|
||||
color: #FFFFFF;
|
||||
line-height: 24px;
|
||||
box-sizing: border-box;
|
||||
padding: 15px 19px 0;
|
||||
|
||||
& > span:nth-child(2n+1) {
|
||||
font-size: 18px;
|
||||
font-weight: 400;
|
||||
line-height: 24px;
|
||||
color: #FFE930;
|
||||
}
|
||||
|
||||
& > span:nth-child(2n) {
|
||||
font-size: 14px;
|
||||
font-weight: 400;
|
||||
color: #FFE930;
|
||||
line-height: 24px;
|
||||
margin: 0 5px;
|
||||
}
|
||||
|
||||
& > span:nth-child(2) {
|
||||
margin-right: 22px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.right-bottom {
|
||||
margin: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.label {
|
||||
position: absolute;
|
||||
left: 24px;
|
||||
top: 23px;
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
color: #FFFFFF;
|
||||
}
|
||||
|
||||
:deep( .index ){
|
||||
background-color: transparent !important;
|
||||
}
|
||||
|
||||
:deep( .header ){
|
||||
background: url("./assets/videoMonitor/titlebox.png");
|
||||
}
|
||||
|
||||
:deep( .row-item div:nth-child(3) ){
|
||||
font-size: 13px;
|
||||
color: #00CDFF;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
Before Width: | Height: | Size: 362 KiB |
|
Before Width: | Height: | Size: 11 KiB |
|
Before Width: | Height: | Size: 3.3 KiB |
|
Before Width: | Height: | Size: 693 KiB |
|
Before Width: | Height: | Size: 11 KiB |
|
Before Width: | Height: | Size: 24 KiB |
|
Before Width: | Height: | Size: 11 KiB |
|
Before Width: | Height: | Size: 445 B |
|
Before Width: | Height: | Size: 26 KiB |
|
Before Width: | Height: | Size: 140 KiB |
|
Before Width: | Height: | Size: 4.5 KiB |
|
Before Width: | Height: | Size: 3.5 KiB |
|
Before Width: | Height: | Size: 3.6 KiB |
|
Before Width: | Height: | Size: 3.4 KiB |
|
Before Width: | Height: | Size: 3.0 KiB |
|
Before Width: | Height: | Size: 8.0 KiB |
|
Before Width: | Height: | Size: 5.2 KiB |
@@ -1,190 +0,0 @@
|
||||
<template>
|
||||
<div class="DoughnutChart-wrapper">
|
||||
<div class="DoughnutChart" :id="id">
|
||||
<canvas :id="canvasId"></canvas>
|
||||
<div class="DonutChart-text">
|
||||
<span>{{ ratio }}%</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="DoughnutChart-explain">
|
||||
<div class="item" v-for="(item, index) in value" :key="index">
|
||||
<i></i>
|
||||
<span :style="labelStyle">{{ item.key }}</span>
|
||||
<p>{{ item.value }}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
props: ['ratio', 'value', 'labelStyle'],
|
||||
|
||||
data () {
|
||||
return {
|
||||
id: `DonutChart-${Math.ceil(Math.random() * 10000)}`,
|
||||
canvasId: `DonutChartCanvas-${Math.ceil(Math.random() * 10000)}`,
|
||||
canvasWidth: 90,
|
||||
canvasHeight: 90
|
||||
}
|
||||
},
|
||||
|
||||
watch: {
|
||||
ratio () {
|
||||
this.init()
|
||||
}
|
||||
},
|
||||
|
||||
mounted () {
|
||||
this.$nextTick(() => {
|
||||
this.init()
|
||||
})
|
||||
},
|
||||
|
||||
methods: {
|
||||
drawLine(ctx, options) {
|
||||
const { beginX, beginY, endX, endY, lineColor, lineWidth } = options
|
||||
ctx.lineWidth = lineWidth
|
||||
ctx.strokeStyle = lineColor
|
||||
ctx.beginPath()
|
||||
ctx.moveTo(beginX, beginY)
|
||||
ctx.lineTo(endX, endY)
|
||||
ctx.closePath()
|
||||
ctx.stroke()
|
||||
},
|
||||
|
||||
angle (a, i, ox, oy, or) {
|
||||
var hudu = (2 * Math.PI / 360) * a * i
|
||||
var x = ox + Math.sin(hudu) * or
|
||||
var y = oy - Math.cos(hudu) * or
|
||||
return x + '_' + y
|
||||
},
|
||||
|
||||
mapColor (value) {
|
||||
if (value < 25) {
|
||||
return '#FFC139'
|
||||
}
|
||||
|
||||
if (value < 50) {
|
||||
return '#21E03E'
|
||||
}
|
||||
|
||||
return '#05C8FF'
|
||||
},
|
||||
|
||||
init () {
|
||||
const ctx = document.querySelector(`#${this.canvasId}`).getContext('2d')
|
||||
const canvasWidth = document.querySelector(`#${this.id}`).offsetWidth
|
||||
const canvasHeight = document.querySelector(`#${this.id}`).offsetHeight
|
||||
const angle = this.ratio / 100 * 2
|
||||
let radian = 0
|
||||
|
||||
ctx.width = canvasWidth
|
||||
ctx.height = canvasHeight
|
||||
const x = canvasWidth / 2
|
||||
const y = canvasHeight / 2
|
||||
ctx.lineWidth = 4
|
||||
ctx.strokeStyle = 'rgba(102, 121, 138, 0.3)'
|
||||
ctx.beginPath();
|
||||
ctx.arc(x, y, x - 8, 0, 2 * Math.PI)
|
||||
ctx.stroke()
|
||||
|
||||
ctx.beginPath()
|
||||
ctx.lineWidth = 4
|
||||
var g = ctx.createLinearGradient(0, 0, 0, 80)
|
||||
g.addColorStop(0, 'rgba(44, 150, 231, 0.8)')
|
||||
g.addColorStop(1, 'rgba(92, 255, 243, 1)')
|
||||
ctx.strokeStyle = g
|
||||
|
||||
if (this.ratio < 25) {
|
||||
radian = 3 / 2 + angle
|
||||
ctx.arc(x, y, x - 8, Math.PI + Math.PI / 2, Math.PI * radian, false)
|
||||
} else if (this.ratio === 100) {
|
||||
ctx.arc(x, y, x - 8, 0, Math.PI * 2)
|
||||
} else {
|
||||
radian = (this.ratio - 25) / 100 * 2
|
||||
ctx.arc(x, y, x - 8, Math.PI + Math.PI / 2, Math.PI * radian, false)
|
||||
}
|
||||
ctx.stroke()
|
||||
|
||||
ctx.beginPath()
|
||||
ctx.strokeStyle = 'rgba(102, 121, 138, 0.4)'
|
||||
ctx.lineWidth = 1
|
||||
ctx.arc(x, y, x - 15, 0, 2 * Math.PI)
|
||||
ctx.stroke()
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.DoughnutChart-wrapper {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
height: 100%;
|
||||
padding-top: 12px;
|
||||
|
||||
.DoughnutChart-explain {
|
||||
flex: 1;
|
||||
margin-left: 10px;
|
||||
|
||||
.item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
&:first-child {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
i {
|
||||
width: 8px;
|
||||
height: 8px;
|
||||
margin-right: 6px;
|
||||
border-radius: 50%;
|
||||
background: #5AF9F0;
|
||||
}
|
||||
|
||||
span {
|
||||
width: 78px;
|
||||
font-weight: 400;
|
||||
font-size: 14px;
|
||||
color: #9BB7D4;
|
||||
}
|
||||
|
||||
p {
|
||||
font-size: 14px;
|
||||
color: #FFFFFF;
|
||||
}
|
||||
|
||||
&:last-child i {
|
||||
background: rgba(102, 121, 138, 0.3);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
.DoughnutChart {
|
||||
position: relative;
|
||||
width: 90px;
|
||||
height: 90px;
|
||||
overflow: hidden;
|
||||
|
||||
.DonutChart-text {
|
||||
display: flex;
|
||||
position: absolute;
|
||||
justify-content: center;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
z-index: 1;
|
||||
transform: translate(-50%, -50%);
|
||||
|
||||
span {
|
||||
font-size: 17px;
|
||||
font-weight: bold;
|
||||
color: #02FEFF;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -1,386 +0,0 @@
|
||||
<template>
|
||||
<div class="AiDvMap">
|
||||
<div class="chart-map" :class="v" style="width: 100%; height: 100%"></div>
|
||||
<transition name="fade">
|
||||
<div class="info" v-if="isShowInfo">
|
||||
<div class="info-mask" @click="isShowInfo = false"></div>
|
||||
<div class="info-content">
|
||||
<div class="info-title">
|
||||
<h2>{{ title }}</h2>
|
||||
</div>
|
||||
<img src="https://cdn.cunwuyun.cn/dvcp/dv/qxn/close.png" @click="isShowInfo = false" />
|
||||
<div class="info-wrapper" v-if="type === '0'">
|
||||
<div class="info-wrapper__item">
|
||||
<label>下属单位:</label>
|
||||
<span>{{ info['派出所数量'] }}个派出所</span>
|
||||
</div>
|
||||
<div class="info-wrapper__item">
|
||||
<label>居民群:</label>
|
||||
<span>{{ info['群数量'] }}</span>
|
||||
</div>
|
||||
<div class="info-wrapper__item">
|
||||
<label>成员人数:</label>
|
||||
<span>{{ info['成员总数'] }}</span>
|
||||
</div>
|
||||
<div class="info-wrapper__item">
|
||||
<label>群人数:</label>
|
||||
<span>{{ info['群成员数量'] }}</span>
|
||||
</div>
|
||||
<div class="info-wrapper__item">
|
||||
<label>激活比例:</label>
|
||||
<span>{{ rate }}</span>
|
||||
</div>
|
||||
<div class="info-wrapper__item">
|
||||
<label>好友人数:</label>
|
||||
<span>{{ info['外部联系人数量'] }}</span>
|
||||
</div>
|
||||
<div class="info-wrapper__item">
|
||||
<label>群主人数:</label>
|
||||
<span>{{ info['群主人数'] }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="info-wrapper" v-else>
|
||||
<div class="info-wrapper__item">
|
||||
<label>负责人:</label>
|
||||
<span>{{ info['负责人'] }}</span>
|
||||
</div>
|
||||
<div class="info-wrapper__item">
|
||||
<label>下属警格数:</label>
|
||||
<span>{{ info['下属警格数量'] }}</span>
|
||||
</div>
|
||||
<div class="info-wrapper__item">
|
||||
<label>警格人数:</label>
|
||||
<span>{{ info['外部联系人数量'] }}</span>
|
||||
</div>
|
||||
<div class="info-wrapper__item">
|
||||
<label>事件处理率:</label>
|
||||
<span>{{ rate }}</span>
|
||||
</div>
|
||||
<div class="info-wrapper__item">
|
||||
<label>待处理:</label>
|
||||
<span>{{ info['待受理'] }}</span>
|
||||
</div>
|
||||
<div class="info-wrapper__item">
|
||||
<label>处理中:</label>
|
||||
<span>{{ info['办理中'] }}</span>
|
||||
</div>
|
||||
<div class="info-wrapper__item">
|
||||
<label>已办理:</label>
|
||||
<span>{{ info['已办结'] }}</span>
|
||||
</div>
|
||||
<div class="info-wrapper__item">
|
||||
<label>事件总数:</label>
|
||||
<span>{{ info['事件总数'] }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</transition>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
||||
|
||||
export default {
|
||||
name: 'AiDvMap',
|
||||
|
||||
props: {
|
||||
instance: Function,
|
||||
type: String
|
||||
},
|
||||
|
||||
data() {
|
||||
return {
|
||||
info: {},
|
||||
timer: null,
|
||||
title: '',
|
||||
v: `AiDvMap-${new Date().getTime()}`,
|
||||
chart: null,
|
||||
isShowInfo: false,
|
||||
geoJSON: require('./geoJSon/qxnGeoJSON.json')
|
||||
}
|
||||
},
|
||||
|
||||
computed: {
|
||||
rate () {
|
||||
if (!this.info['事件总数']) {
|
||||
return '0%'
|
||||
}
|
||||
|
||||
return ((this.info['事件总数'] - this.info['待受理']) / this.info['事件总数']).toFixed(4) * 100 + '%'
|
||||
}
|
||||
},
|
||||
|
||||
mounted() {
|
||||
this.$nextTick(() => {
|
||||
this.initChart()
|
||||
})
|
||||
},
|
||||
|
||||
methods: {
|
||||
initChart() {
|
||||
this.chart = echarts.init(document.querySelector(`.${this.v}`))
|
||||
echarts.registerMap('黔西南', this.geoJSON)
|
||||
|
||||
let option = {
|
||||
geo: [
|
||||
{
|
||||
map: "黔西南",
|
||||
aspectScale: 1,
|
||||
zoom: 0.65,
|
||||
layoutCenter: ["50%", "50%"],
|
||||
layoutSize: "180%",
|
||||
show: true,
|
||||
roam: false,
|
||||
emphasis: {
|
||||
show: true,
|
||||
label: {
|
||||
textStyle: {
|
||||
color: "#FFFFFF"
|
||||
},
|
||||
},
|
||||
itemStyle: {
|
||||
// areaColor: '#fff'
|
||||
}
|
||||
},
|
||||
label: {
|
||||
normal: {
|
||||
show: true,
|
||||
color: '#fff',
|
||||
fontSize: '14'
|
||||
}
|
||||
},
|
||||
itemStyle: {
|
||||
normal: {
|
||||
borderColor: "rgba(2, 254, 255, 0.7)",
|
||||
borderWidth: 2,
|
||||
shadowColor: "rgba(2, 254, 255, 0.1)",
|
||||
shadowOffsetY: 10,
|
||||
shadowBlur: 120,
|
||||
areaColor: "#0f7295",
|
||||
},
|
||||
}
|
||||
},
|
||||
// 重影
|
||||
{
|
||||
type: "map",
|
||||
map: "黔西南",
|
||||
zlevel: -1,
|
||||
aspectScale: 1,
|
||||
zoom: 0.65,
|
||||
layoutCenter: ["50%", "51%"],
|
||||
layoutSize: "180%",
|
||||
roam: false,
|
||||
silent: true,
|
||||
itemStyle: {
|
||||
normal: {
|
||||
borderWidth: 1,
|
||||
// borderColor:"rgba(17, 149, 216,0.6)",
|
||||
borderColor: "rgba(2, 254, 255, 0.3)",
|
||||
shadowColor: "rgba(2, 254, 255, 0.3)",
|
||||
shadowOffsetY: 5,
|
||||
shadowBlur: 15,
|
||||
areaColor: "rgba(5,21,35,0.1)",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
type: "map",
|
||||
map: "黔西南",
|
||||
zlevel: -2,
|
||||
aspectScale: 1,
|
||||
zoom: 0.65,
|
||||
layoutCenter: ["50%", "52%"],
|
||||
layoutSize: "180%",
|
||||
roam: false,
|
||||
silent: true,
|
||||
itemStyle: {
|
||||
normal: {
|
||||
borderWidth: 1,
|
||||
// borderColor: "rgba(57, 132, 188,0.4)",
|
||||
borderColor: "rgba(2, 254, 255, 0.2)",
|
||||
shadowColor: "rgba(2, 254, 255, 0.24)",
|
||||
shadowOffsetY: 5,
|
||||
shadowBlur: 15,
|
||||
areaColor: "transpercent",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
type: "map",
|
||||
map: "黔西南",
|
||||
zlevel: -3,
|
||||
aspectScale: 1,
|
||||
zoom: 0.65,
|
||||
layoutCenter: ["50%", "53%"],
|
||||
layoutSize: "180%",
|
||||
roam: false,
|
||||
silent: true,
|
||||
itemStyle: {
|
||||
normal: {
|
||||
borderWidth: 1,
|
||||
// borderColor: "rgba(11, 43, 97,0.8)",
|
||||
borderColor: "rgba(2, 254, 255, 0.1)",
|
||||
shadowColor: "rgba(2, 254, 255, 0.1)",
|
||||
shadowOffsetY: 15,
|
||||
shadowBlur: 10,
|
||||
areaColor: "transpercent",
|
||||
},
|
||||
},
|
||||
}
|
||||
],
|
||||
series: [
|
||||
{
|
||||
type: 'scatter',
|
||||
map: "黔西南",
|
||||
coordinateSystem: 'geo',
|
||||
z: 3,
|
||||
zlevel: 3,
|
||||
// symbol: 'none',
|
||||
symbolSize: 16,
|
||||
rippleEffect: {
|
||||
period: 2,
|
||||
scale: 4,
|
||||
brushType: 'fill'
|
||||
},
|
||||
label: {
|
||||
show: false
|
||||
},
|
||||
roam: false,
|
||||
itemStyle: {
|
||||
normal: {
|
||||
areaColor: '#000',
|
||||
borderColor: '#a18a3a',
|
||||
borderWidth: 1
|
||||
},
|
||||
emphasis: {
|
||||
show: false,
|
||||
areaColor: null
|
||||
}
|
||||
},
|
||||
data: []
|
||||
}
|
||||
]
|
||||
}
|
||||
this.chart.setOption(option)
|
||||
this.chart.on('click', e => {
|
||||
this.getInfo(e.name)
|
||||
})
|
||||
},
|
||||
|
||||
getInfo (name) {
|
||||
this.title = `${name}公安局`
|
||||
this.instance.post(`/api/wxgridinfo/comprehensiveOverviewMap`, null, {
|
||||
params: {
|
||||
gridName: `${name}公安局`,
|
||||
corpId: 'wwb182f88f0327b37f'
|
||||
}
|
||||
}).then(res => {
|
||||
if (res.code === 0) {
|
||||
this.info = res.data
|
||||
this.isShowInfo = true
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.AiDvMap {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
|
||||
.info {
|
||||
position: fixed;
|
||||
left: 0;
|
||||
top: 0;
|
||||
z-index: 111;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
overflow: hidden;
|
||||
|
||||
.info-mask {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
z-index: 1;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: rgba($color: #000000, $alpha: 0.1);
|
||||
}
|
||||
|
||||
.info-content {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
z-index: 11;
|
||||
width: 390px;
|
||||
height: 262px;
|
||||
padding: 15px 18px 0;
|
||||
background: url(https://cdn.cunwuyun.cn/dvcp/dv/qxn/info-bg.png);
|
||||
background-size: 100% 100%;
|
||||
transform: translate(-50%, -50%);
|
||||
|
||||
.info-wrapper {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
justify-content: space-between;
|
||||
margin-top: 40px;
|
||||
|
||||
.info-wrapper__item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
width: 50%;
|
||||
line-height: 1;
|
||||
margin-bottom: 20px;
|
||||
|
||||
label {
|
||||
width: 90px;
|
||||
margin-right: 10px;
|
||||
color: #fff;
|
||||
text-align: right;
|
||||
font-size: 14px;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
span {
|
||||
flex: 1;
|
||||
font-size: 14px;
|
||||
color: #FF8533;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
img {
|
||||
position: absolute;
|
||||
top: 30px;
|
||||
right: 18px;
|
||||
z-index: 1;
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
cursor: pointer;
|
||||
transition: all ease 300ms;
|
||||
|
||||
&:hover {
|
||||
opacity: 0.6;
|
||||
}
|
||||
}
|
||||
|
||||
.info-title {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
h2 {
|
||||
font-size: 16px;
|
||||
color: #fff;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -1,334 +0,0 @@
|
||||
<template>
|
||||
<div class="PlyGird">
|
||||
<div class="pdgrid-title">
|
||||
<h2>{{ currGird }}</h2>
|
||||
</div>
|
||||
<div class="pdgrid-body">
|
||||
<div class="pdgrid-body__item" @click="isShowGrid2 = true">
|
||||
<h2>{{ girdNum2 }}</h2>
|
||||
<div class="bottom">
|
||||
<i></i>
|
||||
<p>{{ girdName2 }}</p>
|
||||
<i class="right"></i>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<transition name="fade">
|
||||
<div class="grid-dialog" v-show="isShowGrid2">
|
||||
<div class="mask" @click="isShowGrid2 = false"></div>
|
||||
<div class="grid-container">
|
||||
<h2 :title="girdName2">{{ girdName2 }}</h2>
|
||||
<div class="grid-list">
|
||||
<div
|
||||
:class="[currIndex2 === index ? 'grid-active' : '']"
|
||||
v-for="(item, index) in girdInfoList2"
|
||||
:key="index"
|
||||
:title="item.girdName"
|
||||
@click.stop="onGrid2Click(item, index)">
|
||||
{{ item.girdName }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</transition>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'pdgrid',
|
||||
|
||||
props: ['instance'],
|
||||
|
||||
data () {
|
||||
return {
|
||||
isShowGrid2: false,
|
||||
currIndex2: 0,
|
||||
girdInfoList2: [],
|
||||
girdName2: '',
|
||||
girdNum2: 0,
|
||||
currGird: ''
|
||||
}
|
||||
},
|
||||
|
||||
mounted () {
|
||||
this.$nextTick(() => {
|
||||
document.addEventListener('keydown', this.onKeyDown)
|
||||
})
|
||||
this.getInfo()
|
||||
},
|
||||
|
||||
destroyed () {
|
||||
document.removeEventListener('keydown', this.onKeyDown)
|
||||
},
|
||||
|
||||
methods: {
|
||||
onKeyDown (e) {
|
||||
if (e.keyCode == 27) {
|
||||
this.isShowGrid2 = false
|
||||
}
|
||||
},
|
||||
|
||||
onGrid2Click (item, index) {
|
||||
this.currIndex2 = index
|
||||
this.girdName2 = item.girdName
|
||||
this.isShowGrid2 = false
|
||||
this.$emit('nodeClick', item.id)
|
||||
|
||||
this.currGird = item.girdName
|
||||
this.getInfo(item.id)
|
||||
},
|
||||
|
||||
getInfo (id) {
|
||||
this.instance.post(`/app/appgirdinfo/queryPlyDetailByGirdId?id=${id || ''}`).then(res => {
|
||||
if (res.code === 0) {
|
||||
res.data.girdInfoList2 && (this.girdInfoList2 = res.data.girdInfoList2)
|
||||
res.data.girdName2 && (this.girdName2 = res.data.girdName2)
|
||||
res.data.girdNum2 != null && (this.girdNum2 = res.data.girdNum2)
|
||||
res.data.girdName1 && (this.currGird = res.data.girdName1)
|
||||
|
||||
if (!id) {
|
||||
this.currIndex2 = res.data.girdInfoList2.findIndex(v => res.data.girdName2 === v.girdName)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.PlyGird {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
overflow: hidden;
|
||||
box-sizing: border-box;
|
||||
background: url(https://cdn.cunwuyun.cn/dvcp/dv/pddv/middle-bg.png) no-repeat center;
|
||||
background-size: contain;
|
||||
|
||||
.fade-enter-active, .fade-leave-active {
|
||||
transition: opacity .3s ease-in-out;
|
||||
}
|
||||
.fade-enter, .fade-leave-to {
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
* {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.pdgrid-grid__title {
|
||||
position: absolute;
|
||||
top: 40px;
|
||||
left: 50%;
|
||||
width: 271px;
|
||||
height: 53px;
|
||||
line-height: 53px;
|
||||
text-align: center;
|
||||
background: url(https://cdn.cunwuyun.cn/dvcp/dv/pddv/grid-title-sbg.png) no-repeat center;
|
||||
background-size: 100% 100%;
|
||||
cursor: pointer;
|
||||
transform: translateX(-50%);
|
||||
transition: opacity ease 0.3s;
|
||||
|
||||
&:hover {
|
||||
opacity: 0.8;
|
||||
}
|
||||
|
||||
h2 {
|
||||
width: 182px;
|
||||
margin: 0 auto;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
color: #FFFFFF;
|
||||
font-size: 21px;
|
||||
text-shadow: 0px 0px 13px rgb(59 182 255 / 80%);
|
||||
background: #fff;
|
||||
-webkit-background-clip: text;
|
||||
-webkit-text-fill-color: transparent;
|
||||
}
|
||||
}
|
||||
|
||||
.pdgrid-title {
|
||||
position: absolute;
|
||||
top: 200px;
|
||||
left: 50%;
|
||||
min-width: 640px;
|
||||
height: 80px;
|
||||
line-height: 80px;
|
||||
text-align: center;
|
||||
background: url(https://cdn.cunwuyun.cn/dvcp/dv/pddv/middle-titlebg.png) no-repeat center;
|
||||
background-size: 100% 100%;
|
||||
transform: translateX(-50%);
|
||||
|
||||
h2 {
|
||||
color: #FFFFFF;
|
||||
font-size: 22px;
|
||||
white-space: nowrap;
|
||||
text-shadow: 0px 0px 13px rgb(59 182 255 / 80%);
|
||||
background: #fff;
|
||||
-webkit-background-clip: text;
|
||||
-webkit-text-fill-color: transparent;
|
||||
}
|
||||
}
|
||||
|
||||
.pdgrid-body {
|
||||
display: flex;
|
||||
position: absolute;
|
||||
justify-content: center;
|
||||
bottom: 133px;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
padding: 0 112px;
|
||||
|
||||
.pdgrid-body__item {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
width: 200px;
|
||||
height: 187px;
|
||||
align-items: center;
|
||||
padding-top: 71px;
|
||||
cursor: pointer;
|
||||
background: url(https://cdn.cunwuyun.cn/dvcp/dv/pddv/item-bg.png) no-repeat center;
|
||||
background-size: 100% 100%;
|
||||
transition: opacity ease 0.3s;
|
||||
|
||||
&:hover {
|
||||
opacity: 0.8;
|
||||
}
|
||||
|
||||
h2 {
|
||||
font-size: 36px;
|
||||
color: #FFFFFF;
|
||||
text-shadow: 0px 0px 13px rgb(59 182 255 / 80%);
|
||||
background: #fff;
|
||||
-webkit-background-clip: text;
|
||||
-webkit-text-fill-color: transparent;
|
||||
}
|
||||
|
||||
p {
|
||||
max-width: 164px;
|
||||
margin-top: 4px;
|
||||
padding: 0 16px;
|
||||
font-size: 16px;
|
||||
color: #FFFFFF;
|
||||
text-shadow: 0px 0px 13px rgb(59 182 255 / 80%);
|
||||
background: #fff;
|
||||
-webkit-background-clip: text;
|
||||
font-weight: 600;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
-webkit-text-fill-color: transparent;
|
||||
}
|
||||
|
||||
.bottom {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
i {
|
||||
width: 0px;
|
||||
height: 0px;
|
||||
border: 6px solid transparent;
|
||||
border-top-color: transparent;
|
||||
border-bottom-color: transparent;
|
||||
border-left-color: transparent;
|
||||
border-right-color: #FFCB42;
|
||||
|
||||
&.right {
|
||||
width: 0px;
|
||||
height: 0px;
|
||||
border: 6px solid transparent;
|
||||
border-top-color: transparent;
|
||||
border-bottom-color: transparent;
|
||||
border-left-color: #FFCB42;
|
||||
border-right-color: transparent;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.grid-dialog {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
z-index: 111;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
|
||||
& > .mask {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
z-index: 1;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: rgba(0, 0, 0, 0.5);
|
||||
}
|
||||
|
||||
.grid-container {
|
||||
display: flex;
|
||||
position: absolute;
|
||||
flex-direction: column;
|
||||
left: 50%;
|
||||
top: 50%;
|
||||
z-index: 2;
|
||||
width: 640px;
|
||||
height: 640px;
|
||||
background: rgba(7,13,41,0.9);
|
||||
border: 1px solid #144662;
|
||||
transform: translate(-50%, -50%);
|
||||
|
||||
& > h2 {
|
||||
width: 100%;
|
||||
height: 67px;
|
||||
line-height: 67px;
|
||||
padding: 0 20px;
|
||||
text-align: center;
|
||||
color: #FFFFFF;
|
||||
font-size: 24px;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
text-shadow: 0px 0px 13px rgb(59 182 255 / 80%);
|
||||
background: url(https://cdn.cunwuyun.cn/dvcp/dv/pddv/grid-title-bg.png) no-repeat center;
|
||||
background-size: 100% 100%;
|
||||
}
|
||||
|
||||
.grid-list {
|
||||
flex: 1;
|
||||
overflow-y: auto;
|
||||
|
||||
& > div {
|
||||
height: 67px;
|
||||
line-height: 67px;
|
||||
padding: 0 20px;
|
||||
text-align: center;
|
||||
color: #FFFFFF;
|
||||
font-size: 27px;
|
||||
cursor: pointer;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
transition: all ease 0.5s;
|
||||
|
||||
&.grid-active {
|
||||
background: linear-gradient(270deg, rgba(0,48,124,0) 0%, #00307C 16%, rgba(0,99,255,0.9100) 50%, rgba(0,48,124,0.8200) 87%, rgba(0,48,124,0) 100%);
|
||||
box-shadow: inset 0px -1px 0px 0px rgba(16,34,54,1);
|
||||
text-shadow: 0px 3px 5px rgba(0,0,0,0.5000);
|
||||
}
|
||||
|
||||
&:hover {
|
||||
background: linear-gradient(270deg, rgba(0,48,124,0) 0%, #00307C 16%, rgba(0,99,255,0.9100) 50%, rgba(0,48,124,0.8200) 87%, rgba(0,48,124,0) 100%);
|
||||
box-shadow: inset 0px -1px 0px 0px rgba(16,34,54,1);
|
||||
text-shadow: 0px 3px 5px rgba(0,0,0,0.5000);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -1,498 +0,0 @@
|
||||
<template>
|
||||
<div class="pdgrid">
|
||||
<div class="pdgrid-title">
|
||||
<h2>{{ currGird }}</h2>
|
||||
</div>
|
||||
<div class="pdgrid-grid__title" @click="isShowGrid2 = true">
|
||||
<h2 :title="girdName2">{{ girdName2 }}</h2>
|
||||
</div>
|
||||
<div class="pdgrid-body">
|
||||
<div class="pdgrid-body__item" @click="isShowGrid3 = true">
|
||||
<h2>{{ girdNum3 || 0 }}</h2>
|
||||
<div class="bottom">
|
||||
<i></i>
|
||||
<p>{{ girdName3 }}</p>
|
||||
<i class="right"></i>
|
||||
</div>
|
||||
</div>
|
||||
<div class="pdgrid-body__item" @click.stop="isShowGrid4 = true">
|
||||
<h2>{{ girdNum4 || 0 }}</h2>
|
||||
<div class="bottom">
|
||||
<i></i>
|
||||
<p>{{ girdName4 }}</p>
|
||||
<i class="right"></i>
|
||||
</div>
|
||||
</div>
|
||||
<div class="pdgrid-body__item" @click="isShowGrid5 = true">
|
||||
<h2>{{ girdNum5 || 0 }}</h2>
|
||||
<div class="bottom">
|
||||
<i></i>
|
||||
<p>{{ girdName5 }}</p>
|
||||
<i class="right"></i>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<transition name="fade">
|
||||
<div class="grid-dialog" v-show="isShowGrid2">
|
||||
<div class="mask" @click="isShowGrid2 = false"></div>
|
||||
<div class="grid-container">
|
||||
<h2 :title="girdName2">{{ girdName2 }}</h2>
|
||||
<div class="grid-list">
|
||||
<div @click.stop="onGrid2Click(girdId1, girdName2)">{{ girdName2 }}</div>
|
||||
<!-- <div
|
||||
:class="[currIndex2 === index ? 'grid-active' : '']"
|
||||
v-for="(item, index) in girdInfoList2"
|
||||
:key="index"
|
||||
:title="item.girdName"
|
||||
@click.stop="onGrid2Click(item, index)">
|
||||
{{ item.girdName }}
|
||||
</div> -->
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</transition>
|
||||
<transition name="fade">
|
||||
<div class="grid-dialog" v-show="isShowGrid3">
|
||||
<div class="mask" @click="isShowGrid3 = false"></div>
|
||||
<div class="grid-container">
|
||||
<h2 :title="girdName3">{{ girdName3 }}</h2>
|
||||
<div class="grid-list">
|
||||
<div
|
||||
:class="[currIndex3 === index ? 'grid-active' : '']"
|
||||
v-for="(item, index) in girdInfoList3"
|
||||
:key="index"
|
||||
:title="item.girdName"
|
||||
@click.stop="onGrid3Click(item, index)">
|
||||
{{ item.girdName }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</transition>
|
||||
<transition name="fade">
|
||||
<div class="grid-dialog" v-show="isShowGrid4">
|
||||
<div class="mask" @click="isShowGrid4 = false"></div>
|
||||
<div class="grid-container">
|
||||
<h2 :title="girdName4">{{ girdName4 }}</h2>
|
||||
<div class="grid-list">
|
||||
<div
|
||||
:class="[currIndex4 === index ? 'grid-active' : '']"
|
||||
v-for="(item, index) in girdInfoList4"
|
||||
:key="index"
|
||||
:title="item.girdName"
|
||||
@click.stop="onGrid4Click(item, index)">
|
||||
{{ item.girdName }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</transition>
|
||||
<transition name="fade">
|
||||
<div class="grid-dialog" v-show="isShowGrid5">
|
||||
<div class="mask" @click="isShowGrid5 = false"></div>
|
||||
<div class="grid-container">
|
||||
<h2 :title="girdName5">{{ girdName5 }}</h2>
|
||||
<div class="grid-list">
|
||||
<div
|
||||
:class="[currIndex5 === index ? 'grid-active' : '']"
|
||||
v-for="(item, index) in girdInfoList5"
|
||||
:key="index"
|
||||
:title="item.girdName"
|
||||
@click.stop="onGrid5Click(item, index)">
|
||||
{{ item.girdName }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</transition>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'XyGrid',
|
||||
|
||||
props: ['instance'],
|
||||
|
||||
data () {
|
||||
return {
|
||||
isShowGrid2: false,
|
||||
isShowGrid3: false,
|
||||
isShowGrid4: false,
|
||||
isShowGrid5: false,
|
||||
currIndex2: 0,
|
||||
girdId1: '',
|
||||
currIndex3: 0,
|
||||
currIndex4: 0,
|
||||
currIndex5: 0,
|
||||
girdInfoList2: [],
|
||||
girdInfoList3: [],
|
||||
girdInfoList4: [],
|
||||
girdInfoList5: [],
|
||||
girdName2: '',
|
||||
girdName3: '',
|
||||
girdName4: '',
|
||||
girdName5: '',
|
||||
girdNum3: 0,
|
||||
girdNum4: 0,
|
||||
girdNum5: 0,
|
||||
currGird: '',
|
||||
girdName1: ''
|
||||
}
|
||||
},
|
||||
|
||||
mounted () {
|
||||
this.$nextTick(() => {
|
||||
document.addEventListener('keydown', this.onKeyDown)
|
||||
})
|
||||
this.getInfo()
|
||||
},
|
||||
|
||||
destroyed () {
|
||||
document.removeEventListener('keydown', this.onKeyDown)
|
||||
},
|
||||
|
||||
methods: {
|
||||
onKeyDown (e) {
|
||||
if (e.keyCode == 27) {
|
||||
this.isShowGrid2 = false
|
||||
this.isShowGrid3 = false
|
||||
this.isShowGrid4 = false
|
||||
this.isShowGrid5 = false
|
||||
}
|
||||
},
|
||||
|
||||
onGrid2Click (id, name) {
|
||||
// this.currIndex2 = index
|
||||
// this.girdName2 = item.girdName
|
||||
this.currIndex3 = -1
|
||||
this.currIndex4 = -1
|
||||
this.currIndex5 = -1
|
||||
this.isShowGrid2 = false
|
||||
this.girdInfoList3 = []
|
||||
this.girdInfoList4 = []
|
||||
this.girdInfoList5 = []
|
||||
this.$emit('nodeClick', id)
|
||||
|
||||
this.currGird = name
|
||||
this.getInfo(id)
|
||||
},
|
||||
|
||||
onGrid3Click (item, index) {
|
||||
this.currIndex3 = index
|
||||
this.girdName3 = item.girdName
|
||||
this.currIndex4 = -1
|
||||
this.currIndex5 = -1
|
||||
this.girdNum3 = 1
|
||||
this.isShowGrid3 = false
|
||||
this.$emit('nodeClick', {
|
||||
id: item.id,
|
||||
level: 2
|
||||
})
|
||||
this.girdInfoList4 = []
|
||||
this.girdInfoList5 = []
|
||||
this.currGird = item.girdName
|
||||
this.getInfo(item.id)
|
||||
},
|
||||
|
||||
onGrid4Click (item, index) {
|
||||
this.currIndex4 = index
|
||||
this.girdName4 = item.girdName
|
||||
this.currIndex5 = -1
|
||||
this.girdNum4 = 1
|
||||
this.isShowGrid4 = false
|
||||
this.$emit('nodeClick', {
|
||||
id: item.id,
|
||||
level: 3
|
||||
})
|
||||
this.girdInfoList5 = []
|
||||
|
||||
this.currGird = item.girdName
|
||||
this.getInfo(item.id)
|
||||
},
|
||||
|
||||
onGrid5Click (item, index) {
|
||||
this.currIndex5 = index
|
||||
this.girdName5 = item.girdName
|
||||
this.isShowGrid5 = false
|
||||
this.girdNum5 = 1
|
||||
this.$emit('nodeClick', {
|
||||
id: item.id,
|
||||
level: 4
|
||||
})
|
||||
|
||||
this.currGird = item.girdName
|
||||
this.getInfo(item.id)
|
||||
},
|
||||
|
||||
getInfo (id) {
|
||||
this.instance.post(`/app/qxn_appgirdinfo/queryGirdInfo?id=${id || ''}`).then(res => {
|
||||
if (res.code === 0) {
|
||||
res.data.girdInfoList2 && (this.girdInfoList3 = res.data.girdInfoList2)
|
||||
res.data.girdInfoList3 && (this.girdInfoList4 = res.data.girdInfoList3)
|
||||
res.data.girdInfoList4 && (this.girdInfoList5 = res.data.girdInfoList4)
|
||||
|
||||
res.data.girdName1 && (this.girdName2 = res.data.girdName1)
|
||||
res.data.girdName2 && (this.girdName3 = res.data.girdName2)
|
||||
res.data.girdName3 && (this.girdName4 = res.data.girdName3)
|
||||
res.data.girdName4 && (this.girdName5 = res.data.girdName4)
|
||||
|
||||
if (this.girdId1) {
|
||||
this.girdName2 = res.data.girdName1
|
||||
this.girdId1 = res.data.girdId1
|
||||
}
|
||||
|
||||
res.data.girdNum2 != null && (this.girdNum3 = res.data.girdNum2)
|
||||
res.data.girdNum3 != null && (this.girdNum4 = res.data.girdNum3)
|
||||
res.data.girdNum4 != null && (this.girdNum5 = res.data.girdNum4)
|
||||
|
||||
if (!id) {
|
||||
this.currGird = res.data.girdName1
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.pdgrid {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
overflow: hidden;
|
||||
box-sizing: border-box;
|
||||
background: url(https://cdn.cunwuyun.cn/dvcp/dv/pddv/middle-bg.png) no-repeat center;
|
||||
background-size: contain;
|
||||
|
||||
.fade-enter-active, .fade-leave-active {
|
||||
transition: opacity .3s ease-in-out;
|
||||
}
|
||||
.fade-enter, .fade-leave-to {
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
* {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.pdgrid-grid__title {
|
||||
position: absolute;
|
||||
top: 40px;
|
||||
left: 50%;
|
||||
width: 271px;
|
||||
height: 53px;
|
||||
line-height: 53px;
|
||||
text-align: center;
|
||||
background: url(https://cdn.cunwuyun.cn/dvcp/dv/pddv/grid-title-sbg.png) no-repeat center;
|
||||
background-size: 100% 100%;
|
||||
cursor: pointer;
|
||||
transform: translateX(-50%);
|
||||
transition: opacity ease 0.3s;
|
||||
|
||||
&:hover {
|
||||
opacity: 0.8;
|
||||
}
|
||||
|
||||
h2 {
|
||||
width: 182px;
|
||||
margin: 0 auto;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
color: #FFFFFF;
|
||||
font-size: 21px;
|
||||
text-shadow: 0px 0px 13px rgb(59 182 255 / 80%);
|
||||
background: #fff;
|
||||
-webkit-background-clip: text;
|
||||
-webkit-text-fill-color: transparent;
|
||||
}
|
||||
}
|
||||
|
||||
.pdgrid-title {
|
||||
position: absolute;
|
||||
top: 200px;
|
||||
left: 50%;
|
||||
min-width: 640px;
|
||||
height: 80px;
|
||||
line-height: 80px;
|
||||
text-align: center;
|
||||
background: url(https://cdn.cunwuyun.cn/dvcp/dv/pddv/middle-titlebg.png) no-repeat center;
|
||||
background-size: 100% 100%;
|
||||
transform: translateX(-50%);
|
||||
|
||||
h2 {
|
||||
color: #FFFFFF;
|
||||
font-size: 22px;
|
||||
white-space: nowrap;
|
||||
text-shadow: 0px 0px 13px rgb(59 182 255 / 80%);
|
||||
background: #fff;
|
||||
-webkit-background-clip: text;
|
||||
-webkit-text-fill-color: transparent;
|
||||
}
|
||||
}
|
||||
|
||||
.pdgrid-body {
|
||||
display: flex;
|
||||
position: absolute;
|
||||
justify-content: space-between;
|
||||
bottom: 200px;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
padding: 0 112px;
|
||||
|
||||
.pdgrid-body__item {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
width: 200px;
|
||||
height: 187px;
|
||||
align-items: center;
|
||||
padding-top: 71px;
|
||||
cursor: pointer;
|
||||
background: url(https://cdn.cunwuyun.cn/dvcp/dv/pddv/item-bg.png) no-repeat center;
|
||||
background-size: 100% 100%;
|
||||
transition: opacity ease 0.3s;
|
||||
|
||||
&:hover {
|
||||
opacity: 0.8;
|
||||
}
|
||||
|
||||
&:nth-of-type(2) {
|
||||
position: relative;
|
||||
top: 67px;
|
||||
}
|
||||
|
||||
h2 {
|
||||
font-size: 36px;
|
||||
color: #FFFFFF;
|
||||
text-shadow: 0px 0px 13px rgb(59 182 255 / 80%);
|
||||
background: #fff;
|
||||
-webkit-background-clip: text;
|
||||
-webkit-text-fill-color: transparent;
|
||||
}
|
||||
|
||||
p {
|
||||
max-width: 164px;
|
||||
margin-top: 4px;
|
||||
padding: 0 16px;
|
||||
font-size: 16px;
|
||||
color: #FFFFFF;
|
||||
text-shadow: 0px 0px 13px rgb(59 182 255 / 80%);
|
||||
background: #fff;
|
||||
-webkit-background-clip: text;
|
||||
font-weight: 600;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
-webkit-text-fill-color: transparent;
|
||||
}
|
||||
|
||||
.bottom {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
i {
|
||||
width: 0px;
|
||||
height: 0px;
|
||||
border: 6px solid transparent;
|
||||
border-top-color: transparent;
|
||||
border-bottom-color: transparent;
|
||||
border-left-color: transparent;
|
||||
border-right-color: #FFCB42;
|
||||
|
||||
&.right {
|
||||
width: 0px;
|
||||
height: 0px;
|
||||
border: 6px solid transparent;
|
||||
border-top-color: transparent;
|
||||
border-bottom-color: transparent;
|
||||
border-left-color: #FFCB42;
|
||||
border-right-color: transparent;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.grid-dialog {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
z-index: 111;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
|
||||
& > .mask {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
z-index: 1;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: rgba(0, 0, 0, 0.5);
|
||||
}
|
||||
|
||||
.grid-container {
|
||||
display: flex;
|
||||
position: absolute;
|
||||
flex-direction: column;
|
||||
left: 50%;
|
||||
top: 50%;
|
||||
z-index: 2;
|
||||
width: 640px;
|
||||
height: 640px;
|
||||
background: rgba(7,13,41,0.9);
|
||||
border: 1px solid #144662;
|
||||
transform: translate(-50%, -50%);
|
||||
|
||||
& > h2 {
|
||||
width: 100%;
|
||||
height: 67px;
|
||||
line-height: 67px;
|
||||
padding: 0 20px;
|
||||
text-align: center;
|
||||
color: #FFFFFF;
|
||||
font-size: 24px;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
text-shadow: 0px 0px 13px rgb(59 182 255 / 80%);
|
||||
background: url(https://cdn.cunwuyun.cn/dvcp/dv/pddv/grid-title-bg.png) no-repeat center;
|
||||
background-size: 100% 100%;
|
||||
}
|
||||
|
||||
.grid-list {
|
||||
flex: 1;
|
||||
overflow-y: auto;
|
||||
|
||||
& > div {
|
||||
height: 67px;
|
||||
line-height: 67px;
|
||||
padding: 0 20px;
|
||||
text-align: center;
|
||||
color: #FFFFFF;
|
||||
font-size: 27px;
|
||||
cursor: pointer;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
transition: all ease 0.5s;
|
||||
|
||||
&.grid-active {
|
||||
background: linear-gradient(270deg, rgba(0,48,124,0) 0%, #00307C 16%, rgba(0,99,255,0.9100) 50%, rgba(0,48,124,0.8200) 87%, rgba(0,48,124,0) 100%);
|
||||
box-shadow: inset 0px -1px 0px 0px rgba(16,34,54,1);
|
||||
text-shadow: 0px 3px 5px rgba(0,0,0,0.5000);
|
||||
}
|
||||
|
||||
&:hover {
|
||||
background: linear-gradient(270deg, rgba(0,48,124,0) 0%, #00307C 16%, rgba(0,99,255,0.9100) 50%, rgba(0,48,124,0.8200) 87%, rgba(0,48,124,0) 100%);
|
||||
box-shadow: inset 0px -1px 0px 0px rgba(16,34,54,1);
|
||||
text-shadow: 0px 3px 5px rgba(0,0,0,0.5000);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -1,498 +0,0 @@
|
||||
<template>
|
||||
<div class="pdgrid">
|
||||
<div class="pdgrid-title">
|
||||
<h2>{{ currGird }}</h2>
|
||||
</div>
|
||||
<div class="pdgrid-grid__title" @click="isShowGrid2 = true">
|
||||
<h2 :title="girdName2">{{ girdName2 }}</h2>
|
||||
</div>
|
||||
<div class="pdgrid-body">
|
||||
<div class="pdgrid-body__item" @click="isShowGrid3 = true">
|
||||
<h2>{{ girdNum3 || 0 }}</h2>
|
||||
<div class="bottom">
|
||||
<i></i>
|
||||
<p>{{ girdName3 }}</p>
|
||||
<i class="right"></i>
|
||||
</div>
|
||||
</div>
|
||||
<div class="pdgrid-body__item" @click.stop="isShowGrid4 = true">
|
||||
<h2>{{ girdNum4 || 0 }}</h2>
|
||||
<div class="bottom">
|
||||
<i></i>
|
||||
<p>{{ girdName4 }}</p>
|
||||
<i class="right"></i>
|
||||
</div>
|
||||
</div>
|
||||
<div class="pdgrid-body__item" @click="isShowGrid5 = true">
|
||||
<h2>{{ girdNum5 || 0 }}</h2>
|
||||
<div class="bottom">
|
||||
<i></i>
|
||||
<p>{{ girdName5 }}</p>
|
||||
<i class="right"></i>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<transition name="fade">
|
||||
<div class="grid-dialog" v-show="isShowGrid2">
|
||||
<div class="mask" @click="isShowGrid2 = false"></div>
|
||||
<div class="grid-container">
|
||||
<h2 :title="girdName2">{{ girdName2 }}</h2>
|
||||
<div class="grid-list">
|
||||
<div @click.stop="onGrid2Click(girdId1, girdName2)">{{ girdName2 }}</div>
|
||||
<!-- <div
|
||||
:class="[currIndex2 === index ? 'grid-active' : '']"
|
||||
v-for="(item, index) in girdInfoList2"
|
||||
:key="index"
|
||||
:title="item.girdName"
|
||||
@click.stop="onGrid2Click(item, index)">
|
||||
{{ item.girdName }}
|
||||
</div> -->
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</transition>
|
||||
<transition name="fade">
|
||||
<div class="grid-dialog" v-show="isShowGrid3">
|
||||
<div class="mask" @click="isShowGrid3 = false"></div>
|
||||
<div class="grid-container">
|
||||
<h2 :title="girdName3">{{ girdName3 }}</h2>
|
||||
<div class="grid-list">
|
||||
<div
|
||||
:class="[currIndex3 === index ? 'grid-active' : '']"
|
||||
v-for="(item, index) in girdInfoList3"
|
||||
:key="index"
|
||||
:title="item.girdName"
|
||||
@click.stop="onGrid3Click(item, index)">
|
||||
{{ item.girdName }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</transition>
|
||||
<transition name="fade">
|
||||
<div class="grid-dialog" v-show="isShowGrid4">
|
||||
<div class="mask" @click="isShowGrid4 = false"></div>
|
||||
<div class="grid-container">
|
||||
<h2 :title="girdName4">{{ girdName4 }}</h2>
|
||||
<div class="grid-list">
|
||||
<div
|
||||
:class="[currIndex4 === index ? 'grid-active' : '']"
|
||||
v-for="(item, index) in girdInfoList4"
|
||||
:key="index"
|
||||
:title="item.girdName"
|
||||
@click.stop="onGrid4Click(item, index)">
|
||||
{{ item.girdName }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</transition>
|
||||
<transition name="fade">
|
||||
<div class="grid-dialog" v-show="isShowGrid5">
|
||||
<div class="mask" @click="isShowGrid5 = false"></div>
|
||||
<div class="grid-container">
|
||||
<h2 :title="girdName5">{{ girdName5 }}</h2>
|
||||
<div class="grid-list">
|
||||
<div
|
||||
:class="[currIndex5 === index ? 'grid-active' : '']"
|
||||
v-for="(item, index) in girdInfoList5"
|
||||
:key="index"
|
||||
:title="item.girdName"
|
||||
@click.stop="onGrid5Click(item, index)">
|
||||
{{ item.girdName }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</transition>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'XyGrid',
|
||||
|
||||
props: ['instance'],
|
||||
|
||||
data () {
|
||||
return {
|
||||
isShowGrid2: false,
|
||||
isShowGrid3: false,
|
||||
isShowGrid4: false,
|
||||
isShowGrid5: false,
|
||||
currIndex2: 0,
|
||||
girdId1: '',
|
||||
currIndex3: 0,
|
||||
currIndex4: 0,
|
||||
currIndex5: 0,
|
||||
girdInfoList2: [],
|
||||
girdInfoList3: [],
|
||||
girdInfoList4: [],
|
||||
girdInfoList5: [],
|
||||
girdName2: '',
|
||||
girdName3: '',
|
||||
girdName4: '',
|
||||
girdName5: '',
|
||||
girdNum3: 0,
|
||||
girdNum4: 0,
|
||||
girdNum5: 0,
|
||||
currGird: '',
|
||||
girdName1: ''
|
||||
}
|
||||
},
|
||||
|
||||
mounted () {
|
||||
this.$nextTick(() => {
|
||||
document.addEventListener('keydown', this.onKeyDown)
|
||||
})
|
||||
this.getInfo()
|
||||
},
|
||||
|
||||
destroyed () {
|
||||
document.removeEventListener('keydown', this.onKeyDown)
|
||||
},
|
||||
|
||||
methods: {
|
||||
onKeyDown (e) {
|
||||
if (e.keyCode == 27) {
|
||||
this.isShowGrid2 = false
|
||||
this.isShowGrid3 = false
|
||||
this.isShowGrid4 = false
|
||||
this.isShowGrid5 = false
|
||||
}
|
||||
},
|
||||
|
||||
onGrid2Click (id, name) {
|
||||
// this.currIndex2 = index
|
||||
// this.girdName2 = item.girdName
|
||||
this.currIndex3 = -1
|
||||
this.currIndex4 = -1
|
||||
this.currIndex5 = -1
|
||||
this.isShowGrid2 = false
|
||||
this.girdInfoList3 = []
|
||||
this.girdInfoList4 = []
|
||||
this.girdInfoList5 = []
|
||||
this.$emit('nodeClick', id)
|
||||
|
||||
this.currGird = name
|
||||
this.getInfo(id)
|
||||
},
|
||||
|
||||
onGrid3Click (item, index) {
|
||||
this.currIndex3 = index
|
||||
this.girdName3 = item.girdName
|
||||
this.currIndex4 = -1
|
||||
this.currIndex5 = -1
|
||||
this.girdNum3 = 1
|
||||
this.isShowGrid3 = false
|
||||
this.$emit('nodeClick', {
|
||||
id: item.id,
|
||||
level: 2
|
||||
})
|
||||
this.girdInfoList4 = []
|
||||
this.girdInfoList5 = []
|
||||
this.currGird = item.girdName
|
||||
this.getInfo(item.id)
|
||||
},
|
||||
|
||||
onGrid4Click (item, index) {
|
||||
this.currIndex4 = index
|
||||
this.girdName4 = item.girdName
|
||||
this.currIndex5 = -1
|
||||
this.girdNum4 = 1
|
||||
this.isShowGrid4 = false
|
||||
this.$emit('nodeClick', {
|
||||
id: item.id,
|
||||
level: 3
|
||||
})
|
||||
this.girdInfoList5 = []
|
||||
|
||||
this.currGird = item.girdName
|
||||
this.getInfo(item.id)
|
||||
},
|
||||
|
||||
onGrid5Click (item, index) {
|
||||
this.currIndex5 = index
|
||||
this.girdName5 = item.girdName
|
||||
this.isShowGrid5 = false
|
||||
this.girdNum5 = 1
|
||||
this.$emit('nodeClick', {
|
||||
id: item.id,
|
||||
level: 4
|
||||
})
|
||||
|
||||
this.currGird = item.girdName
|
||||
this.getInfo(item.id)
|
||||
},
|
||||
|
||||
getInfo (id) {
|
||||
this.instance.post(`/app/yyx_appgirdinfo/queryGirdInfo?id=${id || ''}`).then(res => {
|
||||
if (res.code === 0) {
|
||||
res.data.girdInfoList2 && (this.girdInfoList3 = res.data.girdInfoList2)
|
||||
res.data.girdInfoList3 && (this.girdInfoList4 = res.data.girdInfoList3)
|
||||
res.data.girdInfoList4 && (this.girdInfoList5 = res.data.girdInfoList4)
|
||||
|
||||
res.data.girdName1 && (this.girdName2 = res.data.girdName1)
|
||||
res.data.girdName2 && (this.girdName3 = res.data.girdName2)
|
||||
res.data.girdName3 && (this.girdName4 = res.data.girdName3)
|
||||
res.data.girdName4 && (this.girdName5 = res.data.girdName4)
|
||||
|
||||
if (this.girdId1) {
|
||||
this.girdName2 = res.data.girdName1
|
||||
this.girdId1 = res.data.girdId1
|
||||
}
|
||||
|
||||
res.data.girdNum2 != null && (this.girdNum3 = res.data.girdNum2)
|
||||
res.data.girdNum3 != null && (this.girdNum4 = res.data.girdNum3)
|
||||
res.data.girdNum4 != null && (this.girdNum5 = res.data.girdNum4)
|
||||
|
||||
if (!id) {
|
||||
this.currGird = res.data.girdName1
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.pdgrid {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
overflow: hidden;
|
||||
box-sizing: border-box;
|
||||
background: url(https://cdn.cunwuyun.cn/dvcp/dv/pddv/middle-bg.png) no-repeat center;
|
||||
background-size: contain;
|
||||
|
||||
.fade-enter-active, .fade-leave-active {
|
||||
transition: opacity .3s ease-in-out;
|
||||
}
|
||||
.fade-enter, .fade-leave-to {
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
* {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.pdgrid-grid__title {
|
||||
position: absolute;
|
||||
top: 40px;
|
||||
left: 50%;
|
||||
width: 271px;
|
||||
height: 53px;
|
||||
line-height: 53px;
|
||||
text-align: center;
|
||||
background: url(https://cdn.cunwuyun.cn/dvcp/dv/pddv/grid-title-sbg.png) no-repeat center;
|
||||
background-size: 100% 100%;
|
||||
cursor: pointer;
|
||||
transform: translateX(-50%);
|
||||
transition: opacity ease 0.3s;
|
||||
|
||||
&:hover {
|
||||
opacity: 0.8;
|
||||
}
|
||||
|
||||
h2 {
|
||||
width: 182px;
|
||||
margin: 0 auto;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
color: #FFFFFF;
|
||||
font-size: 21px;
|
||||
text-shadow: 0px 0px 13px rgb(59 182 255 / 80%);
|
||||
background: #fff;
|
||||
-webkit-background-clip: text;
|
||||
-webkit-text-fill-color: transparent;
|
||||
}
|
||||
}
|
||||
|
||||
.pdgrid-title {
|
||||
position: absolute;
|
||||
top: 200px;
|
||||
left: 50%;
|
||||
min-width: 640px;
|
||||
height: 80px;
|
||||
line-height: 80px;
|
||||
text-align: center;
|
||||
background: url(https://cdn.cunwuyun.cn/dvcp/dv/pddv/middle-titlebg.png) no-repeat center;
|
||||
background-size: 100% 100%;
|
||||
transform: translateX(-50%);
|
||||
|
||||
h2 {
|
||||
color: #FFFFFF;
|
||||
font-size: 22px;
|
||||
white-space: nowrap;
|
||||
text-shadow: 0px 0px 13px rgb(59 182 255 / 80%);
|
||||
background: #fff;
|
||||
-webkit-background-clip: text;
|
||||
-webkit-text-fill-color: transparent;
|
||||
}
|
||||
}
|
||||
|
||||
.pdgrid-body {
|
||||
display: flex;
|
||||
position: absolute;
|
||||
justify-content: space-between;
|
||||
bottom: 200px;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
padding: 0 112px;
|
||||
|
||||
.pdgrid-body__item {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
width: 200px;
|
||||
height: 187px;
|
||||
align-items: center;
|
||||
padding-top: 71px;
|
||||
cursor: pointer;
|
||||
background: url(https://cdn.cunwuyun.cn/dvcp/dv/pddv/item-bg.png) no-repeat center;
|
||||
background-size: 100% 100%;
|
||||
transition: opacity ease 0.3s;
|
||||
|
||||
&:hover {
|
||||
opacity: 0.8;
|
||||
}
|
||||
|
||||
&:nth-of-type(2) {
|
||||
position: relative;
|
||||
top: 67px;
|
||||
}
|
||||
|
||||
h2 {
|
||||
font-size: 36px;
|
||||
color: #FFFFFF;
|
||||
text-shadow: 0px 0px 13px rgb(59 182 255 / 80%);
|
||||
background: #fff;
|
||||
-webkit-background-clip: text;
|
||||
-webkit-text-fill-color: transparent;
|
||||
}
|
||||
|
||||
p {
|
||||
max-width: 164px;
|
||||
margin-top: 4px;
|
||||
padding: 0 16px;
|
||||
font-size: 16px;
|
||||
color: #FFFFFF;
|
||||
text-shadow: 0px 0px 13px rgb(59 182 255 / 80%);
|
||||
background: #fff;
|
||||
-webkit-background-clip: text;
|
||||
font-weight: 600;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
-webkit-text-fill-color: transparent;
|
||||
}
|
||||
|
||||
.bottom {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
i {
|
||||
width: 0px;
|
||||
height: 0px;
|
||||
border: 6px solid transparent;
|
||||
border-top-color: transparent;
|
||||
border-bottom-color: transparent;
|
||||
border-left-color: transparent;
|
||||
border-right-color: #FFCB42;
|
||||
|
||||
&.right {
|
||||
width: 0px;
|
||||
height: 0px;
|
||||
border: 6px solid transparent;
|
||||
border-top-color: transparent;
|
||||
border-bottom-color: transparent;
|
||||
border-left-color: #FFCB42;
|
||||
border-right-color: transparent;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.grid-dialog {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
z-index: 111;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
|
||||
& > .mask {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
z-index: 1;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: rgba(0, 0, 0, 0.5);
|
||||
}
|
||||
|
||||
.grid-container {
|
||||
display: flex;
|
||||
position: absolute;
|
||||
flex-direction: column;
|
||||
left: 50%;
|
||||
top: 50%;
|
||||
z-index: 2;
|
||||
width: 640px;
|
||||
height: 640px;
|
||||
background: rgba(7,13,41,0.9);
|
||||
border: 1px solid #144662;
|
||||
transform: translate(-50%, -50%);
|
||||
|
||||
& > h2 {
|
||||
width: 100%;
|
||||
height: 67px;
|
||||
line-height: 67px;
|
||||
padding: 0 20px;
|
||||
text-align: center;
|
||||
color: #FFFFFF;
|
||||
font-size: 24px;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
text-shadow: 0px 0px 13px rgb(59 182 255 / 80%);
|
||||
background: url(https://cdn.cunwuyun.cn/dvcp/dv/pddv/grid-title-bg.png) no-repeat center;
|
||||
background-size: 100% 100%;
|
||||
}
|
||||
|
||||
.grid-list {
|
||||
flex: 1;
|
||||
overflow-y: auto;
|
||||
|
||||
& > div {
|
||||
height: 67px;
|
||||
line-height: 67px;
|
||||
padding: 0 20px;
|
||||
text-align: center;
|
||||
color: #FFFFFF;
|
||||
font-size: 27px;
|
||||
cursor: pointer;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
transition: all ease 0.5s;
|
||||
|
||||
&.grid-active {
|
||||
background: linear-gradient(270deg, rgba(0,48,124,0) 0%, #00307C 16%, rgba(0,99,255,0.9100) 50%, rgba(0,48,124,0.8200) 87%, rgba(0,48,124,0) 100%);
|
||||
box-shadow: inset 0px -1px 0px 0px rgba(16,34,54,1);
|
||||
text-shadow: 0px 3px 5px rgba(0,0,0,0.5000);
|
||||
}
|
||||
|
||||
&:hover {
|
||||
background: linear-gradient(270deg, rgba(0,48,124,0) 0%, #00307C 16%, rgba(0,99,255,0.9100) 50%, rgba(0,48,124,0.8200) 87%, rgba(0,48,124,0) 100%);
|
||||
box-shadow: inset 0px -1px 0px 0px rgba(16,34,54,1);
|
||||
text-shadow: 0px 3px 5px rgba(0,0,0,0.5000);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||