web端产品库 vite版本

This commit is contained in:
aixianling
2022-04-27 18:18:57 +08:00
parent ee93320cad
commit 4f0178c627
172 changed files with 4520 additions and 16858 deletions

29
.gitignore vendored
View File

@@ -1,27 +1,24 @@
.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

View File

@@ -1,13 +0,0 @@
# 忽略目录
examples/
packages/
subPackages/
core/
public/
project/
.idea/
# 忽略指定文件
vue.config.js
babel.config.js
*.map

View File

@@ -1,3 +0,0 @@
# dvcp_v2_webapp
村微2.0 前端应用库

View File

@@ -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"
]
}

View File

@@ -44,7 +44,7 @@ export default {
return (this.apps || []).filter(e => !this.search || reg.test(e.name) || reg.test(e.label))
},
selectedApp() {
return this.$route.matched.length > 0
return this.$route.name != "产品库"
},
login() {
let url = '/auth/oauth/token';

View File

@@ -1,61 +1,42 @@
import store from "../store";
import appEntry from "../views/appEntry";
import {waiting} from "../utils";
export default {
routes: () => store.state.apps.map(e => {
return {
...e,
component: () => import(`../views/apps/${e.entry}`)
}
}),
routes: [],
init() {
//约束正则式
store.commit("cleanApps")
this.routes = []
// 自动化本工程应用
this.loadApps()
return this.loadApps()
},
loadApps() {
//锁屏loading
waiting.init({innerHTML: '应用加载中..'})
//新App的自动化格式
let files = require.context('../../packages', true, /\.(\/.+)\/App[A-Z][^\/]+\.vue$/)
files.keys().map(path => {
if (files(path).default) {
let {name, label} = files(path).default,
addApp = {
name, label: label || name,
path: path.replace(/\.(\/.+\/App.+)\.vue$/, '/packages$1'),
entry: 'appEntry',
module: files(path).default
}
//命名规范入口文件必须以App开头
store.commit("addApp", addApp)
let files = import.meta.glob('../../packages/**/App*.vue')
let cores = import.meta.glob('../../core/**/App*.vue')
let projects = import.meta.glob('../../project/**/App*.vue')
files = {...files, ...cores, ...projects}
return Promise.all(Object.keys(files).map(path => {
if (/App[A-Z]\w+\.vue/.test(path)) {
return files?.[path]()?.then(file => {
let {name, label} = file.default,
addApp = {
name: [path.replace(/[.\/]+(project)?[\/]([a-z]+).+/, '$2'), name].join("_"), label: label || name,
path: path.replace(/[.\/]+([a-zA-Z].+\/App[A-Z]\w+)\.vue$/, '/$1'),
component: appEntry,
module: file.default
}
//命名规范入口文件必须以App开头
waiting.setContent(`加载${name}...`)
this.routes.push(addApp)
return store.commit("addApp", addApp)
})
} else {
return Promise.resolve()
}
})
let cores = require.context('../../core', true, /\.(\/.+)\/App[^\/]+\.vue$/)
cores.keys().map(path => {
if (cores(path).default) {
let {name, label} = cores(path).default,
addApp = {
name, label: label || name,
path: path.replace(/\.(\/.+\/App.+)\.vue$/, '/core$1'),
entry: 'appEntry',
module: cores(path).default
}
//命名规范入口文件必须以App开头
store.commit("addApp", addApp)
}
})
let project = require.context('../../project', true, /\.(\/.+)\/App[^\/]+\.vue$/)
project.keys().map(path => {
if (project(path).default) {
let {name, label} = project(path).default,
addApp = {
name: [path.replace(/\.\/([^\/]+)\/.*/, '$1'), name].join("_"), label: label || name,
path: path.replace(/\.(\/.+\/App.+)\.vue$/, '/project$1'),
entry: 'appEntry',
module: project(path).default
}
//命名规范入口文件必须以App开头
store.commit("addApp", addApp)
}
})
})).then(() => waiting.close())
}
}

View File

@@ -3,16 +3,20 @@ import VueRouter from 'vue-router'
import autoRoutes from './autoRoutes'
Vue.use(VueRouter)
autoRoutes.init()
export default new VueRouter({
export default autoRoutes.init().then(() => new VueRouter({
mode: 'history',
hashbang: false,
routes: autoRoutes.routes(),
routes: [
{path: "/", name: "产品库"},
...autoRoutes.routes
],
scrollBehavior(to) {
console.log(to)
if (to.hash) {
return {
selector: to.hash
}
}
}
})
}))

View File

@@ -66,14 +66,40 @@ const $decimalCalc = (...arr) => {
* @param { boolean } immediate true 表立即执行false 表非立即执行
*/
export const waiting = {
init(ops, count) {
if (document.body) {
let div = document.createElement('div')
div.id = "ai-waiting"
div.className = "el-loading-mask is-fullscreen"
div.style.zIndex = '202204271710'
div.style.textAlign = 'center'
div.style.lineHeight = '100vh'
document.body.appendChild(div)
} else if (count < 10) {
setTimeout(() => this.init(ops, ++count), 500)
}
},
getDom() {
return document.querySelector('#ai-waiting')
},
setContent(html) {
let div = this.getDom()
div.innerHTML = html
},
close() {
let div = this.getDom()
div.parentElement.removeChild(div)
}
}
export default {
...tools,
addChildParty,
$confirm,
$permissions,
$decimalCalc
$decimalCalc,
$waiting: waiting
}

15
index.html Normal file
View File

@@ -0,0 +1,15 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="favicon.svg" />
<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="main.js"></script>
</body>
</html>

View File

@@ -1,16 +1,14 @@
import Vue from 'vue';
import App from './App.vue';
import App from './examples/App.vue';
import ui from 'element-ui';
import router from './router/router';
import axios from './router/axios';
import utils from './utils';
import createRoute from './examples/router/router';
import axios from './examples/router/axios';
import utils from './examples/utils';
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 store from './examples/store';
Vue.use(dataV);
Vue.use(ui);
Vue.use(vcUI);
//富文本编辑器配置
@@ -18,8 +16,10 @@ Vue.config.productionTip = false;
Vue.prototype.$axios = axios;
Vue.prototype.formatContent = (val) => val.replace(/(\r\n)|(\n)/g, '<br>');
Object.keys(utils).map((e) => (Vue.prototype[e] = utils[e]));
new Vue({
router,
store,
render: (h) => h(App)
}).$mount('#app');
createRoute.then(router => {
new Vue({
router,
store,
render: (h) => h(App)
}).$mount('#app');
})

3452
package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

View File

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

View File

@@ -7,63 +7,67 @@
<template #content>
<ai-search-bar>
<template slot="left">
<el-button type="primary" icon="iconfont iconAdd" @click="handleAdd"
>添加</el-button
>
<el-button type="primary" icon="iconfont iconAdd" @click="handleAdd">添加</el-button>
</template>
<template slot="right">
<el-input
v-model="search.title"
class="search-input"
size="small"
placeholder="请输入课程主题"
clearable
v-throttle="
v-model="search.title"
class="search-input"
size="small"
placeholder="请输入课程主题"
clearable
v-throttle="
() => {
(search.current = 1), getList();
}
"
@clear="(search.current = 1), (search.title = ''), getList()"
suffix-icon="iconfont iconSearch"
@clear="(search.current = 1), (search.title = ''), getList()"
suffix-icon="iconfont iconSearch"
>
</el-input>
</template>
</ai-search-bar>
<ai-table
:tableData="tableData"
:col-configs="colConfigs"
stripe
:total="total"
:current.sync="page.current"
:size.sync="page.size"
style="margin-top: 10px"
@getList="getList"
:tableData="tableData"
:col-configs="colConfigs"
stripe
:total="total"
:current.sync="page.current"
:size.sync="page.size"
style="margin-top: 10px"
@getList="getList"
:dict="dict"
>
<el-table-column
slot="options"
label="操作"
align="center"
width="230px"
fixed="right"
slot="options"
label="操作"
align="center"
width="230px"
fixed="right"
>
<div slot-scope="{ row }" class="table-options">
<el-button
type="text"
:title="row.status == 0 ? '发布' : '取消发布'"
@click="handleChange(row)"
>{{ row.status == 0 ? "发布" : "取消发布" }}</el-button
type="text"
:title="row.status == 0 ? '发布' : '取消发布'"
@click="handleChange(row)"
>{{ row.status == 0 ? "发布" : "取消发布" }}
</el-button
>
<el-button type="text" title="添加" @click="handleAddSeries(row)"
>添加剧集</el-button
>添加剧集
</el-button
>
<el-button type="text" title="详情" @click="handleDetail(row)"
>详情</el-button
>详情
</el-button
>
<el-button type="text" title="编辑" @click="handleEdit(row)"
>编辑</el-button
>编辑
</el-button
>
<el-button type="text" title="删除" @click="handleDelete(row)"
>删除</el-button
>删除
</el-button
>
</div>
</el-table-column>
@@ -71,14 +75,14 @@
</template>
</ai-list>
<component
:is="comp"
v-else
:row="row"
:instance="instance"
:dict="dict"
:permissions="permissions"
@back="back"
:isEdit="isEdit"
:is="comp"
v-else
:row="row"
:instance="instance"
:dict="dict"
:permissions="permissions"
@back="back"
:isEdit="isEdit"
></component>
</section>
</template>
@@ -86,12 +90,12 @@
<script>
import partyClassAdd from "./components/partyClassAdd";
import seriesManage from "./components/seriesManage";
import { mapState } from "vuex";
import {mapState} from "vuex";
export default {
name: "AppPartyHistoryClass",
label: "党员学习",
components: { partyClassAdd, seriesManage },
components: {partyClassAdd, seriesManage},
props: {
instance: Function,
dict: Object,
@@ -121,37 +125,21 @@ export default {
...mapState(["user"]),
colConfigs() {
return [
{ label: "课程主题", prop: "title" },
{
label: "更新状态",
render: (h, { row }) => [
<span>
{" "}
{this.dict.getLabel(
"classroomUpdateStatus",
row.updateStatus
)}{" "}
</span>,
],
},
{ label: "更新时间", prop: "updateDate" },
{ label: "发布时间", prop: "createDate" },
{
label: "发布状态",
render: (h, { row }) => [
<span> {this.dict.getLabel("newsCenterStatus", row.status)} </span>,
],
},
{ label: "发布组织", prop: "organizationName" },
{ slot: "options" },
{label: "课程主题", prop: "title"},
{label: "更新状态", dict: "classroomUpdateStatus", prop: "updateStatus"},
{label: "更新时间", prop: "updateDate"},
{label: "发布时间", prop: "createDate"},
{label: "发布状态", prop: "status", dict: "newsCenterStatus"},
{label: "发布组织", prop: "organizationName"},
{slot: "options"},
];
},
},
methods: {
handleChange(row) {
this.$confirm(`是否确定要${row.status == 0 ? "发布" : "取消发布"}?`).then(
(_) => {
this.instance
(_) => {
this.instance
.post("/app/apppartyclassroom/addOrUpdate", {
id: row.id,
status: row.status == 0 ? 1 : 0,
@@ -159,12 +147,12 @@ export default {
.then((res) => {
if (res.code == 0) {
this.$message.success(
`${row.status == 0 ? "发布成功" : "取消发布成功"}`
`${row.status == 0 ? "发布成功" : "取消发布成功"}`
);
this.getList();
}
});
}
}
);
},
handleAddSeries(row) {
@@ -172,20 +160,20 @@ export default {
this.comp = "seriesManage";
this.row = row;
},
handleDelete({ id }) {
handleDelete({id}) {
this.$confirm("确定要删除吗?").then((_) => {
this.instance
.post("/app/apppartyclassroom/delete", null, {
params: {
ids: id,
},
})
.then((res) => {
if (res.code == 0) {
this.$message.success("删除成功");
this.getList();
}
});
.post("/app/apppartyclassroom/delete", null, {
params: {
ids: id,
},
})
.then((res) => {
if (res.code == 0) {
this.$message.success("删除成功");
this.getList();
}
});
});
},
handleEdit(row) {
@@ -228,18 +216,18 @@ export default {
},
getList() {
this.instance
.post("/app/apppartyclassroom/list", null, {
params: {
...this.page,
...this.search,
},
})
.then((res) => {
if (res?.data) {
this.tableData = res.data.records;
this.total = res.data.total;
}
});
.post("/app/apppartyclassroom/list", null, {
params: {
...this.page,
...this.search,
},
})
.then((res) => {
if (res?.data) {
this.tableData = res.data.records;
this.total = res.data.total;
}
});
},
},
created() {

View File

@@ -70,7 +70,7 @@ export default {
...mapState(["user"]),
colConfigs() {
return [
{label: "类型", render: (h, {row}) => [< span> {row.type == 1 ? '单选题' : '多选题'} < /span>]},
{label: "类型", render: (h, {row}) =>h('p',row.type == 1 ? '单选题' : '多选题')},
{label: "题目", prop: "title"},
{label: "创建时间", prop: "createDate"},
{slot: "options"}

View File

@@ -60,7 +60,7 @@
</section>
</template>
<script>
<script lang="jsx">
import {mapState} from 'vuex'
import DeviceSlider from "../components/deviceSlider"
import LocateDialog from "../components/locateDialog"
@@ -227,7 +227,7 @@
if (node.isLeaf) {
return (
<div class="flexRow">
{index > 0 ?
{index > 0 ?
<span>{ index }</span>
: ''
}

View File

@@ -1,99 +0,0 @@
<template>
<ai-list v-if="!isShowDetail">
<template slot="title">
<ai-title title="大屏列表" :isShowBottomBorder="false" :instance="instance"></ai-title>
</template>
<template slot="tabs">
<el-tabs v-model="currIndex">
<el-tab-pane v-for="(tab,i) in tabs" :key="i" :label="tab.label">
<component :urlPrefix="urlPrefix" :areaId="areaId" :ref="tab.name" v-if="currIndex == i" :is="tab.comp"
@change="onChange" lazy
:instance="instance" :dict="dict" :permissions="permissions"/>
</el-tab-pane>
</el-tabs>
</template>
</ai-list>
<Add v-else-if="componentName === 'Add'" :urlPrefix="urlPrefix" :areaId="areaId" :params="params" :instance="instance"
:dict="dict"
:permissions="permissions" @change="onChange"></Add>
<SourceData v-else-if="componentName === 'SourceData'" :urlPrefix="urlPrefix" :params="params" :instance="instance"
:dict="dict"
:permissions="permissions" @change="onChange"></SourceData>
</template>
<script>
import List from './components/List.vue'
import Add from './components/Add'
import SourceData from './components/SourceData'
import dvui from '../../../project/dvui/entries'
import Vue from "vue";
Vue.use(dvui)
export default {
name: 'AppDesigner',
label: '大屏设计',
components: {
List,
Add,
SourceData
},
props: {
instance: Function,
dict: Object,
permissions: Function,
urlPrefix: {
type: String,
default: '/app'
}
},
computed: {
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
}
}
},
created() {
}
}
</script>
<style lang="scss" scoped>
</style>

View File

@@ -1,297 +0,0 @@
<template>
<ai-detail>
<template slot="title">
<ai-title :title="id ? '编辑项目' : '添加项目'" isShowBack isShowBottomBorder @onBackClick="cancel(false)">
</ai-title>
</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="大屏">
<template #right>
<el-button @click="add('')" 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" 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>
<Layout
v-if="isShowLayout"
:instance="instance"
:dict="dict"
:params="query"
@change="onChange"
:urlPrefix="urlPrefix"
@close="isShowLayout = false">
</Layout>
<ai-dv-wrapper :views="[{label: '返回'}]" @change="screenId = false" v-if="screenId" :title="form.name">
<AppGigscreenViewer :urlPrefix="urlPrefix" :instance="instance" :dict="dict" :id="screenId"></AppGigscreenViewer>
</ai-dv-wrapper>
<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 AppGigscreenViewer from '../../viewer/AppGigscreenViewer'
import Layout from './Layout.vue'
import Sortable from 'sortablejs'
export default {
name: 'Add',
props: {
instance: Function,
dict: Object,
params: Object,
urlPrefix: String
},
inject: {
home:{default: ''}
},
components: {
Layout,
AppGigscreenViewer
},
data() {
return {
info: {},
department: [],
form: {
name: '',
relationLsIds: '',
relationLsNames: '',
status: '1',
description: ''
},
screenId: '',
query: {},
total: 0,
colConfigs: [
{prop: 'title', label: '标题'},
{prop: 'id', label: 'ID'}
],
tableData: [],
isShowLayout: false,
id: '',
dialog: false,
custom: {},
rules: {
dv: [{required: true, message: "请选择 定制大屏"}],
title: [{required: true, message: "请输入 大屏标题"}],
}
}
},
created() {
this.dict.load('customizedDVs')
if (this.params && this.params.id) {
this.id = this.params.id
this.getInfo(this.params.id)
}
},
mounted () {
},
methods: {
getInfo(id) {
this.instance.post(`${this.urlPrefix}/appdiylargescreen/queryLargeScreenProjectDetailById?id=${id}`).then(res => {
if (res.code === 0) {
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
}
})
this.total = res.data.lsList.length
this.$nextTick(() => {
this.rowDrop()
})
}
}
})
},
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.screenId = id
},
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
})
} else {
const index = this.tableData.findIndex(v => v.id === e.id)
this.$set(this.tableData[index], 'title', e.title)
}
},
add() {
this.query = {
id: '',
name: this.form.name
}
this.isShowLayout = true
},
toEdit(id, isCustom, form) {
if (!isCustom) {
this.query = {
id,
name: this.form.name
}
this.isShowLayout = true
} 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(true)
}, 600)
}
})
}
})
},
cancel(isRefresh) {
this.$emit('change', {
type: 'list',
isRefresh: !!isRefresh
})
},
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>

View File

@@ -1,92 +0,0 @@
<template>
<div class="swiper">
<el-carousel height="100%" indicator-position="none">
<el-carousel-item v-for="(item, index) in data" :key="index">
<img :src="item.img">
<div class="swiper-content" v-if="item.title">
<h2>{{ item.title }}</h2>
<p>{{ item.content }}</p>
</div>
</el-carousel-item>
</el-carousel>
</div>
</template>
<script>
export default {
name: 'AiSwiper',
props: {
data: {
type: Array,
default: () => []
},
width: {
type: String,
default: '100%'
},
heigth: {
type: String,
default: '100%'
}
},
data () {
return {
}
},
mounted () {
},
methods: {
}
}
</script>
<style lang="scss" scoped>
.swiper {
width: 100%;
height: 100%;
padding: 20px 0 0;
::v-deep .el-carousel {
height: 100%;
}
img {
width: 100%;
height: 100%;
}
.swiper-content {
position: absolute;
bottom: 0;
left: 0;
z-index: 1;
width: 100%;
padding: 10px;
text-align: center;
background: linear-gradient(180deg, rgba(0, 0, 0, 0.1) 0%, #000000 100%);
h2 {
margin-bottom: 4px;
color: #fff;
text-align: center;
font-size: 18px;
}
p {
line-height: 22px;
white-space: pre-line;
color: #B6DFFF;
font-size: 14px;
text-align: center;
}
}
}
</style>

File diff suppressed because it is too large Load Diff

View File

@@ -1,178 +0,0 @@
<template>
<ai-list class="form-list" isTabs style="width: 100%">
<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">
<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: '状态', formart: v => this.dict.getLabel('cwpStatus', v) },
{ prop: 'createTime', align: 'center', label: '创建时间' }
],
tableData: [],
total: 0,
loading: false
}
},
created () {
this.dict.load('cwpStatus').then(() => {
this.getList()
})
},
mounted () {
this.loading = true
},
methods: {
copy (id) {
this.id = id
this.isShowAdd = true
},
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.$emit('change', {
type: 'add',
params: {
id: id || ''
}
})
},
toAddData () {
this.$emit('change', {
type: 'SourceData'
})
}
}
}
</script>
<style scoped lang="scss">
</style>

View File

@@ -1,188 +0,0 @@
<template>
<div class="render-element" style="width: 100%; height: 100%;">
<ai-dv-display v-if="data.type === 'display'" :title="data.title" :list="data[data.dataType]"></ai-dv-display>
<ai-dv-panel
style="height: 100%; width: 100%;"
v-if="data.type !== 'display'"
:title="data.title"
:border="data.border || ''">
<AiDvSummary v-if="data.type === 'summary'" :summaryTitle="data.summaryTitle" :key="`summary${index}`" :type="data.display" :data="data[data.dataType]"/>
<AiSwiper v-else-if="data.type === 'swiper'" :heigth="'100%'" :data="data[data.dataType]"/>
<dv-scroll-board
v-if="data.type === 'table'"
:config="formatTable(data[data.dataType], data.isShowIndex, data.rowNum)"
:key="data.height"
:style="{height: data.height + 'px', width: '100%'}" />
<ai-echart
v-else-if="data.type === 'barChart1'"
style="height: 100%; width: 100%;"
:ref="'chart' + index"
:key="`chart${index}`"
:data="data[data.dataType]"
:ops="data.config"/>
<ai-echart
v-else-if="data.type === 'barChart2'"
style="height: 100%; width: 100%;"
:ref="'chart' + index"
:key="`chart${index}`"
:data="data[data.dataType]"
:ops="data.config"/>
<ai-echart
v-else-if="data.type === 'barChart3'"
style="height: 100%; width: 100%;"
:ref="'chart' + index"
:key="`chart${index}`"
:data="data[data.dataType]"
:ops="data.config"/>
<ai-echart
v-else-if="data.type === 'barChart5'"
style="height: 100%; width: 100%;"
:ref="'chart' + index"
:key="`chart${index}`"
:data="data[data.dataType]"
:ops="data.config"/>
<ai-echart
v-else-if="data.type === 'barChart7'"
style="height: 100%; width: 100%;"
:ref="'chart' + index"
:key="`chart${index}`"
:data="data[data.dataType]"
:ops="data.config"/>
<ai-echart
v-else-if="data.type === 'barChart8'"
style="height: 100%; width: 100%;"
:ref="'chart' + index"
:key="`chart${index}`"
:data="data[data.dataType]"
:ops="data.config"/>
<ai-echart
v-else-if="data.type === 'barChart9'"
style="height: 100%; width: 100%;"
:ref="'chart' + index"
:key="`chart${index}`"
:data="data[data.dataType]"
:ops="data.config"/>
<ai-echart
v-else-if="data.type === 'lineChart1'"
style="height: 100%; width: 100%;"
:ref="'chart' + index"
:key="`chart${index}`"
:data="data[data.dataType]"
:ops="lineChart1"/>
<ai-echart
v-else-if="data.type === 'lineChart2'"
style="height: 100%; width: 100%;"
:ref="'chart' + index"
:key="`chart${index}`"
:data="data[data.dataType]"
:ops="lineChart2"/>
<ai-echart
v-else-if="data.type === 'lineChart3'"
style="height: 100%; width: 100%;"
:ref="'chart' + index"
:key="`chart${index}`"
:data="data[data.dataType]"
:ops="data.config"/>
<ai-echart
v-else-if="data.type === 'lineChart4'"
style="height: 100%; width: 100%;"
:ref="'chart' + index"
:key="`chart${index}`"
:data="data[data.dataType]"
:ops="data.config"/>
<ai-echart
v-else-if="data.type === 'lineChart5'"
style="height: 100%; width: 100%;"
:ref="'chart' + index"
:key="`chart${index}`"
:data="data[data.dataType]"
:ops="lineChart5"/>
<ai-echart
v-else-if="data.type === 'pieChart'"
style="height: 100%; width: 100%;"
:ref="'chart' + index"
:key="`chart${index}`"
:data="data[data.dataType]"
:ops="pieChart"/>
<ai-map :markers="data[data.dataType]" v-else-if="data.type=='map'" :mask="data.mask === '1'" :areaId="data.areaId || user.info.areaId" map-style="amap://styles/e51987628aee5206d4c9ca8c6e98b4f7"/>
<ai-monitor :src="data.src" v-else-if="data.type === 'monitor'" :type="data.monitorType"></ai-monitor>
<video style="width: 100%; height: 100%; object-fit: fill;" loop :src="data.src" autoplay v-else-if="data.type === 'video'"></video>
</ai-dv-panel>
</div>
</template>
<script>
import { mapState } from 'vuex'
import AiSwiper from './AiSwiper.vue'
import pieChart from 'dvcp-dv-ui/components/AiEchart/template/pie/pieChart2'
import lineChart1 from 'dvcp-dv-ui/components/AiEchart/template/line/lineChart1'
import lineChart2 from 'dvcp-dv-ui/components/AiEchart/template/line/lineChart2'
import lineChart5 from 'dvcp-dv-ui/components/AiEchart/template/line/lineChart5'
export default {
name: 'RenderElement',
props: ['data', 'index'],
components: {
AiSwiper
},
data () {
return {
lineChart1,
lineChart2,
lineChart5,
pieChart
}
},
computed: {
...mapState(['user'])
},
methods: {
formatTable(data, isShowIndex, rowNum) {
if (!data.length) {
return {
header: [],
data: []
}
}
let rows = []
const header = data.map(v => {
return v[Object.keys(v)[0]]
})
Object.keys(data[0]).forEach((item, index) => {
if (index !== 0) {
rows.push(item)
}
})
return {
header: header,
data: rows.map(item => {
return data.map(v => {
return v[item]
})
}),
headerBGC: 'transparent',
evenRowBGC: 'transparent',
oddRowBGC: 'rgba(0, 133, 255, 0.2)',
headerHeight: 42,
rowNum: rowNum || 7,
index: isShowIndex === '1',
carousel: 'page',
indexHeader: '排名',
align: ['center', 'center', 'center', 'center', 'center']
}
},
}
}
</script>
<style lang="scss" scoped>
</style>

View File

@@ -1,456 +0,0 @@
<template>
<ai-detail>
<template slot="title">
<ai-title title="数据源" isShowBack isShowBottomBorder @onBackClick="cancel(false)">
</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
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: '类型', formart: v => v === '0' ? '村微应用' : 'sql语句' },
{ prop: 'createUserName', align: 'center', label: '创建人' },
{ prop: 'createTime', align: 'center', label: '创建时间' }
],
tableData: [],
filedList: [],
appList: [],
form: {
orderType: 'asc',
dataRange: '0',
type: '0',
sqlContent: '',
appId: '',
description: '',
appName: '',
appTableName: '',
count: '100',
statisticsConfigs: [{
alias: '',
calcType: '',
dictCode: '',
fieldCnName: '',
fieldName: ''
}],
orderConfigs: [{
alias: '',
calcType: '',
dictCode: '',
fieldCnName: '',
fieldName: ''
}],
groupConfigs: [{
alias: '',
calcType: '',
dictCode: '',
fieldCnName: '',
fieldName: ''
}]
},
id: '',
orderTypeDict: [
{
value: 'asc',
label: '升序'
},
{
value: 'desc',
label: '降序'
}
]
}
},
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 (isRefresh) {
this.$emit('change', {
type: 'list',
isRefresh: !!isRefresh
})
}
}
}
</script>
<style scoped lang="scss">
.form-flex {
display: flex;
justify-content: space-between;
align-items: center;
}
</style>

View File

@@ -1,459 +0,0 @@
<template>
<div class="layout-config__group--wrapper">
<ai-dialog
append-to-body
:visible.sync="isShowEditor"
width="1000px"
class="layout-config__edit"
title="编辑器"
@onConfirm="onConfirm">
<div>
<code-editor v-model="json" :lint="true" auto-format height="440px"></code-editor>
</div>
</ai-dialog>
<div class="layout-config__group" v-if="options.monitorType !== 'hik' && options.monitorType !== 'dahua'">
<h2>基础设置</h2>
<div class="layout-config__item">
<label>数据类型</label>
<div class="layout-config__item--right">
<el-select size="mini" v-model="options.dataType" placeholder="请选择数据类型">
<el-option
v-for="item in dataTypes"
:key="item.value"
:label="item.label"
:value="item.value">
</el-option>
</el-select>
</div>
</div>
<div class="layout-config__code" v-if="options.dataType === 'staticData'">
<el-button @click="showEditor" class="layout-config__code--btn" title="编辑" type="text" icon="iconfont iconjdq_led_edit"></el-button>
<vue-json-editor
:value="options.staticData"
:show-btns="false"
mode="view"
lang="zh">
</vue-json-editor>
</div>
<template v-else-if="options.dataType === 'dynamicData'">
<div class="layout-config__item">
<label>数据源</label>
<div class="layout-config__item--right">
<el-select size="mini" v-model="options.sourceDataId" placeholder="请选择数据源" @change="onDataChange">
<el-option
v-for="item in sourceData"
:key="item.id"
:label="item.description"
:value="item.id">
</el-option>
</el-select>
</div>
</div>
</template>
<template v-else>
<div class="layout-config__item">
<label>接口地址</label>
<div class="layout-config__item--right">
<el-input size="mini" v-model="options.api" @blur="onApiChange"></el-input>
</div>
</div>
</template>
</div>
<div class="layout-config__group" v-if="options.monitorType === 'hik' || options.monitorType === 'dahua'">
<h2>基础设置</h2>
<div class="layout-config__item">
<label>视频地址</label>
<div class="layout-config__item--right">
<el-input size="mini" v-model="options.src"></el-input>
</div>
</div>
</div>
<div class="layout-config__group" v-if="options.dataType !== 'staticData' && options.type === 'monitor' && (options.monitorType === 'cmcc' || options.monitorType === 'slw')">
<h2>字段设置</h2>
<div class="layout-config__item">
<label>监控视频</label>
<div class="layout-config__item--right">
<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>
</div>
</div>
</div>
<div class="layout-config__group" v-if="options.dataType !== 'staticData' && options.type !== 'monitor' && keys.length && options.type !== 'table'">
<h2>字段设置</h2>
<div class="layout-config__item">
<label>X轴设置</label>
<div class="layout-config__item--right">
<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>
</div>
</div>
<div class="layout-config__item">
<label>Y轴设置</label>
<div class="layout-config__item--right">
<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>
</div>
</div>
</div>
</div>
</template>
<script>
import vueJsonEditor from 'vue-json-editor'
import { CodeEditor } from 'bin-code-editor'
import 'bin-code-editor/lib/styles/index.css'
export default {
name: 'dataCofing',
props: {
options: Object,
instance: Function,
dict: Object,
params: Object,
urlPrefix: String
},
data () {
return {
dataTypes: [
{
value: 'staticData',
label: '静态数据'
},
{
value: 'dynamicData',
label: '动态数据'
},
{
value: 'apiData',
label: '接口'
}
],
isShowEditor: false,
json: {},
sourceDataId: '',
sourceData: [],
keys: [],
monitorList: [],
list: [],
jsonData: `{"title":"测试json数据","children":[{"name":"子项名称", "desc":"子项说明" },{"name":"子项名称1", "desc":"子项说明1" }]}`
}
},
components: {
vueJsonEditor,
CodeEditor
},
mounted () {
this.getDataList()
if ((this.options.dataY && this.options.dataY.length && this.options.dataX) || this.options.type === 'monitor') {
const api = this.options.dataType === 'apiData' ? this.options.api : `${this.urlPrefix}/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: {
showEditor () {
this.json = JSON.stringify(this.options.staticData)
this.isShowEditor = true
},
onMoniterId (e) {
this.instance.post(`${this.urlPrefix}/appzyvideoequipment/getWebSdkUrl?deviceId=${e}`).then(res => {
if (res.code == 0) {
this.options.src = JSON.parse(res.data).url
}
})
},
getDataList () {
this.instance.post(`${this.urlPrefix}/appdiylargescreen/allDatasourceByPage`, null, {
params: {
current: 1,
size: 10000
}
}).then(res => {
if (res.code == 0) {
this.sourceData = res.data.records
}
})
},
onApiChange () {
this.options.dataX = ''
this.options.dataY = []
this.instance.post(this.options.api).then(res => {
if (res.code == 0) {
if (res.data.length) {
if (this.options.type === 'table') {
const keys = Object.keys(res.data[0])
const list = res.data
this.options.apiData = keys.map(v => {
let obj = {}
list.forEach((item, index) => {
obj[`v${index}`] = item[v]
})
return {
row: v,
...obj
}
})
} else if (this.options.type === 'summary') {
if (this.options.display === 'summary9') {
this.options.apiData = res.data
} else {
this.options.apiData = Object.keys(res.data[0]).map(item => {
return {
key: item,
value: res.data[0][item]
}
})
}
} else if (this.options.type === 'monitor') {
this.monitorList = res.data
} else {
this.list = res.data
this.keys = Object.keys(res.data[0])
}
}
}
})
},
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
}
},
onDataChange (e) {
this.options.dataX = ''
this.options.dataY = []
this.instance.post(`${this.urlPrefix}/appdiylargescreen/statisticsByLsid?id=${e}`).then(res => {
if (res.code == 0) {
if (res.data.length) {
if (this.options.type === 'table') {
const keys = Object.keys(res.data[0])
const list = res.data
this.options.dynamicData = keys.map(v => {
let obj = {}
list.forEach((item, index) => {
obj[`v${index}`] = item[v]
})
return {
row: v,
...obj
}
})
} else if (this.options.type === 'summary') {
this.options.dynamicData = Object.keys(res.data[0]).map(item => {
return {
key: item,
value: res.data[0][item]
}
})
} else {
this.list = res.data
this.keys = Object.keys(res.data[0])
}
}
}
})
},
onConfirm () {
this.$set(this.options, 'staticData', JSON.parse(this.json))
this.isShowEditor = false
this.$emit('change')
}
}
}
</script>
<style lang="scss">
.el-dialog__body {
.jsoneditor-vue {
height: 480px;
.jsoneditor-poweredBy {
display: none;
}
}
}
.layout-config__group--wrapper {
.layout-config__code .jsoneditor-vue {
.jsoneditor-menu {
display: none;
}
.jsoneditor {
border: 1px solid #030411;
background: #0e1013;
}
.jsoneditor-field {
color: gray;
}
.jsoneditor-tree button:focus {
background-color: transparent;
outline: none;
}
}
.layout-config__group {
padding: 10px 10px 20px;
border-bottom: 1px solid #000000;
&:last-child {
border: none;
}
.layout-config__code {
position: relative;
padding-left: 10px;
.layout-config__code--btn {
position: absolute;
right: 0;
top: 0;
color: gray;
z-index: 1;
&:hover {
opacity: 0.8 ;
}
}
}
& > h2 {
margin-bottom: 20px;
color: #FFFFFF;
font-size: 15px;
font-weight: 700;
}
}
.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;
}
.layout-config__item--right {
display: flex;
align-items: center;
justify-content: flex-end;
width: 200px;
text-align: right;
}
.el-select .el-tag {
color: #fff;
background: transparent;
}
input {
background: #262C33;
font-size: 12px;
color: #fff;
border: 1px solid #030411;
}
.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;
}
}
}
}
</style>

View File

@@ -1,638 +0,0 @@
import lineChart1 from 'dvcp-dv-ui/components/AiEchart/template/line/lineChart1'
import lineChart2 from 'dvcp-dv-ui/components/AiEchart/template/line/lineChart2'
import lineChart3 from 'dvcp-dv-ui/components/AiEchart/template/line/lineChart3'
import lineChart4 from 'dvcp-dv-ui/components/AiEchart/template/line/lineChart4'
import lineChart5 from 'dvcp-dv-ui/components/AiEchart/template/line/lineChart5'
import barChart1 from 'dvcp-dv-ui/components/AiEchart/template/bar/barChart1'
import barChart2 from 'dvcp-dv-ui/components/AiEchart/template/bar/barChart2'
import barChart3 from 'dvcp-dv-ui/components/AiEchart/template/bar/barChart3'
import barChart8 from 'dvcp-dv-ui/components/AiEchart/template/bar/barChart8'
import barChart5 from 'dvcp-dv-ui/components/AiEchart/template/bar/barChart5'
import barChart7 from 'dvcp-dv-ui/components/AiEchart/template/bar/barChart7'
import barChart9 from 'dvcp-dv-ui/components/AiEchart/template/bar/barChart9'
import pieChart from 'dvcp-dv-ui/components/AiEchart/template/pie/pieChart2'
const components = [
{
type: 'chart',
label: '图表',
list: [
{
label: '柱状图',
type: 'bar',
list: [
{
code: 'widget-linechart',
type: 'barChart1',
label: '柱状图1',
title: '柱状图',
border: 'border1',
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: 'barChart1',
label: '柱状图2',
icon: 'icontext_box',
value: '',
title: '柱状图2',
width: 500,
border: 'border1',
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: 'border1',
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: 'border1',
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: 'border1',
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: 'border1',
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: []
}
]
},
{
label: '折线图',
type: 'line',
list: [
{
code: 'widget-linechart',
type: 'lineChart1',
label: '折线图1',
title: '折线图1',
border: 'border1',
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: 'border1',
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: 'border1',
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: 'border1',
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: 'border1',
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: 'pieChart',
label: '饼图',
title: '饼图',
icon: 'icontext_box',
value: '',
border: 'border1',
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: pieChart,
sourceDataId: '',
dynamicData: []
}
]
}
]
},
{
type: 'table',
label: '表格',
list: [
{
label: '表格',
type: 'table',
list: [
{
type: 'table',
label: '表格',
title: '表格',
border: 'border1',
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: 'other',
label: '其他',
list: [
{
label: '地图',
type: 'map',
list: [
{
type: 'map',
label: '地图',
display: 'map',
width: 840,
height: 534,
left: 0,
top: 0,
mask: '2',
areaId: '',
zIndex: 1,
apiData: [],
dataType: 'staticData',
dynamicData: [],
staticData: [
{
content: '中卫慧通',
lng: 117.1339399,
lat: 36.7190487
}
],
api: '',
thumb: 'https://cdn.cunwuyun.cn/dvcp/dv/tpl/map.png'
}
]
},
{
label: '边框',
type: 'panel',
list: [
{
type: 'panel',
label: '边框',
title: '边框',
border: 'border0',
width: 400,
height: 400,
isZoom: false,
zIndex: 1,
thumb: 'https://cdn.cunwuyun.cn/dvcp/dv/tpl/border.png'
}
]
},
{
label: '装饰',
type: 'display',
list: [
{
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: [
{
key: '个人服务办理',
value: 247
},
{
key: '同比上月',
value: 247
}
]
}
]
},
{
label: '轮播图',
type: 'swiper',
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'
}
]
},
{
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: '数据统计',
type: 'summary',
list: [
{
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'
}
]
},
{
label: '视频监控',
type: 'monitor',
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'
}
]
}
]
}
]
export { components }

View File

@@ -1,88 +0,0 @@
<template>
<section class="AiDataPanel">
<b class="item-title" v-text="label"/>
<div class="num-bg">
<span ref="num" class="num" v-text="num"/>
</div>
</section>
</template>
<script>
import {gsap} from 'gsap'
export default {
name: "AiDataPanel",
props: {
label: {default: "标题"},
value: {default: 0}
},
data() {
return {
num: 0
}
},
methods: {
animation() {
let demo = {num: Math.max(this.value - 30, 0)}
gsap.to(demo, 1, {
num: this.value, onUpdate: () => {
this.num = demo.num?.toFixed(0)
}
})
}
},
mounted() {
this.animation()
}
}
</script>
<style lang="scss" scoped>
.AiDataPanel {
flex: 1;
width: 172px;
height: 160px;
display: flex;
flex-direction: column;
align-items: center;
background: #000;
& + .AiDataPanel {
margin-left: 16px;
}
.item-title {
font-size: 24px;
line-height: 32px;
background-image: -webkit-linear-gradient(bottom, #35BEFF, #EBF9FF, #FFFFFF);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
margin-top: 30px;
}
.num-bg {
width: 100%;
height: 160px;
background-image: url(https://cdn.cunwuyun.cn/dvcp/dv/dianjiang/number-bg.png);
background-size: 100% 100%;
position: relative;
margin-top: -76px;
.num {
position: absolute;
left: 0;
bottom: 30px;
width: 100%;
text-align: center;
height: 50px;
font-size: 40px;
font-family: D-DIN-Bold, D-DIN;
font-weight: bold;
line-height: 54px;
background-image: -webkit-linear-gradient(bottom, #35BEFF, #EBF9FF, #FFFFFF);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
}
}
}
</style>

View File

@@ -1,30 +0,0 @@
<template>
<section class="AiStaData">
<ai-data-panel v-for="op in data" :key="op[key]"
:label="op[label]" :value="op[key]"/>
</section>
</template>
<script>
import AiDataPanel from "./AiDataPanel";
export default {
name: "AiStaData",
components: {AiDataPanel},
props: {
data: {default: () => []},
key: {default: "id"},
label: {default: "label"},
}
}
</script>
<style lang="scss" scoped>
.AiStaData {
width: 100%;
display: flex;
align-items: center;
flex-wrap: wrap;
justify-content: center;
}
</style>

View File

@@ -1,223 +0,0 @@
<template>
<div class="AppGigscreenViewer">
<div v-if="!component">
<div
class="component-item"
:style="{
width: item.width + 'px',
height: item.height + 'px',
left: item.left * scale + 'px',
top: item.top * scale + 'px',
position: 'absolute',
zIndex: item.zIndex,
transform: `scale(${scale})`
}"
v-for="(item, index) in componentList"
:key="index">
<RenderElement :data="item" :index="index"></RenderElement>
</div>
</div>
<components v-else :is="component" :dict="dict" :instance="instance" :nav="meta"/>
</div>
</template>
<script>
import RenderElement from '../designer/components/RenderElement'
export default {
name: 'AppGigscreenViewer',
label: '大屏预览',
props: {
instance: Function,
dict: Object,
id: String,
urlPrefix: {
type: String,
default: '/app'
}
},
watch: {
id(v) {
this.getInfo(v)
}
},
components: {
RenderElement
},
data() {
return {
component: '',
dashboard: {
title: '大屏',
width: 1920,
height: 1080,
backgroundColor: '',
backgroundImage: []
},
componentList: [],
scale: 1,
meta: {}
}
},
created() {
this.getInfo(this.id)
// this.scale = document.body.clientWidth / 1920
},
mounted() {
this.$nextTick(() => {
let content = document.querySelector('#dv-full-screen-container')
if (content) {
const transform = content.style.transform
const scale = transform.replace('scale', '').replace('(', '').replace(')', '')
if (scale == 1) {
this.scale = document.body.clientWidth / 1920
}
}
})
},
methods: {
getInfo(id) {
this.component = null
this.instance.post(`${this.urlPrefix}/appdiylargescreen/queryLargeScreenDetailById?id=${id}`).then(res => {
if (res?.data) {
const config = JSON.parse(res.data.config)
if (config.custom) {
this.component = config.custom
this.meta = config?.meta || {}
} else {
this.componentList = JSON.parse(res.data.config).config
this.dashboard = JSON.parse(res.data.config).dashboard
this.componentList.forEach((item, index) => {
if (item.dataType !== 'staticData' && ((item.type.indexOf('Chart') > -1) || item.type === 'display' || item.type === 'table' || item.type === 'summary')) {
this.getSourceData(item, index)
}
if (item.type === 'monitor' && item.monitorType === 'cmcc') {
this.instance.post(`${this.urlPrefix}/appzyvideoequipment/getWebSdkUrl?deviceId=${item.moniterId}`).then(res => {
if (res.code == 0) {
this.$set(this.componentList[index], 'src', JSON.parse(res.data).url)
}
})
}
if (item.type === 'monitor' && item.monitorType === 'slw') {
this.instance.post(`${this.urlPrefix}/appzyvideoequipment/getWebSdkUrl?deviceId=${item.moniterId}`).then(res => {
if (res.code == 0) {
this.$set(this.componentList[index], 'src', res.data)
}
})
}
})
}
}
})
},
getSourceData(item, index) {
const api = item.dataType === 'apiData' ? item.api : `${this.urlPrefix}/appdiylargescreen/statisticsByLsid?id=${item.sourceDataId}`
this.instance.post(api).then(res => {
if (res.code == 0) {
if (res.data.length) {
const keys = Object.keys(res.data[0])
const list = res.data
let dynamicData = []
if (item.type === 'table') {
dynamicData = keys.map(v => {
let obj = {}
list.forEach((item, index) => {
obj[`v${index}`] = item[v]
})
return {
row: v,
...obj
}
})
} else if (item.type === 'summary') {
if (item.display === 'summary9') {
dynamicData = res.data
} else {
dynamicData = Object.keys(res.data[0]).map(item => {
return {
key: item,
value: res.data[0][item]
}
})
}
} else if (item.dataType === 'dynamicData' && !item.dataX && !item.dataY.length) {
dynamicData = Object.keys(res.data[0]).map(item => {
return {
label: item,
value: res.data[0][item]
}
})
} else {
if (item.dataX && item.dataY.length) {
list.forEach(i => {
let obj = {}
item.dataY.forEach(v => {
obj[v] = i[v]
})
dynamicData.push({
[item.dataX]: i[item.dataX],
...obj
})
})
}
}
this.$set(this.componentList[index], item.dataType, dynamicData)
}
}
})
},
close() {
this.$emit('close')
}
}
}
</script>
<style lang="scss">
.AppGigscreenViewer {
position: relative;
height: 100%;
background: transparent !important;
.component-item {
transform-origin: 0 0;
}
.dv-scroll-board {
height: calc(100%) !important;
.header-item {
color: #7e8697;
font-size: 16px;
}
.index {
display: inline-block;
width: 26px;
height: 26px;
line-height: 26px;
font-size: 16px;
background-color: #4F57FF !important;
}
}
.vdr {
border: none;
}
}
</style>

View File

@@ -104,17 +104,12 @@ export default {
return [
{prop: "residentName", label: "姓名"},
{prop: "description", label: "调整说明"},
{
prop: "changeIntegral", label: "类型", align: "center",
render: (h, {row}) => [< span> {+row.changeIntegral > 0 ? "加分" : '减分'
} < /span>]
},
{prop: "changeIntegral", label: "类型", align: "center", render: (h, {row}) => h('p', +row.changeIntegral > 0 ? "加分" : '减分')},
{
prop: "changeIntegral",
label: "积分",
align: "center",
render: (h, {row}) => [
<span>{row.changeIntegral > 0 ? `+${row.changeIntegral}` : `${row.changeIntegral}`}</span>]
render: (h, {row}) =>h('p',row.changeIntegral > 0 ? `+${row.changeIntegral}` : `${row.changeIntegral}`)
},
{prop: "doTime", label: "操作时间"},
{prop: "declareObjName", label: "操作人", align: "center"},

View File

@@ -26,168 +26,169 @@
</el-form>
</ai-dialog>
<locate-dialog v-model="locate" :ins="instance" :latlng="latlng" @confirm="v=>handleLocate(selected,v)"/>
<ai-area custom-clicker :input-clicker="false" v-model="selected.areaId" :hideLevel="disabledLevel" :instance="instance" ref="BindArea"
<ai-area custom-clicker :input-clicker="false" v-model="selected.areaId" :hideLevel="disabledLevel"
:instance="instance" ref="BindArea"
@change="handleSubmit(selected)"/>
</section>
</template>
<script>
import { mapState } from 'vuex'
import DeviceSlider from "../components/deviceSlider";
import LocateDialog from "../components/locateDialog";
<script lang="jsx">
import {mapState} from 'vuex'
import DeviceSlider from "../components/deviceSlider";
import LocateDialog from "../components/locateDialog";
export default {
name: "AppMonitorManage",
components: {LocateDialog, DeviceSlider},
label: "监控实况",
props: {
instance: Function,
dict: Object,
permissions: Function
export default {
name: "AppMonitorManage",
components: {LocateDialog, DeviceSlider},
label: "监控实况",
props: {
instance: Function,
dict: Object,
permissions: Function
},
computed: {
splitOps() {
return [
{label: "单分屏", value: 1, per: "100%"},
{label: "四分屏", value: 4, per: "49%"},
{label: "九分屏", value: 9, per: "32%"}
]
},
computed: {
splitOps() {
return [
{label: "单分屏", value: 1, per: "100%"},
{label: "四分屏", value: 4, per: "49%"},
{label: "九分屏", value: 9, per: "32%"}
]
},
currentSplitStyle() {
let per = this.splitOps.find(e => e.value == this.splitScreen)?.per || "100%"
return {width: per, height: per}
},
...mapState(['user'])
currentSplitStyle() {
let per = this.splitOps.find(e => e.value == this.splitScreen)?.per || "100%"
return {width: per, height: per}
},
...mapState(['user'])
},
data() {
return {
slider: true,
fullscreen: false,
splitScreen: 1,
monitors: [],
dialog: false,
locate: false,
selected: {
areaId: ''
},
latlng: null,
disabledLevel: 0,
rules: {
name: [{required: true, message: "请填写 设备名称"}]
}
data() {
return {
slider: true,
fullscreen: false,
splitScreen: 1,
monitors: [],
dialog: false,
locate: false,
selected: {
areaId: ''
},
latlng: null,
disabledLevel: 0,
rules: {
name: [{required: true, message: "请填写 设备名称"}]
}
},
}
},
created () {
this.selected.areaId = this.user.info.areaId
this.disabledLevel = this.user.info.areaList.length
},
created() {
this.selected.areaId = this.user.info.areaId
this.disabledLevel = this.user.info.areaList.length
},
methods: {
handleFullscreen() {
this.fullscreen = !this.fullscreen
this.$fullscreen(this.fullscreen)
},
handleSelectMonitor(monitor) {
let {id} = monitor,
index = this.monitors.findIndex(e => e.id == id)
if (index > -1) {
this.monitors.splice(index, 1)
this.monitors.map((e, i) => {
if (i > index) {
this.showMonitor(e, true)
}
})
} else if (this.monitors.length >= this.splitScreen && this.splitScreen > 1) {
this.$message.warning("可分屏监控已满,请先取消其他的监控")
} else {
this.showMonitor(monitor)
}
},
showMonitor(monitor, refresh = false) {
let {id: deviceId} = monitor
deviceId && this.instance.post("/app/appzyvideoequipment/getWebSdkUrl", null, {
params: {deviceId}
}).then(res => {
if (res?.data) {
let data = JSON.parse(res.data)
if (refresh) {
monitor.url = data.url
} else if (this.splitScreen == 1) {
this.monitors = [{...monitor, ...data}]
} else {
this.monitors.push({...monitor, ...data})
}
methods: {
handleFullscreen() {
this.fullscreen = !this.fullscreen
this.$fullscreen(this.fullscreen)
},
handleSelectMonitor(monitor) {
let {id} = monitor,
index = this.monitors.findIndex(e => e.id == id)
if (index > -1) {
this.monitors.splice(index, 1)
this.monitors.map((e, i) => {
if (i > index) {
this.showMonitor(e, true)
}
})
},
renderTreeItem: function (h, {node, data}) {
let show = data.deviceStatus==1 ? 'show' : ''
if (node.isLeaf) {
return (
<div class="flexRow">
<i class={['iconfont', 'iconshipinjiankong', show]}/>
<div>{node.label}</div>
<el-dropdown class="menuBtn" onCommand={e => this.handleSliderOption(e, data)}>
<i class="iconfont iconMore"/>
<el-dropdown-menu slot="dropdown">
<el-dropdown-item command="edit">修改名称</el-dropdown-item>
<el-dropdown-item command="area">行政地区</el-dropdown-item>
<el-dropdown-item command="locate">地图标绘</el-dropdown-item>
</el-dropdown-menu>
</el-dropdown>
</div>
)
} else return (
} else if (this.monitors.length >= this.splitScreen && this.splitScreen > 1) {
this.$message.warning("可分屏监控已满,请先取消其他的监控")
} else {
this.showMonitor(monitor)
}
},
showMonitor(monitor, refresh = false) {
let {id: deviceId} = monitor
deviceId && this.instance.post("/app/appzyvideoequipment/getWebSdkUrl", null, {
params: {deviceId}
}).then(res => {
if (res?.data) {
let data = JSON.parse(res.data)
if (refresh) {
monitor.url = data.url
} else if (this.splitScreen == 1) {
this.monitors = [{...monitor, ...data}]
} else {
this.monitors.push({...monitor, ...data})
}
}
})
},
renderTreeItem: function (h, {node, data}) {
let show = data.deviceStatus == 1 ? 'show' : ''
if (node.isLeaf) {
return (
<div class="flexRow">
<i class={['iconfont', 'iconshipinjiankong', show]}/>
<div>{node.label}</div>
{data.id != 'no_area' ? <div class="sta">
<p>{data.online || 0}</p>/{data.sum || 0}
</div>
: <div/>}
<el-dropdown class="menuBtn" onCommand={e => this.handleSliderOption(e, data)}>
<i class="iconfont iconMore"/>
<el-dropdown-menu slot="dropdown">
<el-dropdown-item command="edit">修改名称</el-dropdown-item>
<el-dropdown-item command="area">行政地区</el-dropdown-item>
<el-dropdown-item command="locate">地图标绘</el-dropdown-item>
</el-dropdown-menu>
</el-dropdown>
</div>
)
},
handleSliderOption(command, data) {
this.selected = JSON.parse(JSON.stringify({...data, command}))
if (command == "edit") {//修改名称
this.dialog = true
} else if (command == "area") {//绑定areaId
this.$refs.BindArea?.chooseArea()
} else if (command == "locate") {//地图标绘
this.latlng = data.lat && data.lng ? {
lat: data.lat,
lng: data.lng
} : ''
this.locate = true
}
},
handleSubmit(row) {
delete row.createTime
return this.instance.post("/app/appzyvideoequipment/addOrUpdate", {
...row
}).then(res => {
if (res?.code == 0) {
this.$message.success("提交成功!")
this.dialog = false
this.$refs.DeviceSlider?.getDevices()
}
})
},
handleLocate(row, locate) {
if (locate) {
let {lat, lng} = locate.location
this.handleSubmit({...row, lat, lng}).then(() => {
this.locate = false
})
}
} else return (
<div class="flexRow">
<div>{node.label}</div>
{data.id != 'no_area' ? <div class="sta">
<p>{data.online || 0}</p>/{data.sum || 0}
</div>
: <div/>}
</div>
)
},
handleSliderOption(command, data) {
this.selected = JSON.parse(JSON.stringify({...data, command}))
if (command == "edit") {//修改名称
this.dialog = true
} else if (command == "area") {//绑定areaId
this.$refs.BindArea?.chooseArea()
} else if (command == "locate") {//地图标绘
this.latlng = data.lat && data.lng ? {
lat: data.lat,
lng: data.lng
} : ''
this.locate = true
}
},
beforeDestroy() {
this.monitors = []
handleSubmit(row) {
delete row.createTime
return this.instance.post("/app/appzyvideoequipment/addOrUpdate", {
...row
}).then(res => {
if (res?.code == 0) {
this.$message.success("提交成功!")
this.dialog = false
this.$refs.DeviceSlider?.getDevices()
}
})
},
handleLocate(row, locate) {
if (locate) {
let {lat, lng} = locate.location
this.handleSubmit({...row, lat, lng}).then(() => {
this.locate = false
})
}
}
},
beforeDestroy() {
this.monitors = []
}
}
</script>
<style lang="scss" scoped>

View File

@@ -15,13 +15,14 @@
</el-button>
</template>
</ai-search-bar>
<ai-table :tableData="tableData"
:col-configs="colConfigs"
:total="total"
ref="aitableex"
:current.sync="search.current"
:size.sync="search.size"
@getList="getAppLeaveMessage">
<ai-table :tableData="tableData"
:col-configs="colConfigs"
:total="total"
ref="aitableex"
:current.sync="search.current"
:size.sync="search.size"
:dict="dict"
@getList="getAppLeaveMessage">
<el-table-column label="是否公示" slot="isPublic" align="center" width="150">
<template v-slot="{row}">
<el-switch v-model="row.isPublic" @change="onChange(row)" active-value="0" inactive-value="1"
@@ -31,7 +32,9 @@
<el-table-column label="操作" slot="options" align="center" width="150">
<template v-slot="{row}">
<el-button type="text" title="详情" @click="toDetail(row.id)" v-if="$permissions('app_appleavemessagereply_detail')">详情</el-button>
<el-button type="text" title="详情" @click="toDetail(row.id)"
v-if="$permissions('app_appleavemessagereply_detail')">详情
</el-button>
</template>
</el-table-column>
</ai-table>
@@ -123,7 +126,6 @@ export default {
onChange({id, isPublic}) {
this.instance.post(`/app/appleavemessage/public?id=${id}`).then(res => {
if (res.code == 0) {
console.log(isPublic)
this.$message.success(isPublic == 1 ? "已公示" : "不公示")
this.getAppLeaveMessage()
}
@@ -213,15 +215,14 @@ export default {
...mapState(['user']),
colConfigs() {
return [
{ prop: 'msgCode', label: '编号', align: 'center' },
{ prop: 'title', label: '标题', align: 'center' },
{ prop: 'type', label: '类型', align: 'center',
render:(h,{row})=>[<span>{this.dict.getLabel('leaveMessageType', row.type)}</span>] },
{ prop: 'leaveName', label: '留言', align: 'center' },
{ prop: 'createTime', label: '留言提交时间', align: 'center' },
{ prop: 'lastReplyTime', label: '最后回复时间', align: 'center' },
{ slot: 'isPublic'},
{ slot: 'options'},
{prop: 'msgCode', label: '编号', align: 'center'},
{prop: 'title', label: '标题', align: 'center'},
{prop: 'type', label: '类型', align: 'center', dict: "leaveMessageType"},
{prop: 'leaveName', label: '留言人', align: 'center'},
{prop: 'createTime', label: '留言提交时间', align: 'center'},
{prop: 'lastReplyTime', label: '最后回复时间', align: 'center'},
{slot: 'isPublic'},
{slot: 'options'},
]
}
}

View File

@@ -7,58 +7,62 @@
<el-select v-model="search.department" placeholder="请选择所属部门" @change="page.current=1,getList()"
size="small" clearable>
<el-option
v-for="(item,i) in dict.getDict('hbDepartment')" :key="i"
:label="item.dictName"
:value="item.dictValue">
v-for="(item,i) in dict.getDict('hbDepartment')" :key="i"
:label="item.dictName"
:value="item.dictValue">
</el-option>
</el-select>
<el-select v-model="search.classificationId" placeholder="请选择所属分类" @change="page.current=1,getList()"
size="small" clearable>
<el-option
v-for="(item,i) in classList" :key="i"
:label="item.name"
:value="item.id">
v-for="(item,i) in classList" :key="i"
:label="item.name"
:value="item.id">
</el-option>
</el-select>
</template>
<template #right>
<el-input
v-model="search.processName"
size="small"
placeholder="事项名称/创建人"
@clear="search={},page.current=1,getList()"
v-throttle="() => {page.current = 1, getList()}"
clearable
suffix-icon="iconfont iconSearch"/>
v-model="search.processName"
size="small"
placeholder="事项名称/创建人"
@clear="search={},page.current=1,getList()"
v-throttle="() => {page.current = 1, getList()}"
clearable
suffix-icon="iconfont iconSearch"/>
</template>
</ai-search-bar>
<ai-search-bar>
<template #left>
<el-button type="primary" icon="iconfont iconAdd" @click="goPage(tab.value==0 ? 'addConfig':'guidance')">添加{{tab.value==0?'事项':'办事指南'}}</el-button>
<el-button type="primary" icon="iconfont iconAdd" @click="goPage(tab.value==0 ? 'addConfig':'guidance')">
添加{{ tab.value == 0 ? '事项' : '办事指南' }}
</el-button>
</template>
</ai-search-bar>
<ai-table
:tableData="tableData"
:col-configs="colConfigs"
:header-cell-style="{fontWeight:'bold',color:'#333'}"
:total="page.total"
:current.sync="page.current"
:size.sync="page.size"
@getList="getList">
:tableData="tableData"
:col-configs="colConfigs"
:header-cell-style="{fontWeight:'bold',color:'#333'}"
:total="page.total"
:current.sync="page.current"
:size.sync="page.size"
:dict="dict"
@getList="getList">
<el-table-column label="是否启用" slot="processDefStatus" align="center" width="150">
<template v-slot="{row}">
<el-switch
v-model="row.processDefStatus"
@change="onChange(row)" active-value="1" inactive-value="0"
active-color="#5088FF"
inactive-color="#D0D4DC">
v-model="row.processDefStatus"
@change="onChange(row)" active-value="1" inactive-value="0"
active-color="#5088FF"
inactive-color="#D0D4DC">
</el-switch>
</template>
</el-table-column>
<el-table-column label="操作" slot="options" align="center" width="150">
<template v-slot="{row}">
<div class="table-options">
<el-button type="text" title="编辑" @click="goPage(tab.value==0 ? 'addConfig':'guidance',row)">编辑</el-button>
<el-button type="text" title="编辑" @click="goPage(tab.value==0 ? 'addConfig':'guidance',row)">编辑
</el-button>
<el-button type="text" title="删除" @click="delInfo(row)">删除</el-button>
</div>
</template>
@@ -70,145 +74,141 @@
</template>
<script>
import day from 'dayjs'
import day from 'dayjs'
export default {
name: "configList",
props: {
instance: Function,
dict: Object,
permissions: Function,
tab: Object,
},
data() {
return {
search: {
department: "",
classificationId: "",
processName: "",
export default {
name: "configList",
props: {
instance: Function,
dict: Object,
permissions: Function,
tab: Object,
},
data() {
return {
search: {
department: "",
classificationId: "",
processName: "",
},
page: {current: 1, size: 10},
total: 0,
row: {},
tableData: [],
classList: [],
}
},
computed: {
colConfigs() {
return [
{
prop: 'processName',
align: 'left',
label: '事项名称',
},
page: {current: 1, size: 10},
total: 0,
row: {},
tableData: [],
classList: [],
}
{
prop: 'department',
align: 'left',
label: '所属部门',
dict: "hbDepartment"
},
{
prop: 'classificationName',
align: 'center',
label: '所属分类',
},
{
prop: 'timeLimit',
align: 'center',
label: '办结时限(日)',
},
{
prop: 'createUserName',
align: 'center',
label: '创建人',
},
{
prop: 'createTime',
align: 'center',
label: '最后修改时间',
render: (h, {row}) => h('p', day(row.createTime).format("YYYY-MM-DD HH:mm"))
},
{slot: 'processDefStatus', align: 'center', label: '是否启用',},
{slot: 'options', align: 'center', label: '操作',},
].filter(e => this.tab.value == 0 ? true : (e.prop != "timeLimit"))
},
computed: {
colConfigs() {
return [
{
prop: 'processName',
align: 'left',
label: '事项名称',
},
{
prop: 'department',
align: 'left',
label: '所属部门',
render: (h, {row}) => [ < span > {this.dict.getLabel('hbDepartment', row.department)} < /span>]
},
{
prop: 'classificationName',
align: 'center',
label: '所属分类',
},
{
prop: 'timeLimit',
align: 'center',
label: '办结时限(日)',
},
{
prop: 'createUserName',
align: 'center',
label: '创建人',
},
{
prop: 'createTime',
align: 'center',
label: '最后修改时间',
render: (h, {row}) => [ < span > {day(row.createTime
).
format("YYYY-MM-DD HH:mm")
}<
/span>]
},
{slot: 'processDefStatus', align:'center', label:'是否启用',},
{ slot: 'options',align:'center',label:'操作',},
].filter(e=>this.tab.value==0 ? true : (e.prop!="timeLimit"))
},
},
methods: {
goPage(comp, row = {}) {
this.$emit("goPage", {comp, row})
},
methods: {
goPage(comp, row = {}) {
this.$emit("goPage", {comp, row})
},
/**
* 获取分类
*/
getClassification() {
this.instance.post(`/app/zwspapprovalclassification/list`, null, {
params:{
current: 1,
status: 1,
size: 9999
}
}).then(res => {
if (res && res.data) {
this.classList = res.data.records
}
})
},
/**
* 删除
* */
delInfo({id}) {
this.$confirm("是否删除").then(() => {
this.instance.post(`/app/approval-process-def/delete?id=${id}`).then(res => {
if (res.code == 0) {
this.$message.success("删除成功")
this.getList()
}
})
})
},
/**
* 启用,停用
*/
onChange({id, processDefStatus}) {
this.instance.post(`/app/approval-process-def/enable-disable`, null, {
params: {id}
}).then(res => {
/**
* 获取分类
*/
getClassification() {
this.instance.post(`/app/zwspapprovalclassification/list`, null, {
params: {
current: 1,
status: 1,
size: 9999
}
}).then(res => {
if (res && res.data) {
this.classList = res.data.records
}
})
},
/**
* 删除
* */
delInfo({id}) {
this.$confirm("是否删除").then(() => {
this.instance.post(`/app/approval-process-def/delete?id=${id}`).then(res => {
if (res.code == 0) {
this.$message.success(processDefStatus == 0 ? "不启用" : "已启用")
this.$message.success("删除成功")
this.getList()
}
})
},
})
},
/**
* 启用,停用
*/
onChange({id, processDefStatus}) {
this.instance.post(`/app/approval-process-def/enable-disable`, null, {
params: {id}
}).then(res => {
if (res.code == 0) {
this.$message.success(processDefStatus == 0 ? "不启用" : "已启用")
this.getList()
}
})
},
getList() {
this.instance.post(`/app/approval-process-def/list`, null, {
params: {
...this.page,
...this.search,
processType: this.tab.value
},
}).then(res => {
if (res?.data) {
this.tableData = res.data.records
this.page.total = res.data.total;
}
})
},
getList() {
this.instance.post(`/app/approval-process-def/list`, null, {
params: {
...this.page,
...this.search,
processType: this.tab.value
},
}).then(res => {
if (res?.data) {
this.tableData = res.data.records
this.page.total = res.data.total;
}
})
},
mounted() {
this.getList()
this.getClassification()
},
}
},
mounted() {
this.getList()
this.getClassification()
},
}
</script>
<style lang="scss" scoped>
.config-list {
height: 100%;
}
.config-list {
height: 100%;
}
</style>

View File

@@ -26,6 +26,7 @@
:total="total"
:current.sync="page.current"
:size.sync="page.size"
:dict="dict"
@getList="getList">
<el-table-column slot="option" label="操作" fixed="right" width="300" align="center">
<template slot-scope="{ row }">
@@ -80,7 +81,7 @@
{prop: 'viewTotal', label: '浏览数', align: 'center'},
{prop: 'publishUserName', label: '发布人'},
{prop: 'publishTime', label: '发布时间'},
{prop: 'status', label: '发布状态', align: 'center',render:(h,{row})=>[<span>{this.$dict.getLabel('newsCenterStatus',row.status)}</span>]},
{prop: 'status', label: '发布状态', align: 'center',dict:"newsCenterStatus"},
{slot: 'option'},
]
}

View File

@@ -53,6 +53,7 @@
:total="total"
:current.sync="search.current"
:size.sync="search.size"
:dict="dict"
@getList="getList">
<el-table-column slot="readUserName" label="姓名" align="center">
<template slot-scope="{ row }">
@@ -103,9 +104,8 @@ export default {
{slot: "unitName"},
{
prop: "readStatus", label: "查阅状态", align: "center",
render: (h, {row}) => [<span
style={{color: this.dict.getColor("announcementReadStatus", row.readStatus)}}>{this.dict.getLabel("announcementReadStatus", row.readStatus)}</span>]
},
render: (h, {row}) => h('p', {color: this.dict.getColor("announcementReadStatus", row.readStatus)}, this.dict.getLabel("announcementReadStatus", row.readStatus))
}
];
}
},

View File

@@ -40,6 +40,7 @@
:total="total"
:current.sync="search.current"
:size.sync="search.size"
:dict="dict"
@getList="getList">
<el-table-column slot="releaseUserName" label="发布人" align="center">
<template slot-scope="{ row }">
@@ -123,17 +124,20 @@ export default {
{prop: 'title', label: '标题'},
{
prop: 'readNum', label: '查询状态', align: 'center',
render: (h, {row}) => [<span class='status'
onClick={this.showDialog.bind(this, row)}>{row.readNum}人已读</span>,
<span class='status' onClick={this.showDialog.bind(this, row)}>{row.unReadNum}人未读</span>]
render: (h, {row}) => h('p', {
class: 'status', on: {
click() {
this.showDialog(row)
}
}
}, `${row.readNum || 0}人已读,${row.unReadNum}人未读`)
},
{slot: 'releaseUserName'},
{slot: 'unitName'},
{prop: 'releaseTime', label: '发布时间', align: 'center'},
{
prop: 'status', label: '发布状态', align: 'center',
render: (h, {row}) => [<span
style={{color: this.dict.getColor("announcementStatus", row.status)}}>{this.dict.getLabel("announcementStatus", row.status)}</span>]
render: (h, {row}) => h('p', {color: this.dict.getColor("announcementStatus", row.status)}, this.dict.getLabel("announcementStatus", row.status))
},
{slot: 'options'},
];

View File

@@ -3,56 +3,59 @@
<template slot="content">
<ai-search-bar>
<template slot="left">
<el-button :disabled="!permissions('app_appactivity_edit')" icon="iconfont iconAdd" type="primary" size="small" @click="add">添加</el-button>
<el-button :disabled="!permissions('app_appactivity_edit')" icon="iconfont iconAdd" type="primary"
size="small" @click="add">添加
</el-button>
</template>
<template slot="right">
<el-input
placeholder="请输入标题"
size="small"
clearable
v-model="search.title"
v-throttle="() => {search.current = 1, getList()}"
@clear="search.current = 1, search.title = '', getList()"
suffix-icon="iconfont iconSearch" />
placeholder="请输入标题"
size="small"
clearable
v-model="search.title"
v-throttle="() => {search.current = 1, getList()}"
@clear="search.current = 1, search.title = '', getList()"
suffix-icon="iconfont iconSearch"/>
</template>
</ai-search-bar>
<div class="ai-table">
<ai-table
:tableData="tableData"
:col-configs="colConfigs"
:total="total"
:current.sync="search.current"
:size.sync="search.size"
@getList="getList">
:tableData="tableData"
:col-configs="colConfigs"
:total="total"
:current.sync="search.current"
:size.sync="search.size"
:dict="dict"
@getList="getList">
<el-table-column slot="options" label="操作" align="center" width="250" fixed="right">
<template slot-scope="{ row }">
<div class="table-options">
<el-button
type="text"
@click="publish(row)"
:title="row.status === '1' ? '取消发布' : '发布'"
:disabled="!permissions('app_appvillageinfo_edit')">
type="text"
@click="publish(row)"
:title="row.status === '1' ? '取消发布' : '发布'"
:disabled="!permissions('app_appvillageinfo_edit')">
{{ row.status === '1' ? '取消发布' : '发布' }}
</el-button>
<el-button
type="text"
title="详情"
@click="toDetail(row.id)"
:disabled="!permissions('app_appactivity_detail')">
type="text"
title="详情"
@click="toDetail(row.id)"
:disabled="!permissions('app_appactivity_detail')">
详情
</el-button>
<el-button
type="text"
title="编辑"
@click="toAdd(row.id)"
:disabled="!permissions('app_appactivity_edit')">
type="text"
title="编辑"
@click="toAdd(row.id)"
:disabled="!permissions('app_appactivity_edit')">
编辑
</el-button>
<el-button
@click="remove(row.id)"
type="text"
title="删除"
:disabled="!permissions('app_appactivity_del')">
@click="remove(row.id)"
type="text"
title="删除"
:disabled="!permissions('app_appactivity_del')">
删除
</el-button>
</div>
@@ -65,133 +68,133 @@
</template>
<script>
import { mapState } from 'vuex'
import {mapState} from 'vuex'
export default {
name: 'ReportEvent',
props: {
instance: Function,
dict: Object,
areaId: String,
permissions: Function
export default {
name: 'ReportEvent',
props: {
instance: Function,
dict: Object,
areaId: String,
permissions: Function
},
computed: {
...mapState(['user']),
colConfigs() {
return [
{prop: 'title', label: '标题'},
{prop: 'type', label: '活动名称', dict: "activityAirticleType"},
{prop: 'readCount', label: '浏览数', align: 'center'},
{prop: 'commentCount', label: '评论数', align: 'center'},
{prop: 'createDate', label: '创建时间'},
{prop: 'status', label: '发布状态', dict: "villInfoStatus"},
{slot: 'options', label: '操作'}
]
}
},
data() {
return {
search: {
current: 1,
size: 10,
title: ''
},
total: 0,
ids: [],
tableData: [],
}
},
created() {
this.dict.load("activityAirticleType", 'villInfoStatus').then(() => this.getList())
},
methods: {
getList() {
this.instance.post(`/app/appactivity/list`, null, {
params: {
...this.search,
areaId: this.areaId
}
}).then(res => {
if (res.data) {
this.tableData = res.data.records
this.total = res.data.total
}
})
},
computed: {
...mapState(['user']),
colConfigs() {
return [
{ prop: 'title', label: '标题'},
{ prop: 'type', label: '活动名称',render:(h,{row})=>[<span>{this.dict.getLabel('activityAirticleType', row.type)}</span>]},
{ prop: 'readCount', label: '浏览数', align: 'center' },
{ prop: 'commentCount', label: '评论数', align: 'center' },
{ prop: 'createDate', label: '创建时间'},
{ prop: 'status', label: '发布状态',render:(h,{row})=>[<span>{this.dict.getLabel('villInfoStatus', row.status)}</span>]},
{ slot: 'options', label: '操作' }
]
}
},
data () {
return {
search: {
current: 1,
size: 10,
title: ''
},
total: 0,
ids: [],
tableData: [],
}
},
created () {
this.dict.load("activityAirticleType",'villInfoStatus').then(() => this.getList())
},
methods: {
getList () {
this.instance.post(`/app/appactivity/list`, null, {
params: {
...this.search,
areaId: this.areaId
}
publish(params) {
this.$confirm(`是否${params.status === '1' ? '取消发布' : '发布'}该条数据?`).then(() => {
this.instance.post(`/app/appactivity/updateCountYardstatus`, {
id: params.id,
status: params.status === '1' ? 0 : 1
}).then(res => {
if (res.data) {
this.tableData = res.data.records
this.total = res.data.total
if (res.code == 0) {
this.$message.success(`${params.status === '1' ? '取消发布' : '发布'}成功!`)
this.getList()
}
})
},
})
},
publish (params) {
this.$confirm(`是否${params.status === '1' ? '取消发布' : '发布'}该条数据?`).then(() => {
this.instance.post(`/app/appactivity/updateCountYardstatus`, {
id: params.id,
status: params.status === '1' ? 0 : 1
}).then(res => {
if (res.code == 0) {
this.$message.success(`${params.status === '1' ? '取消发布' : '发布'}成功!`)
this.getList()
}
})
})
},
toAdd(id) {
this.$emit('change', {
type: 'add',
params: {
id
}
})
},
toAdd (id) {
this.$emit('change', {
type: 'add',
params: {
id
add() {
this.$emit('change', {
type: 'add',
params: {
id: ''
}
})
},
toEdit(id) {
this.$emit('change', {
type: 'add',
params: {
type: 'ReportAdd',
id
}
})
},
toDetail(id) {
this.$emit('change', {
type: 'detail',
params: {
type: 'eventDetail',
id
}
})
},
remove(id) {
this.$confirm('确定删除该数据?').then(() => {
this.instance.post(`/app/appactivity/delete?ids=${id}`).then(res => {
if (res.code == 0) {
this.$message.success('删除成功!')
this.getList()
}
})
},
add () {
this.$emit('change', {
type: 'add',
params: {
id: ''
}
})
},
toEdit (id) {
this.$emit('change', {
type: 'add',
params: {
type: 'ReportAdd',
id
}
})
},
toDetail (id) {
this.$emit('change', {
type: 'detail',
params: {
type: 'eventDetail',
id
}
})
},
remove (id) {
this.$confirm('确定删除该数据?').then(() => {
this.instance.post(`/app/appactivity/delete?ids=${id}`).then(res => {
if (res.code == 0) {
this.$message.success('删除成功!')
this.getList()
}
})
})
}
})
}
}
}
</script>
<style lang="scss" scoped>
.join-event {
height: 100%;
}
.join-event {
height: 100%;
}
</style>

View File

@@ -13,13 +13,13 @@
</div>
</div>
<div class="header-right">
<!-- <div class="header-right__item">-->
<!-- <span>成员总数</span>-->
<!-- <h3>{{ chartData.groupSum}}</h3>-->
<!-- </div>-->
<!-- <div class="header-right__item">-->
<!-- <span>成员总数</span>-->
<!-- <h3>{{ chartData.groupSum}}</h3>-->
<!-- </div>-->
<div class="header-right__item">
<span>成员总数</span>
<h3>{{chartData.today && chartData.today.total }}</h3>
<h3>{{ chartData.today && chartData.today.total }}</h3>
</div>
<div class="header-right__item">
<span>今日新增</span>
@@ -27,13 +27,13 @@
</div>
<div class="header-right__item">
<span>今日流失</span>
<h3>{{chartData.today && chartData.today.decrease}}</h3>
<h3>{{ chartData.today && chartData.today.decrease }}</h3>
</div>
</div>
</div>
<div class="detail-top__content">
<ai-wrapper
label-width="80px">
label-width="80px">
<ai-info-item label="群主" :value="info.ownerName"></ai-info-item>
<ai-info-item label="群公告" :value="info.notice" isLine></ai-info-item>
<ai-info-item label="群聊标签" isLine>
@@ -53,14 +53,25 @@
<ai-card title="成员列表">
<template slot="content">
<ai-table
:tableData="tableData"
:col-configs="colConfigs"
:total="total"
border
ref="aitableex"
@getList="getDynamicInfo"
:current.sync="search.current"
:size.sync="search.size">
:tableData="tableData"
:col-configs="colConfigs"
:total="total"
border
ref="aitableex"
@getList="getDynamicInfo"
:current.sync="search.current"
:size.sync="search.size"
:dict="dict">
<el-table-column slot="member" label="成员">
<template slot-scope="{row}">
<el-row type="flex" align="middle">
<img class="avatar" :src='row.avatar || "https://cdn.cunwuyun.cn/dvcp/h5/defaultAvatar.png"'/>
<div v-text="row.memberName"/>
<span :style="{color: row.customerType == 1 ? '#2EA222' : '#3C7FC8', marginLeft: '8px'}"
v-text="(row.customerType == 1 ? '@微信' : '@' + row.corpName)|| ''"/>
</el-row>
</template>
</el-table-column>
<el-table-column slot="options" label="操作" width="100" align="center">
<template slot-scope="{ row }">
<el-button type="text" v-if="row.type==2 && row.avatar" @click="toDetail(row)">居民详情</el-button>
@@ -74,304 +85,300 @@
</template>
<script>
import * as echarts from 'echarts'
import * as echarts from 'echarts'
export default {
name: 'Detail',
export default {
name: 'Detail',
props: {
instance: Function,
dict: Object,
params: Object
},
props: {
instance: Function,
dict: Object,
params: Object
},
computed: {
colConfigs() {
return [
{
prop: 'memberName', label: '成员',render:(h,{row})=>[<img class="avatar" src={row.avatar || "https://cdn.cunwuyun.cn/dvcp/h5/defaultAvatar.png"} />,
<span>{row.memberName}</span>,
<span style={{color:row.customerType==1 ? '#2EA222' : '#3C7FC8',marginLeft:'8px'}}>{ row.customerType?(row.customerType==1 ? '@微信' : '@' + row.corpName):'' }</span>],
computed: {
colConfigs() {
return [
{slot: "member"},
{prop: 'type', label: '类型', dict: "wxGroupMemberType"},
{prop: 'joinTime', label: '入群时间'},
{prop: 'joinScene', label: '入群方式', dict: "wxGroupMemberJoinScene"},
{slot: "options"},
]
}
},
data() {
return {
isShow: false,
info: {},
search: {
current: 1,
size: 10
},
{prop: 'type', label: '类型',render:(h,{row})=>[<span>{this.dict.getLabel("wxGroupMemberType",row.type)}</span>]},
{prop: 'joinTime', label: '入群时间'},
{prop: 'joinScene', label: '入群方式',render:(h,{row})=>[<span>{this.dict.getLabel("wxGroupMemberJoinScene",row.joinScene)}</span>]},
{slot: "options"},
]
}
},
total: 0,
tableData: [],
chart: null,
chartData: {},
}
},
data() {
return {
isShow: false,
info: {},
search: {
current: 1,
size: 10
created() {
this.dict.load("wxGroupMemberJoinScene", "wxGroupMemberType")
},
mounted() {
if (this.params && this.params.id) {
this.getInfo()
this.getDynamicInfo()
this.getChart()
}
},
methods: {
getChart() {
this.instance.post(`/app/wxcp/wxgroup/groupStatistic`, null, {
params: {
id: this.params.id
}
}).then(res => {
if (res && res.data) {
this.chartData = res.data
this.initChart()
}
})
},
initChart() {
this.chart = echarts.init(document.getElementById('lineChart'))
this.setOptions()
},
setOptions() {
const x = Object.keys(this.chartData.list)
const y = Object.values(this.chartData.list)
this.chart.setOption({
tooltip: {
trigger: 'axis'
},
total: 0,
tableData: [],
chart: null,
chartData: {},
}
},
created() {
this.dict.load("wxGroupMemberJoinScene", "wxGroupMemberType")
},
mounted() {
if (this.params && this.params.id) {
this.getInfo()
this.getDynamicInfo()
this.getChart()
}
},
methods: {
getChart() {
this.instance.post(`/app/wxcp/wxgroup/groupStatistic`, null, {
params: {
id: this.params.id
}
}).then(res => {
if (res && res.data) {
this.chartData = res.data
this.initChart()
}
})
},
initChart() {
this.chart = echarts.init(document.getElementById('lineChart'))
this.setOptions()
},
setOptions() {
const x = Object.keys(this.chartData.list)
const y = Object.values(this.chartData.list)
this.chart.setOption({
tooltip: {
trigger: 'axis'
legend: {
type: "plain"
},
grid: {
left: '20px',
right: '38px',
bottom: '14px',
top: '30px',
containLabel: true
},
color: ['#2266FF', '#22AA99', '#F8B425'],
xAxis: {
type: 'category',
axisLabel: {
align: 'center',
padding: [2, 0, 0, 0],
interval: 0,
fontSize: 14,
color: '#666666'
},
legend: {
type: "plain"
},
grid: {
left: '20px',
right: '38px',
bottom: '14px',
top: '30px',
containLabel: true
},
color: ['#2266FF', '#22AA99', '#F8B425'],
xAxis: {
type: 'category',
axisLabel: {
align: 'center',
padding: [2, 0, 0, 0],
interval: 0,
fontSize: 14,
color: '#666666'
},
boundaryGap: false,
axisLine: {
lineStyle: {
color: '#E1E5EF'
}
},
data: x
},
yAxis: {
axisTick: {
length: 0,
show: false
},
splitLine: {
show: true,
lineStyle: {
color: ['#E1E5EF'],
width: 1,
type: 'solid'
}
},
nameTextStyle: {
color: '#666666',
align: 'left'
},
axisLine: {
show: false
},
axisLabel: {
color: '#666666'
},
type: 'value'
},
series: [
{
name: '成员总数',
type: 'line',
data: y.map(v => v.total)
},
{
name: '新增成员数',
type: 'line',
data: y.map(v => v.increase)
},
{
name: '流失成员数',
type: 'line',
data: y.map(v => v.decrease)
boundaryGap: false,
axisLine: {
lineStyle: {
color: '#E1E5EF'
}
]
})
},
getInfo() {
this.instance.post(`/app/wxcp/wxgroup/getDetail?id=${this.params.id}`).then(res => {
if (res && res.data) {
this.info = res.data
},
data: x
},
yAxis: {
axisTick: {
length: 0,
show: false
},
splitLine: {
show: true,
lineStyle: {
color: ['#E1E5EF'],
width: 1,
type: 'solid'
}
},
nameTextStyle: {
color: '#666666',
align: 'left'
},
axisLine: {
show: false
},
axisLabel: {
color: '#666666'
},
type: 'value'
},
series: [
{
name: '成员总数',
type: 'line',
data: y.map(v => v.total)
},
{
name: '新增成员数',
type: 'line',
data: y.map(v => v.increase)
},
{
name: '流失成员数',
type: 'line',
data: y.map(v => v.decrease)
}
})
},
]
})
},
getDynamicInfo() {
this.instance.post(`/app/wxcp/wxgroup/listMember?groupId=${this.params.id}`, null, {
params: {
...this.search
}
}).then(res => {
if (res.code === 0) {
this.tableData = res.data.records
this.total = res.data.total
}
})
},
getInfo() {
this.instance.post(`/app/wxcp/wxgroup/getDetail?id=${this.params.id}`).then(res => {
if (res && res.data) {
this.info = res.data
}
})
},
toDetail(row) {
this.$router.push({
name: '68',
query: {
id: row.userId,
type: 'Detail'
}
})
},
getDynamicInfo() {
this.instance.post(`/app/wxcp/wxgroup/listMember?groupId=${this.params.id}`, null, {
params: {
...this.search
}
}).then(res => {
if (res.code === 0) {
this.tableData = res.data.records
this.total = res.data.total
}
})
},
cancel(isRefresh) {
this.$emit('change', {
type: 'list',
isRefresh: isRefresh ? true : false
})
}
toDetail(row) {
this.$router.push({
name: '68',
query: {
id: row.userId,
type: 'Detail'
}
})
},
cancel(isRefresh) {
this.$emit('change', {
type: 'list',
isRefresh: isRefresh ? true : false
})
}
}
}
</script>
<style scoped lang="scss">
.AppResidentManage {
::v-deep .ai-detail__content--wrapper {
max-width: 100% !important;
padding: 20px;
.AppResidentManage {
::v-deep .ai-detail__content--wrapper {
max-width: 100% !important;
padding: 20px;
}
h2, h3 {
margin: 0;
}
.detail-top {
padding: 30px 40px;
background: #FFFFFF;
box-shadow: 0px 4px 6px -2px rgba(15, 15, 21, 0.15);
border-radius: 2px;
margin-bottom: 20px;
.detail-top__content {
padding-top: 32px;
}
h2, h3 {
margin: 0;
}
.detail-top__header {
display: flex;
justify-content: space-between;
align-items: center;
padding-bottom: 32px;
border-bottom: 1px solid #EEEEEE;
.detail-top {
padding: 30px 40px;
background: #FFFFFF;
box-shadow: 0px 4px 6px -2px rgba(15, 15, 21, 0.15);
border-radius: 2px;
margin-bottom: 20px;
.header-right {
.header-right__item {
width: 120px;
margin-right: 8px;
text-align: center;
}
.detail-top__content {
padding-top: 32px;
div {
text-align: center;
&:last-child {
margin-right: 0;
}
span {
display: block;
margin-bottom: 10px;
color: #888888;
}
}
.el-button {
height: 28px;
margin-left: 8px;
border-radius: 14px;
font-size: 12px;
padding: 7px 15px;
}
}
.detail-top__header {
.header-left, .header-right {
display: flex;
justify-content: space-between;
align-items: center;
padding-bottom: 32px;
border-bottom: 1px solid #EEEEEE;
}
.header-right {
.header-right__item {
width: 120px;
margin-right: 8px;
text-align: center;
}
div {
text-align: center;
&:last-child {
margin-right: 0;
}
span {
display: block;
margin-bottom: 10px;
color: #888888;
}
}
.el-button {
height: 28px;
margin-left: 8px;
border-radius: 14px;
font-size: 12px;
padding: 7px 15px;
}
.header-left {
img {
width: 64px;
height: 64px;
margin-right: 16px;
}
.header-left, .header-right {
display: flex;
align-items: center;
h2 {
margin-bottom: 6px;
color: #222222;
font-size: 16px;
}
.header-left {
img {
width: 64px;
height: 64px;
margin-right: 16px;
}
h2 {
margin-bottom: 6px;
color: #222222;
font-size: 16px;
}
p {
color: #2EA222;
font-size: 14px;
}
p {
color: #2EA222;
font-size: 14px;
}
}
}
#lineChart {
width: 100%;
height: 336px;
}
.table-tags {
.el-tag {
margin-right: 8px;
&:last-child {
margin-right: 0;
}
}
}
::v-deep .avatar {
width: 40px;
height: 40px;
vertical-align: middle;
margin-right: 8px;
object-fit: fill;
}
}
#lineChart {
width: 100%;
height: 336px;
}
.table-tags {
.el-tag {
margin-right: 8px;
&:last-child {
margin-right: 0;
}
}
}
::v-deep .avatar {
width: 40px;
height: 40px;
vertical-align: middle;
margin-right: 8px;
object-fit: fill;
}
}
</style>

View File

@@ -1,4 +0,0 @@
{
"AppGigscreenViewer": "大屏预览组件",
"AppDesigner": "大屏设计"
}

View File

@@ -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;
}
::v-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>

View File

@@ -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;
::v-deep .eventItem {
width: 100%;
color: #82C5FF;
& > .fill {
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
}
::v-deep .communityEvent {
list-style-type: circle;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
height: 40px;
line-height: 40px;
padding-left: 1px;
color: #82C5FF;
}
::v-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%);
}
::v-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;
}
}
::v-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>

View File

@@ -1,878 +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}`}">
<VueOkrTree
ref="VueOkrTree"
:data="chartData"
node-key="id"
show-collapsable
aniamte
animate-name="okr-fade-in-linear"
:render-content="renderContent"
default-expand-all>
</VueOkrTree>
</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="pieChart">
</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
v-if="tableData.length"
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 pieChart from 'dvcp-dv-ui/components/AiEchart/template/pie/pieChart2'
import barChart1 from 'dvcp-dv-ui/components/AiEchart/template/bar/barChart1'
import { VueOkrTree } from 'vue-okr-tree'
import 'vue-okr-tree/dist/vue-okr-tree.css'
export default {
name: 'AppGridDV',
label: '网格数据大屏',
props: {
instance: Function,
dict: Object,
},
data () {
return {
isLoading: false,
treeList: [],
search: {
size: 100,
current: 1
},
barChart1,
userInfo: [],
eventInfo: [],
pieChart,
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) || '-'))
},
formart: v => this.dict.getLabel('householdRelation', v)
},
{ prop: 'idNumber', label: '身份证号', align: 'center', width: 220, formart: 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'
}
},
components: {
VueOkrTree
},
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, level) {
this.instance.post(`/app/appgirdinfo/listAllGirdAndMemberByTop?id=${id || ''}`).then((res) => {
if (res.code == 0) {
const chartData = this.formatList(res.data)
if (res.data && res.data[0] && res.data[0].parentGirdInfo) {
const parentGirdInfo = res.data[0].parentGirdInfo
const girdMemberList = parentGirdInfo.girdMemberManageList ? parentGirdInfo.girdMemberManageList.map(v => {
return {
...v,
label: v.name,
id: v.id,
checkType: '2',
girdName: parentGirdInfo.girdName,
girdLevel: parentGirdInfo.girdLevel,
isUser: true
}
}) : [{
label: '-',
id: parentGirdInfo.id,
girdLevel: parentGirdInfo.girdLevel,
girdName: parentGirdInfo.girdName
}]
this.chartData = [{
label: parentGirdInfo.girdName,
id: parentGirdInfo.id,
girdLevel: parentGirdInfo.girdLevel,
isUser: false,
children: chartData,
userList: girdMemberList
}]
} else {
this.chartData = chartData
}
this.$nextTick(() => {
if (level === '2') {
this.getUserList(id)
} else {
this.isLoading = false
this.autoScale()
}
})
}
})
},
getUserList (id) {
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(id)
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;
}
}
}
::v-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;
}
}
::v-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;
}
}
::v-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%;
}
::v-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;
}
}
::v-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;
}
::v-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>

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -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;
}
}
::v-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;
}
::v-deep .index {
background-color: transparent !important;
}
::v-deep .header {
background: url("../assets/videoMonitor/titlebox.png");
}
::v-deep .row-item div:nth-child(3) {
font-size: 13px;
color: #00CDFF;
}
}
</style>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 362 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 693 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 445 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 140 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.2 KiB

View File

@@ -1,12 +0,0 @@
{
"name": "dvcp-dv",
"description": "大屏应用",
"version": "1.0.0",
"main": "dist/dvcp-dv.common.js",
"publishConfig": {
"registry": "http://192.168.1.87:4873/"
},
"dependencies": {
"dvcp-dv-ui": "^2.0.0"
}
}

View File

@@ -1,144 +0,0 @@
<template>
<section class="AppDVDemo">
<ai-list>
<ai-title slot="title" title="数据大屏草稿板" isShowBottomBorder/>
<template #content>
<div class="showPanel">
<ai-dv-wrapper :views="views" v-model="active">
<AiDvDisplay></AiDvDisplay>
</ai-dv-wrapper>
</div>
</template>
</ai-list>
</section>
</template>
<script>
import AiDvWrapper from "./layout/AiDvWrapper/AiDvWrapper";
import ops from './components/AiEchart/template/pie/pieChart2'
import AiDvPanel from "./layout/AiDvPanel/AiDvPanel";
import AiDvDisplay from "./layout/AiDvDisplay/AiDvDisplay";
import AiDvSummary from "./layout/AiDvSummary/AiDvSummary";
import AiMonitor from "./components/AiMonitor/AiMonitor";
export default {
name: "AppDVDemo",
label: "数据大屏草稿板",
components: {AiMonitor, AiDvPanel, AiDvWrapper, AiDvDisplay, AiDvSummary},
data() {
return {
ops,
active: '',
views: [
{label: '标准大屏', id: '0'},
{label: '当前大屏', id: '1'},
{label: '平安乡村', id: '2'},
{label: '人口数据', id: '3'},
{label: '人口数据', id: '4'},
{label: '人口数据', id: '5'},
{label: '宅基地', id: '6'},
],
list: [
{name: '阿斯达', v1: 23, v2: 33},
{name: '水电费', v1: 12, v2: 34},
{name: '凡哥', v1: 67, v2: 25},
{name: '党费', v1: 98, v2: 85},
{name: '阿萨德', v1: 98, v2: 85},
{name: '电饭锅', v1: 98, v2: 85},
{name: '户籍科', v1: 98, v2: 85},
],
data: [
{
"key": "阿斯达",
"value": '22',
"percentage": 33,
text: '同比上月'
},
{
"key": "阿斯达",
"value": '22',
"percentage": -33,
text: '同比上月'
}
],
value: [
{
"key": "宅基地 ",
"value": 1252292,
"value1": 12592,
"value2": 12592,
"value3": 12592,
"value4": 12592
},
{
"key": "人数",
"value": 12592,
"value1": 12592,
"value2": 12592,
"value3": 12592,
"value4": 12592
},
{
"key": "户数 ",
"value": 12592,
"value1": 12592,
"value2": 12592,
"value3": 12592,
"value4": 12592
},
{
"key": "村社区",
"value": 12592,
"value1": 12592,
"value2": 12592,
"value3": 12592,
"value4": 12592
}
],
markers: []
}
},
methods: {
getMarkers() {
this.$request.post('/app/appcommunitybuildinginfo/listByBuildingAndHomestead', null, {
params: {current: 1, size: 1000000},
withoutToken: true
}).then(res => {
if (res?.data) {
this.markers = res.data.map(e => ({
...e,
icon: "https://cdn.cunwuyun.cn/dvcp/dv/monitor.svg",
label: e.communityName
}))
}
})
}
},
created() {
// this.getMarkers()
setTimeout(() => {
this.list = this.list.map(e => ({name: e.name, '电费': e.v1, '水费': e.v2 * 2}))
}, 2000)
},
mounted() {
this.$initWxOpenData()
}
}
</script>
<style lang="scss" scoped>
@import "./lib/animation";
.AppDVDemo {
height: 100%;
.showPanel {
height: 600px;
}
.AiDvPanel {
width: 600px;
}
}
</style>

View File

@@ -1,91 +0,0 @@
export default {
legend: {
right: 0,
itemHeight: 5,
itemWidth: 16,
textStyle: { color: '#fff' }
},
yAxis: {
nameGap: 23,
minInterval: 1,
splitLine: { lineStyle: { color: 'rgba(255,255,255,.2)', type: 'dashed' } },
axisLabel: { color: '#fff' },
axisPointer: { show: false }
},
axisPointer: {
type: 'shadow',
triggerTooltip: false,
shadowStyle: { color: 'rgba(46, 153, 255, .2)' }
},
color: [
{
type: 'linear',
x: 0,
x2: 0,
y: 0,
y2: 1,
colorStops: [
{ offset: 0, color: 'rgba(66, 187, 255, 1)' },
{ offset: 1, color: 'rgba(37, 143, 255, 0.2)' }
]
},
{
type: 'linear',
x: 0,
x2: 0,
y: 0,
y2: 1,
colorStops: [
{ offset: 0, color: 'rgba(66, 255, 254, 1)' },
{ offset: 1, color: 'rgba(37, 255, 246, 0.2)' }
]
},
{
type: 'linear',
x: 0,
x2: 0,
y: 0,
y2: 1,
colorStops: [
{ offset: 0, color: 'rgba(97, 253, 185, 1)' },
{ offset: 1, color: 'rgba(97, 253, 185, 0.2)' }
]
},
{
type: 'linear',
x: 0,
x2: 0,
y: 0,
y2: 1,
colorStops: [
{ offset: 0, color: 'rgba(253, 108, 57, 1)' },
{ offset: 1, color: 'rgba(253, 108, 57, 0.2)' }
]
},
{
type: 'linear',
x: 0,
x2: 0,
y: 0,
y2: 1,
colorStops: [
{ offset: 0, color: 'rgba(248, 187, 25, 1)' },
{ offset: 1, color: 'rgba(55, 39, 5, 1)' }
]
}
],
daemon: {
type: 'bar',
label: {
show: true,
position: 'top',
color: '#fff',
formatter: e => {
return e.data[e.seriesName] || ''
}
},
barWidth: 16,
barCategoryGap: 40,
itemStyle: {}
}
}

View File

@@ -1,24 +0,0 @@
export default {
legend: {
right: 0, itemGap: 16,
textStyle: {color: '#fff', padding: [0, 0, 0, 8], fontSize: 14},
itemWidth: 16, itemHeight: 5
},
grid: {
left: 50, right: 0
},
tooltip: {
trigger: 'axis', backgroundColor: 'rgba(14, 51, 111, 0.9)', borderColor: '#1A6ABC',
textStyle: {color: '#fff'}
},
yAxis: {
nameGap: 23, minInterval: 1,
splitLine: {lineStyle: {color: 'rgba(255,255,255,.2)', type: 'dashed'}},
axisLabel: {color: '#fff'}, axisPointer: {show: false}
},
axisPointer: {
type: 'shadow', show: true,
shadowStyle: {color: 'rgba(46, 153, 255, .2)'}
},
daemon: {type: 'bar', barWidth: 2, barGap: 4}
}

View File

@@ -1,33 +0,0 @@
export default {
legend: {show: false},
yAxis: {
nameGap: 23, minInterval: 1,
splitLine: {lineStyle: {color: 'rgba(255,255,255,.2)', type: 'dashed'}},
axisLabel: {color: '#fff'}, axisPointer: {show: false}
},
axisPointer: {
type: 'none', show: true, triggerTooltip: false,
},
daemon: {
type: 'bar', label: {show: true, position: 'insideBottom', color: '#fff'},
barWidth: 24,
showBackground: true,
backgroundStyle: {
color: 'rgba(123, 165, 255, .2)'
},
itemStyle: {
color: {
type: 'linear', x: 0, x2: 0, y: 0, y2: 1,
colorStops: [{offset: 0, color: '#42BBFF'}, {offset: 1, color: 'rgba(37, 143, 255, 0.2)'}]
}
},
emphasis: {
itemStyle: {
color: {
type: 'linear', x: 0, x2: 0, y: 0, y2: 1,
colorStops: [{offset: 0, color: '#42FFFE'}, {offset: 1, color: 'rgba(37, 255, 246, 0.2)'}]
}
}
}
}
}

View File

@@ -1,23 +0,0 @@
export default {
legend: {
right: 0, itemGap: 16,
textStyle: {color: '#fff', padding: [0, 0, 0, 8], fontSize: 14},
itemWidth: 16, itemHeight: 5
},
grid: {
left: 50, right: 0
},
tooltip: {
trigger: 'axis', backgroundColor: 'rgba(14, 51, 111, 0.9)', borderColor: '#1A6ABC',
textStyle: {color: '#fff'}
},
yAxis: {
nameGap: 23, minInterval: 1,
splitLine: {lineStyle: {color: 'rgba(255,255,255,.2)', type: 'dashed'}},
axisLabel: {color: '#fff'}, axisPointer: {show: false}
},
axisPointer: {
type: 'none', show: true, triggerTooltip: false,
},
daemon: {type: 'bar', barWidth: 12, stack: 'stack'}
}

View File

@@ -1,45 +0,0 @@
export default {
legend: {show: false},
tooltip: {
trigger: 'axis',
backgroundColor: 'rgba(14, 51, 111, 0.9)', borderColor: '#1A6ABC', textStyle: {color: '#fff'},
axisPointer: {
type: 'shadow', shadowStyle: {color: 'rgba(46, 153, 255, .2)'},
label: {show: true, backgroundColor: 'transparent', fontSize: 14, margin: 1, color: '#28FBFF'}
}
},
yAxis: {
type: 'category',
axisLabel: {color: '#fff', fontSize: 14},
axisTick: {show: false},
axisLine: {show: false},
},
xAxis: {
nameGap: 23, minInterval: 1,
splitLine: {lineStyle: {color: 'rgba(255,255,255,.2)', type: 'dashed'}},
axisLabel: {color: '#fff', fontSize: 14},
},
daemon: {
type: 'bar', barWidth: 10, barGap: '40%',
label: {show: true, position: 'insideRight', color: '#fff', fontSize: 14},
showBackground: true,
backgroundStyle: {
color: 'rgba(123, 165, 255, .2)'
},
itemStyle: {
color: {
type: 'linear', x: 0, x2: 1, y: 0, y2: 0,
colorStops: [{offset: 0, color: 'rgba(37, 143, 255,.5)'}, {offset: 1, color: 'rgba(43, 199, 255, 1)'}]
}
},
emphasis: {
label: {color: '#28FBFF', position: 'right'},
itemStyle: {
color: {
type: 'linear', x: 0, x2: 1, y: 0, y2: 0,
colorStops: [{offset: 0, color: 'rgba(37, 255, 246, 0.5)'}, {offset: 1, color: '#28FBFF'}]
}
}
}
}
}

View File

@@ -1,36 +0,0 @@
import tools from "../tools";
export default {
legend: {
right: 0, itemGap: 16,
textStyle: {color: '#fff', padding: [0, 0, 0, 8], fontSize: 14},
itemWidth: 16, itemHeight: 5
},
grid: {
left: 50, right: 0
},
tooltip: {
trigger: 'axis',
backgroundColor: 'rgba(14, 51, 111, 0.9)', borderColor: '#1A6ABC', textStyle: {color: '#fff'}
},
yAxis: {
type: 'category',
axisLabel: {color: '#fff', fontSize: 14},
axisLine: {lineStyle: {color: 'rgba(255,255,255,.5)'}},
axisPointer: {show: false},
},
xAxis: {
nameGap: 23, minInterval: 1,
splitLine: {lineStyle: {color: 'rgba(255,255,255,.2)', type: 'dashed'}},
axisLabel: {color: '#fff', fontSize: 14},
},
daemon: {
type: 'bar', barWidth: 10,
itemStyle: {
color: ({color}) => ({
type: 'linear', x: 0, x2: 1, y: 0, y2: 0,
colorStops: [{offset: 0, color: tools.$colorUtils.Hex2RGBA(color, .5)}, {offset: 1, color}]
})
},
}
}

View File

@@ -1,29 +0,0 @@
export default {
legend: {
right: 0, itemGap: 16,
textStyle: {color: '#fff', padding: [0, 0, 0, 8], fontSize: 14},
itemWidth: 16, itemHeight: 5
},
grid: {
left: 80, right: 0
},
tooltip: {
backgroundColor: 'rgba(14, 51, 111, 0.9)', borderColor: '#1A6ABC', textStyle: {color: '#fff'},
},
yAxis: {
type: 'category',
axisLabel: {color: '#fff', fontSize: 14, margin: 23},
axisTick: {show: false},
axisLine: {show: false},
},
xAxis: {
nameGap: 23, minInterval: 1,
splitLine: {lineStyle: {color: 'rgba(255,255,255,.2)', type: 'dashed'}},
axisLabel: {color: '#fff', fontSize: 14},
},
daemon: {
type: 'bar', barWidth: 10, barGap: '40%', stack: 'stack',
showBackground: true,
backgroundStyle: {color: 'rgba(123, 165, 255, .2)'}
}
}

View File

@@ -1,40 +0,0 @@
import tools from '../tools';
export default {
legend: { show: false },
grid: {
left: 50,
right: 0
},
tooltip: {
trigger: 'axis',
backgroundColor: 'rgba(14, 51, 111, 0.9)',
borderColor: '#1A6ABC',
textStyle: { color: '#fff' },
axisPointer: { type: 'cross' }
},
yAxis: {
nameGap: 23,
minInterval: 1,
splitLine: { lineStyle: { color: 'rgba(255,255,255,.2)', type: 'dashed' } },
axisLabel: { color: '#fff' },
axisPointer: { snap: true }
},
daemon: (color) => ({
showSymbol: false,
lineStyle: { shadowBlur: 4, shadowOffsetY: 2 },
areaStyle: {
color: {
type: 'linear',
x: 0,
x2: 0,
y: 0,
y2: 1,
colorStops: [
{ offset: 0, color: tools.$colorUtils.Hex2RGBA(color, 0.5) },
{ offset: 1, color: tools.$colorUtils.Hex2RGBA(color, 0.5) }
]
}
}
})
};

View File

@@ -1,27 +0,0 @@
import tools from "../tools";
export default {
legend: {
right: 0, itemGap: 16,
textStyle: {color: '#fff', padding: [0, 0, 0, 8], fontSize: 14},
},
grid: {
left: 50, right: 0
},
tooltip: {
trigger: 'axis', backgroundColor: 'rgba(14, 51, 111, 0.9)', borderColor: '#1A6ABC',
textStyle: {color: '#fff'}
},
daemon: color => ({
showSymbol: false,
lineStyle: {shadowBlur: 4, shadowOffsetY: 2},
areaStyle: {
color: {
type: 'linear', x: 0, x2: 0, y: 0, y2: 1, colorStops: [
{offset: 0, color: tools.$colorUtils.Hex2RGBA(color, .5)},
{offset: 1, color: tools.$colorUtils.Hex2RGBA(color, 0)},
]
}
}
})
}

View File

@@ -1,16 +0,0 @@
export default {
legend: {
right: 0, itemGap: 16,
textStyle: {color: '#fff', padding: [0, 0, 0, 8], fontSize: 14},
},
grid: {
left: 50, right: 0
},
tooltip: {
trigger: 'axis', backgroundColor: 'rgba(14, 51, 111, 0.9)', borderColor: '#1A6ABC',
textStyle: {color: '#fff'}
},
daemon: {
lineStyle: {shadowBlur: 4, shadowOffsetY: 2},
}
}

View File

@@ -1,19 +0,0 @@
export default {
legend: {
right: 0, itemGap: 16,
textStyle: {color: '#fff', padding: [0, 0, 0, 8], fontSize: 14},
},
grid: {
left: 50, right: 0
},
tooltip: {
trigger: 'axis', backgroundColor: 'rgba(14, 51, 111, 0.9)', borderColor: '#1A6ABC',
textStyle: {color: '#fff'}
},
daemon: {
lineStyle: {shadowBlur: 4, shadowOffsetY: 2},
emphasis: {
focus: 'self'
}
}
}

View File

@@ -1,31 +0,0 @@
import tools from "../tools";
export default {
legend: {show: false},
grid: {
left: 50, right: 0
},
tooltip: {
trigger: 'axis', backgroundColor: 'rgba(14, 51, 111, 0.9)', borderColor: '#1A6ABC',
textStyle: {color: '#fff'},
axisPointer: {type: 'cross'}
},
yAxis: {
nameGap: 23, minInterval: 1,
splitLine: {lineStyle: {color: 'rgba(255,255,255,.2)', type: 'dashed'}},
axisLabel: {color: '#fff'},
axisPointer: {snap: true}
},
daemon: color=> ({
showSymbol: false, smooth: true,
lineStyle: {shadowBlur: 4, shadowOffsetY: 2},
areaStyle: {
color: {
type: 'linear', x: 0, x2: 0, y: 0, y2: 1, colorStops: [
{offset: 0, color: tools.$colorUtils.Hex2RGBA(color, .5)},
{offset: 1, color: tools.$colorUtils.Hex2RGBA(color, 0)},
]
}
}
})
}

View File

@@ -1,96 +0,0 @@
export default {
legend: {
bottom: 0,
itemGap: 14,
itemWidth: 16,
itemHeight: 5,
textStyle: {color: "#fff", fontSize: 14}
},
grid: {
height: 260
},
xAxis: {show: false},
yAxis: {show: false},
tooltip: {
backgroundColor: "rgba(14, 51, 111, 0.9)",
borderColor: "#1A6ABC",
textStyle: {color: "#fff"}
},
series: {
type: "pie",
minShowLabelAngle: 10,
radius: [70, 81],
itemStyle: {
borderColor: "#fff",
borderWidth: 2
},
label: {
color: "#A8D7F3",
fontSize: 14,
formatter: "{name|{b}}\n{v|{d}%}",
minMargin: 5,
edgeDistance: 10,
lineHeight: 22,
rich: {
v: {
color: "#fff"
}
}
},
labelLine: {},
labelLayout: function (params) {
let points = params.labelLinePoints,
isLeft = points[2][0] < points[1][0]
points[2][0] =
points[2][0] + (params.labelRect.width + 4) * (isLeft ? -1 : 1)
return {
labelLinePoints: points
}
}
},
render: (h, params) => {
const formatNum = num => {
if (num >= 10000000) {
return num / 10000000 + "千万"
}
if (num >= 10000) {
return num / 10000 + "万"
}
return parseFloat(num.toFixed(2))
}
let total = params.data.reduce((t, e) => {
return t + Number(Object.values(e)?.[1] || 0)
}, 0)
return h(
"div",
{
style: {
height: "162px",
width: "162px",
color: "#8BCCFF",
left: "50%",
top: "50%",
display: "flex",
alignItems: "center",
justifyContent: "center",
flexDirection: "column",
position: "absolute",
transform: "translate(-50%,-50%)",
backgroundImage: `url('https://cdn.cunwuyun.cn/dvcp/dv/tpl/pie2Circle.png')`,
backgroundPosition: "center"
}
},
[
h(
"span",
{style: {fontSize: "28px", color: "#fff", fontFamily: "DIN"}},
formatNum(total)
),
h("span", null, "总量")
]
)
}
}

View File

@@ -1,24 +0,0 @@
export default {
$colorUtils: {
Hex2RGBA(color, alpha = 1) {
let hex = 0;
if (color.charAt(0) == "#") {
if (color.length == 4) {
//检测诸如#FFF简写格式
color = "#" + color.charAt(1).repeat(2) +
color.charAt(2).repeat(2) +
color.charAt(3).repeat(2);
}
hex = parseInt(color.slice(1), 16);
}
let r = hex >> 16 & 0xFF;
let g = hex >> 8 & 0xFF;
let b = hex & 0xFF;
return `rgba(${r},${g},${b},${alpha})`;
},
RGBtoHex(r, g, b) {
let hex = r << 16 | g << 8 | b;
return "#" + hex.toString(16);
}
}
}

View File

@@ -1,48 +0,0 @@
<template>
<section class="AiMonitor">
<template v-if="type=='cmcc'">
<iframe :src="src" allow="autoplay *; microphone *; fullscreen *" allowfullscreen allowtransparency
allowusermedia frameBorder="no"/>
</template>
<hikversion-monitor v-else-if="type=='hik'" :src="src"/>
<dhVideo v-else-if="type=='dahua'" :src="src"/>
<slwVideo v-else-if="type=='slw'" :src="src"/>
</section>
</template>
<script>
import HikversionMonitor from "./hikversionMonitor";
import dhVideo from "./dhVideo";
import slwVideo from "./slwVideo";
export default {
name: "AiMonitor",
components: {HikversionMonitor, dhVideo, slwVideo},
props: {
/**
* 视频源
*/
src: {default: ""},
/**
* 组件类型
* cmcc 中移物联,hik 海康威视
* @values cmcc,hik
*/
type: {default: "cmcc"},
}
}
</script>
<style lang="scss" scoped>
.AiMonitor {
width: 100%;
height: 100%;
min-width: 100px;
min-height: 60px;
iframe {
width: 100%;
height: 100%;
}
}
</style>

View File

@@ -1,77 +0,0 @@
<template>
<div class="dh-video">
<video :id="id" autoplay class="video-js vjs-default-skin" style="width: 100%; height: 100%;" controls>
<source :src="src">
</video>
</div>
</template>
<script>
import videojs from 'video.js'
import 'videojs-contrib-hls'
import 'video.js/dist/video-js.css'
export default {
props: ['src'],
data () {
return {
id: `video-${new Date().getTime()}`
}
},
watch: {
src: {
handler(val) {
if (val) {
this.$nextTick(() => {
videojs(this.id, {
autoplay: true
}, function () { console.log('videojs播放器初始化成功') })
})
}
},
immediate: true,
deep: true
}
},
mounted () {
if (this.src) {
this.$nextTick(() => {
videojs(this.id, {
autoplay: true
}, function () { console.log('videojs播放器初始化成功') })
})
}
}
}
</script>
<style lang="scss" scoped>
.dh-video {
width: 100%;
height: 100%;
.video-js {
width: 100%!important;
height: 100%!important;
}
::v-deep .video-js {
width: 100%!important;
height: 100%!important;
.vjs-big-play-button {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}
}
& > div {
width: 100%!important;
height: 100%!important;
}
}
</style>

View File

@@ -1,169 +0,0 @@
<template>
<section class="hikversionMonitor">
<div id="monitorIns">
<el-link v-if="needSetupPlugin" href="https://cdn.cunwuyun.cn/wsr/lib/VideoWebPlugin.exe" type="primary">
请检查是否安装视频插件,如果没有请点击下载视频插件并安装
</el-link>
<div v-else>视频插件未启动正在尝试启动请稍候...</div>
</div>
</section>
</template>
<script>
export default {
name: "hikversionMonitor",
props: {
src: {default: ""},
list: {default: () => []}
},
data() {
return {
monitorIns: null,
initCount: 0
}
},
computed: {
needSetupPlugin() {
return this.initCount >= 3
}
},
methods: {
getMonitorWidth() {
let {width} = document.querySelector("#monitorIns")?.getBoundingClientRect()
return width
},
getMonitorHeight() {
let {height} = document.querySelector("#monitorIns")?.getBoundingClientRect()
return height
},
initSDK() {
this.$nextTick(() => {
let width = this.getMonitorWidth(), height = this.getMonitorHeight()
if (width) {
this.monitorIns = new WebControl({
szPluginContainer: "monitorIns", // 指定容器id
iServicePortStart: 15900, // 指定起止端口号,建议使用该值
iServicePortEnd: 15909,
szClassId: "23BF3B0A-2C56-4D97-9C03-0CB103AA8F11", // 用于IE10使用ActiveX的clsid
cbConnectSuccess: () => { // 创建WebControl实例成功
this.monitorIns.JS_StartService("window", { // WebControl实例创建成功后需要启动服务
dllPath: "./VideoPluginConnect.dll" // 值"./VideoPluginConnect.dll"写死
}).then(() => { // 启动插件服务成功
this.monitorIns.JS_CreateWnd("monitorIns", width, height).then(() => { //JS_CreateWnd创建视频播放窗口宽高可设定
this.monitorIns.JS_RequestInterface({
funcName: "getRSAPubKey",
argument: JSON.stringify({
keyLength: 1024
})
}).then((oData) => {
if (oData.responseMsg.data) {
let encrypt = new JSEncrypt();
encrypt.setPublicKey(oData.responseMsg.data);
let secret = encrypt.encrypt("JSqHo9JUgPLQxfCIjsmQ");
this.monitorIns.JS_RequestInterface({
funcName: "init",
argument: JSON.stringify({
appkey: "23335895", //API网关提供的appkey
secret, //API网关提供的secret
ip: "124.128.246.74", //API网关IP地址
playMode: 0, //初始播放模式0-预览1-回放
port: 1443, //端口
snapDir: ".", //抓图存储路径
videoDir: ".", //紧急录像或录像剪辑存储路径
layout: "1x1", //布局
enableHTTPS: 1, //是否启用HTTPS协议
encryptedFields: "secret", //加密字段
showToolbar: 1, //是否显示工具栏
showSmart: 1, //是否显示智能信息
buttonIDs: "0,16,256,257,258,259,260,512,513,514,515,516,517,768,769" //自定义工具条按钮
})
}).then(() => {
this.monitorIns.JS_Resize(width, height); // 初始化后resize一次规避firefox下首次显示窗口后插件窗口未与DIV窗口重合问题
this.startPreview()
})
}
})
});
}, (...args) => {
// 启动插件服务失败
console.log(args)
})
},
cbConnectError: () => {
this.monitorIns = null
WebControl.JS_WakeUp("VideoWebPlugin://");
this.initCount++
if (!this.needSetupPlugin) {
setTimeout(() => {
this.initSDK()
}, 3000)
}
}
})
}
})
},
startPreview() {
const layout = len =>
len <= 1 ? '1x1' :
len == 2 ? '1x2' :
len == 3 ? '1+2' :
len == 4 ? '2x2' :
len < 6 ? '1+5' :
len == 7 ? '3+4' :
len == 8 ? '1+7' :
len == 9 ? '3x3' :
len == 10 ? '1+9' :
len <= 16 ? '4x4' : '4x6'
let list = this.src?.split(",")
this.monitorIns?.JS_RequestInterface({
funcName: "setLayout",
argument: JSON.stringify({layout: layout(list.length)})
}).then(() => {
this.monitorIns?.JS_RequestInterface({
funcName: "startMultiPreviewByCameraIndexCode",
argument: JSON.stringify({
list: list.map((cameraIndexCode, i) => ({
cameraIndexCode, //监控点编号
streamMode: 0, //主子码流标识
transMode: 1, //传输协议
gpuMode: 0, //是否开启GPU硬解
wndId: i + 1 //可指定播放窗口
}))
})
})
})
},
},
watch: {
src(v) {
v && this.monitorIns?.JS_RequestInterface({funcName: "stopAllPreview"}).then(() => this.startPreview())
}
},
mounted() {
this.$injectLib("https://cdn.cunwuyun.cn/wsr/lib/jsencrypt.min.js")
this.$injectLib("https://cdn.cunwuyun.cn/wsr/lib/jsWebControl-1.0.0.min.js", () => {
this.initSDK()
})
},
beforeDestroy() {
this.monitorIns?.JS_DestroyWnd()
}
}
</script>
<style lang="scss" scoped>
.hikversionMonitor {
color: #fff;
height: 100%;
#monitorIns {
height: 100%;
background: #000;
display: flex;
justify-content: center;
align-items: center;
}
}
</style>

View File

@@ -1,90 +0,0 @@
<template>
<div class="slw">
<iframe
v-if="isShow"
:id="id"
allow="autoplay *; microphone *; fullscreen *" allowfullscreen allowtransparency key="" allowusermedia frameBorder="no"
style="width: 100%; height: 100%;"
:src="`https://cdn.cunwuyun.cn/jssdk/slw/index.html?url=${src}`"></iframe>
</div>
</template>
<script>
export default {
props: ['src'],
name: 'slwVideo',
data () {
return {
isShow: true,
id: `video-${new Date().getTime()}`
}
},
watch: {
src: {
handler (val) {
if (val) {
this.isShow = false
this.$nextTick(() => {
this.isShow = true
})
}
},
immediate: true,
deep: true
}
},
mounted () {
window.addEventListener('message', e => {
if (e.data.type && e.data.name === 'fullscreen') {
this.requestFullScreen(document.getElementById(this.id))
}
if (!e.data.type && e.data.name === 'fullscreen') {
this.exitFullscreen()
}
}, false)
},
methods: {
exitFullscreen () {
if (document.exitFullscreen) {
document.exitFullscreen()
} else if (document.msExitFullscreen) {
document.msExitFullscreen()
} else if (document.mozCancelFullScreen) {
document.mozCancelFullScreen()
} else if (document.webkitExitFullscreen) {
document.webkitExitFullscreen()
}
},
requestFullScreen (element) {
var requestMethod = element.requestFullScreen || element.webkitRequestFullScreen || element.mozRequestFullScreen || element.msRequestFullScreen;
if (requestMethod) {
requestMethod.call(element);
} else if (typeof window.ActiveXObject !== 'undefined') {
var wscript = new ActiveXObject('WScript.Shell')
if (wscript !== null) {
wscript.SendKeys('{F11}')
}
}
}
}
}
</script>
<style lang="scss" scoped>
.slw {
width: 100%;
height: 100%;
iframe {
border: none;
}
}
</style>

View File

@@ -1,2 +0,0 @@
# jessibuca-mobile-demo
jessibuca mobile demo

File diff suppressed because one or more lines are too long

View File

@@ -1,72 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
<style>
* {
margin: 0;
}
html,
body {
width: 100%;
height: 100%;
}
#container {
width: 100%;
height: 100%;
background-color: #000;
}
</style>
</head>
<body>
<div id="container"></div>
<script src="index.js"></script>
<script>
var search = document.location.search
if (!search && search.split('url=').length < 2) {
} else {
var url = search.split('url=')[1]
var player = new window.Jessibuca({
container: document.getElementById("container"),
decoder: "./index.js",
isResize: false,
supportDblclickFullscreen: true,
forceNoOffscreen: true,
keepScreenOn: true,
isNotMute: true,
loadingText: '加载中...',
operateBtns: {
fullscreen: true,
screenshot: true,
play: true,
audio: true,
record: true
}
});
if (player.hasLoaded()) {
player.play(url)
} else {
player.on('load', function () {
player.play(url)
})
}
player.on('fullscreen', function (e) {
window.parent.postMessage(e, '*')
})
}
</script>
</body>
</html>

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -1,30 +0,0 @@
const apps = []
const install = function (Vue) {
if (install.installed) return Promise.resolve()
else {
let contexts = require.context('.', true, /(\/.+)\/Ai[^\/]+\.vue$/)
if (contexts) {
contexts.keys().map(e => {
if (contexts(e).default) {
let mod = apps.find(a => a.name == contexts(e).default.name)
if (mod) {
mod.component = contexts(e).default
} else {
apps.push({name: contexts(e).default.name, component: contexts(e).default})
}
}
})
}
apps.map(e => {
Vue.component(e.name, e.component)
})
}
}
// 判断是否是直接引入文件
if (typeof window !== 'undefined' && window.Vue) {
install(window.Vue)
}
export default {
// 导出的对象必须具有 install才能被 Vue.use() 方法安装
install
}

View File

@@ -1,32 +0,0 @@
<template>
<section class="AiDvBackground" :style="{opacity:alpha}">
<img class="bgImage" :src="src"/>
</section>
</template>
<script>
export default {
name: "AiDvBackground",
props: {
src: String,
alpha: {default: 1}
}
}
</script>
<style lang="scss" scoped>
.AiDvBackground {
top: 0;
left: 0;
bottom: 0;
right: 0;
position: absolute;
pointer-events: none;
//z-index: -1;
.bgImage {
width: 100%;
height: 100%;
}
}
</style>

View File

@@ -1,131 +0,0 @@
<template>
<section class="AiDvDisplay">
<div class="display-top">
<img class="left" src="https://cdn.cunwuyun.cn/dvcp/dv/img/display-icon.svg">
<h2>{{ title }}</h2>
<img class="right" src="https://cdn.cunwuyun.cn/dvcp/dv/img/display-icon.svg">
</div>
<component class="background" :is="type"/>
<div class="displayPanel">
<div class="animation">
<component class="item" v-for="(op,i) in list" :key="i" :is="item" v-bind="op" :style="{transform:getPos(i)}"/>
</div>
</div>
</section>
</template>
<script>
import Display0 from './components/Display0'
import DisplayItem from "./components/displayItem";
export default {
name: 'AiDvDisplay',
components: {DisplayItem, Display0},
props: {
type: {default: 'display0'},
item: {default: 'DisplayItem'},
title: {
default: '数据统计'
},
list: {default: () => []},
},
data () {
return {
}
},
methods: {
getPos(i) {
let unit = this.list.length > 0 ? 2 * Math.PI / this.list.length : 0,
corner = this.list.length > 0 ? 360 / this.list.length : 0
return `translateZ(${250 * Math.cos(unit * i)}px) translateX(${250 * Math.sin(unit * i)}px) rotateY(${corner * i}deg)`
}
}
}
</script>
<style lang="scss" scoped>
.AiDvDisplay {
position: relative;
width: 100%;
height: 100%;
.display-top {
position: relative;
width: 840px;
background-image: url(asset/display-top.svg);
background-size: 1420px 142px;
background-position: center;
text-align: center;
overflow: hidden;
.left {
position: absolute;
left: 280px;
top: 50%;
z-index: 1;
width: 35px;
height: 22px;
background-image: url(asset/display-icon.svg);
background-size: 100% 100%;
transform: translate(0, -50%);
}
.right {
position: absolute;
right: 280px;
top: 50%;
z-index: 1;
width: 35px;
height: 22px;
background-image: url(asset/display-icon.svg);
background-size: 100% 100%;
transform: translate(0, -50%) rotate(180deg);
transform-origin: center;
}
h2 {
line-height: 75px;
margin: 0;
font-size: 36px;
color: #FFFFFF;
text-shadow: 0px 4px 20px #345FFF;
background: linear-gradient(180deg, #FFFFFF 0%, #A1E4FF 100%);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
}
}
.displayPanel {
position: absolute;
width: 160px;
height: 160px;
transform: translate(-50%, -50%);
top: 50%;
left: 50%;
z-index: 9;
.animation {
animation: rotate3D 30s infinite linear;
transform-style: preserve-3d;
&:hover {
animation-play-state: paused;
}
}
.item {
position: absolute;
}
}
}
@keyframes rotate3D {
from {
transform: rotateY(0deg);
}
to {
transform: rotateY(360deg);
}
}
</style>

View File

@@ -1,25 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="35px" height="22px" viewBox="0 0 35 22" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<title>形状结合</title>
<defs>
<path d="M1072,220 L1072,228 L1068,224 L1072,220 Z M1064,220 L1064,228 L1060,224 L1064,220 Z M1056,220 L1056,228 L1052,224 L1056,220 Z" id="path-1"></path>
<filter x="-60.0%" y="-150.0%" width="220.0%" height="400.0%" filterUnits="objectBoundingBox" id="filter-2">
<feOffset dx="0" dy="0" in="SourceAlpha" result="shadowOffsetOuter1"></feOffset>
<feGaussianBlur stdDeviation="4" in="shadowOffsetOuter1" result="shadowBlurOuter1"></feGaussianBlur>
<feColorMatrix values="0 0 0 0 1 0 0 0 0 0.760001846 0 0 0 0 0.291006098 0 0 0 1 0" type="matrix" in="shadowBlurOuter1"></feColorMatrix>
</filter>
<filter x="-50.0%" y="-125.0%" width="200.0%" height="350.0%" filterUnits="objectBoundingBox" id="filter-3">
<feGaussianBlur stdDeviation="2" in="SourceAlpha" result="shadowBlurInner1"></feGaussianBlur>
<feOffset dx="0" dy="0" in="shadowBlurInner1" result="shadowOffsetInner1"></feOffset>
<feComposite in="shadowOffsetInner1" in2="SourceAlpha" operator="arithmetic" k2="-1" k3="1" result="shadowInnerInner1"></feComposite>
<feColorMatrix values="0 0 0 0 1 0 0 0 0 0.97961238 0 0 0 0 0.9078125 0 0 0 1 0" type="matrix" in="shadowInnerInner1"></feColorMatrix>
</filter>
</defs>
<g id="钟祥大屏" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="形状结合" transform="translate(-1045.000000, -213.000000)">
<use fill="black" fill-opacity="1" filter="url(#filter-2)" xlink:href="#path-1"></use>
<use fill="#FFC143" fill-rule="evenodd" xlink:href="#path-1"></use>
<use fill="black" fill-opacity="1" filter="url(#filter-3)" xlink:href="#path-1"></use>
</g>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 2.0 KiB

View File

@@ -1,36 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="1478px" height="142px" viewBox="0 0 1478 142" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<title>编组 2</title>
<defs>
<linearGradient x1="100%" y1="50%" x2="0%" y2="50%" id="linearGradient-1">
<stop stop-color="#5A86FF" stop-opacity="0" offset="0%"></stop>
<stop stop-color="#5AACFF" offset="36.7624563%"></stop>
<stop stop-color="#7EEFFF" offset="50.0376124%"></stop>
<stop stop-color="#5AACFF" offset="62.9709649%"></stop>
<stop stop-color="#5A86FF" offset="100%"></stop>
</linearGradient>
<path d="M547,0.25 C556.749607,0.25 565.858022,4.76380868 571.818048,12.456132 L572.118303,12.85 C577.460114,19.9724141 585.628339,24.4148226 594.493503,25.038944 L594.977736,25.069194 L800,39.9977736 L594.814342,27.814741 C585.045723,27.2819072 576.001062,22.5266807 570.024678,14.8021845 L569.718303,14.4 C564.430381,7.34943641 556.184331,3.14910303 547.389942,3.00389299 L547,3 C483.876874,3 434.876874,3 400,3 C365.099096,3 316.099096,3 253,3 C244.186796,3 235.797203,7.07663928 230.404401,14.0250247 L230.118303,14.4 C224.248419,22.2265123 215.269839,27.1053605 205.52688,27.7834215 L205.022264,27.814741 L0,39.9977736 L204.858871,25.069194 C213.748674,24.5842957 221.980256,20.260414 227.424142,13.235831 L227.718303,12.85 C233.568068,5.05031402 242.693181,0.406510872 252.423056,0.253884 L253,0.25 C316.068383,0.0833333333 365.068383,3.55271368e-15 400,3.55271368e-15 C434.846161,3.55271368e-15 483.846161,0.0833333333 547,0.25 Z" id="path-2"></path>
<filter x="-45.4%" y="-147.5%" width="190.9%" height="479.4%" filterUnits="objectBoundingBox" id="filter-3">
<feMorphology radius="1" operator="dilate" in="SourceAlpha" result="shadowSpreadOuter1"></feMorphology>
<feOffset dx="0" dy="8" in="shadowSpreadOuter1" result="shadowOffsetOuter1"></feOffset>
<feGaussianBlur stdDeviation="20" in="shadowOffsetOuter1" result="shadowBlurOuter1"></feGaussianBlur>
<feColorMatrix values="0 0 0 0 0 0 0 0 0 0.254665854 0 0 0 0 0.715268342 0 0 0 1 0" type="matrix" in="shadowBlurOuter1"></feColorMatrix>
</filter>
<linearGradient x1="0%" y1="49.1111111%" x2="100%" y2="50%" id="linearGradient-4">
<stop stop-color="#0085FF" stop-opacity="0.502840909" offset="0%"></stop>
<stop stop-color="#0085FF" stop-opacity="0" offset="100%"></stop>
</linearGradient>
</defs>
<g id="钟祥大屏" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="公共招聘" transform="translate(-221.000000, -146.000000)">
<g id="编组-2" transform="translate(560.000000, 180.000000)">
<g id="路径-3备份" fill-rule="nonzero">
<use fill="black" fill-opacity="1" filter="url(#filter-3)" xlink:href="#path-2"></use>
<use fill="url(#linearGradient-1)" xlink:href="#path-2"></use>
</g>
<path d="M190.442478,46.7350415 L194.690265,47.0710935 L200,54 L195.752212,53.663948 L190.442478,46.7350415 Z M181.946903,46.0629376 L186.19469,46.3989895 L191.504425,53.3278961 L187.256637,52.9918441 L181.946903,46.0629376 Z M173.451327,45.3919885 L177.699115,45.7280404 L183.00885,52.656947 L178.761062,52.320895 L173.451327,45.3919885 Z M164.955752,44.7198845 L169.20354,45.0559365 L174.513274,51.984843 L170.265487,51.6487911 L164.955752,44.7198845 Z M156.460177,44.0489354 L160.707965,44.3849874 L166.017699,51.3138939 L161.769912,50.9778419 L156.460177,44.0489354 Z M147.964602,43.3768315 L152.212389,43.7128834 L157.522124,50.64179 L153.274336,50.305738 L147.964602,43.3768315 Z M139.469027,42.7047275 L143.716814,43.0407795 L149.026549,49.969686 L144.778761,49.6336341 L139.469027,42.7047275 Z M130.973451,42.0326236 L135.221239,42.3686756 L140.530973,49.2975821 L136.283186,48.9615301 L130.973451,42.0326236 Z M122.477876,41.3605197 L126.725664,41.6965716 L132.035398,48.6254782 L127.787611,48.2894262 L122.477876,41.3605197 Z M113.982301,40.6884157 L118.230088,41.0244677 L123.539823,47.9533742 L119.292035,47.6173223 L113.982301,40.6884157 Z M105.486726,40.0163118 L109.734513,40.3523638 L115.044248,47.2812703 L110.79646,46.9452183 L105.486726,40.0163118 Z M96.9911504,39.3442079 L101.238938,39.6802598 L106.548673,46.6091664 L102.300885,46.2731144 L96.9911504,39.3442079 Z M88.4955752,38.6721039 L92.7433628,39.0081559 L98.0530973,45.9370624 L93.8053097,45.6010105 L88.4955752,38.6721039 Z M80,38 L84.2477876,38.336052 L89.5575221,45.2649585 L85.3097345,44.9289065 L80,38 Z" id="形状" fill="url(#linearGradient-4)" transform="translate(140.000000, 46.000000) scale(-1, 1) translate(-140.000000, -46.000000) "></path>
<path d="M710.442478,46.7350415 L714.690265,47.0710935 L720,54 L715.752212,53.663948 L710.442478,46.7350415 Z M701.946903,46.0629376 L706.19469,46.3989895 L711.504425,53.3278961 L707.256637,52.9918441 L701.946903,46.0629376 Z M693.451327,45.3919885 L697.699115,45.7280404 L703.00885,52.656947 L698.761062,52.320895 L693.451327,45.3919885 Z M684.955752,44.7198845 L689.20354,45.0559365 L694.513274,51.984843 L690.265487,51.6487911 L684.955752,44.7198845 Z M676.460177,44.0489354 L680.707965,44.3849874 L686.017699,51.3138939 L681.769912,50.9778419 L676.460177,44.0489354 Z M667.964602,43.3768315 L672.212389,43.7128834 L677.522124,50.64179 L673.274336,50.305738 L667.964602,43.3768315 Z M659.469027,42.7047275 L663.716814,43.0407795 L669.026549,49.969686 L664.778761,49.6336341 L659.469027,42.7047275 Z M650.973451,42.0326236 L655.221239,42.3686756 L660.530973,49.2975821 L656.283186,48.9615301 L650.973451,42.0326236 Z M642.477876,41.3605197 L646.725664,41.6965716 L652.035398,48.6254782 L647.787611,48.2894262 L642.477876,41.3605197 Z M633.982301,40.6884157 L638.230088,41.0244677 L643.539823,47.9533742 L639.292035,47.6173223 L633.982301,40.6884157 Z M625.486726,40.0163118 L629.734513,40.3523638 L635.044248,47.2812703 L630.79646,46.9452183 L625.486726,40.0163118 Z M616.99115,39.3442079 L621.238938,39.6802598 L626.548673,46.6091664 L622.300885,46.2731144 L616.99115,39.3442079 Z M608.495575,38.6721039 L612.743363,39.0081559 L618.053097,45.9370624 L613.80531,45.6010105 L608.495575,38.6721039 Z M600,38 L604.247788,38.336052 L609.557522,45.2649585 L605.309735,44.9289065 L600,38 Z" id="形状" fill="url(#linearGradient-4)"></path>
</g>
</g>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 6.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 500 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 25 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 9.4 KiB

View File

@@ -1,34 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="128px" height="128px" viewBox="0 0 128 128" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<title>编组 3</title>
<defs>
<linearGradient x1="100%" y1="0%" x2="0%" y2="100%" id="linearGradient-1">
<stop stop-color="#00DDF2" stop-opacity="0" offset="0%"></stop>
<stop stop-color="#00E0C9" offset="100%"></stop>
</linearGradient>
<linearGradient x1="0%" y1="0%" x2="100%" y2="100%" id="linearGradient-2">
<stop stop-color="#FFE457" stop-opacity="0" offset="0%"></stop>
<stop stop-color="#FFDC2C" offset="100%"></stop>
</linearGradient>
<linearGradient x1="0%" y1="0%" x2="100%" y2="100%" id="linearGradient-3">
<stop stop-color="#FFDC2C" offset="0%"></stop>
<stop stop-color="#FFE457" stop-opacity="0" offset="100%"></stop>
</linearGradient>
<linearGradient x1="100%" y1="0%" x2="0%" y2="100%" id="linearGradient-4">
<stop stop-color="#00E0C9" offset="0%"></stop>
<stop stop-color="#00DDF2" stop-opacity="0" offset="100%"></stop>
</linearGradient>
</defs>
<g id="大屏" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="农产品推荐" transform="translate(-896.000000, -416.000000)" fill-rule="nonzero">
<g id="编组-13" transform="translate(880.000000, 400.000000)">
<g id="编组-3" transform="translate(22.000000, 22.000000)">
<path d="M122,58 C122,92.9927617 93.9164341,121.426255 59.058357,121.991426 L58,122 L58,110 C86.4316189,110 109.533832,87.1821027 109.993033,58.8599151 L110,58 L122,58 Z" id="路径" fill="url(#linearGradient-1)"></path>
<path d="M58,-6 C92.9927617,-6 121.426255,22.0835659 121.991426,56.941643 L122,58 L110,58 C110,29.5683811 87.1821027,6.46616762 58.8599151,6.00696651 L58,6 L58,-6 Z" id="路径" fill="url(#linearGradient-2)"></path>
<path d="M6,58 C6,86.4316189 28.8178973,109.533832 57.1400849,109.993033 L58,110 L58,122 C23.0072383,122 -5.42625523,93.9164341 -5.99142583,59.058357 L-6,58 L6,58 Z" id="路径" fill="url(#linearGradient-3)"></path>
<path d="M58,-6 L58,6 C29.5683811,6 6.46616762,28.8178973 6.00696651,57.1400849 L6,58 L-6,58 C-6,23.0072383 22.0835659,-5.42625523 56.941643,-5.99142583 L58,-6 Z" id="路径" fill="url(#linearGradient-4)"></path>
</g>
</g>
</g>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 2.5 KiB

View File

@@ -1,49 +0,0 @@
<template>
<div class="display0">
<div class="display0-container">
<div class="display0-content">
<img src="https://cdn.cunwuyun.cn/dvcp/dv/img/display0-left.png">
<img src="https://cdn.cunwuyun.cn/dvcp/dv/img/display0-left.png">
</div>
</div>
</div>
</template>
<script>
export default {
name: 'display0',
data () {
return {
}
}
}
</script>
<style lang="scss" scoped>
.display0 {
position: relative;
width: 840px;
height: 465px;
background: url(./../asset/display0-bg.png) no-repeat center;
background-size: cover;
.display0-content {
display: flex;
position: absolute;
top: 50%;
width: 100%;
height: 465px;
transform: translateY(-50%);
align-items: center;
justify-content: space-between;
background: url(./../asset/display0-bg.png) no-repeat center;
background-size: cover;
img:last-child {
position: relative;
transform: rotate(180deg);
}
}
}
</style>

View File

@@ -1,64 +0,0 @@
<template>
<section class="displayItem">
<span class="num" v-text="value"/>
<span v-text="label"/>
</section>
</template>
<script>
export default {
name: "displayItem",
props: {
label: {default: "标题"},
value: {default: 0},
}
}
</script>
<style lang="scss" scoped>
.displayItem {
width: 160px;
height: 160px;
color: #fff;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
font-size: 15px;
font-weight: bold;
line-height: 26px;
position: relative;
background-image: url("./../asset/displayItem-bg.svg");
background-repeat: no-repeat;
background-position: center;
&:before {
position: absolute;
top: 0;
left: 0;
bottom: 0;
right: 0;
content: " ";
background-image: url("./../asset/displayItem-bg1.svg");
background-repeat: no-repeat;
background-position: center;
animation: rotate 4s infinite linear;
background-color: transparent;
}
.num {
font-family: DIN;
font-size: 32px;
line-height: 32px;
}
}
@keyframes rotate {
0% {
transform: rotate(0);
}
100% {
transform: rotate(360deg);
}
}
</style>

View File

@@ -1,40 +0,0 @@
<template>
<section class="AiDvPanel">
<component :is="border" :title="title" v-if="border">
<template v-if="$slots.title" #title>
<slot name="title"/>
</template>
<slot/>
</component>
<slot style="width: 100%; height: 100%;" v-else></slot>
</section>
</template>
<script>
import Border1 from "./borders/border1";
import Border0 from "./borders/border0";
import Border2 from "./borders/border2";
import Border3 from "./borders/border3";
import Border4 from "./borders/border4";
export default {
name: "AiDvPanel",
components: { Border0, Border1, Border2, Border3, Border4 },
props: {
title: {default: "请传入标题"},
border: {default: "border0"}
},
mounted() {
},
}
</script>
<style lang="scss" scoped>
.AiDvPanel {
height: 100%;
* {
box-sizing: border-box;
}
}
</style>

View File

@@ -1,23 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="560px" height="280px" version="1.1" xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink">
<title>矩形备份 58</title>
<defs>
<polygon id="path-1" points="680 760 690 750 1230 750 1240 760 1240 1020 1230 1030 690 1030 680 1020"></polygon>
<filter x="-2.7%" y="-5.4%" width="105.4%" height="110.7%" filterUnits="objectBoundingBox" id="filter-2">
<feMorphology radius="10" operator="erode" in="SourceAlpha" result="shadowSpreadInner1"></feMorphology>
<feGaussianBlur stdDeviation="10" in="shadowSpreadInner1" result="shadowBlurInner1"></feGaussianBlur>
<feOffset dx="0" dy="0" in="shadowBlurInner1" result="shadowOffsetInner1"></feOffset>
<feComposite in="shadowOffsetInner1" in2="SourceAlpha" operator="arithmetic" k2="-1" k3="1"
result="shadowInnerInner1"></feComposite>
<feColorMatrix values="0 0 0 0 0.239634146 0 0 0 0 0.473717493 0 0 0 0 1 0 0 0 1 0" type="matrix"
in="shadowInnerInner1"></feColorMatrix>
</filter>
</defs>
<g id="钟祥大屏" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd" opacity="0.5">
<g id="矩形备份-58" transform="translate(-680.000000, -750.000000)">
<use fill="#0B2949" fill-rule="evenodd" xlink:href="#path-1"></use>
<use fill="black" fill-opacity="1" filter="url(#filter-2)" xlink:href="#path-1"></use>
</g>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 1.5 KiB

Some files were not shown because too many files have changed in this diff Show More