Commit e02d81d6 by jml0128

feat:项目BI

0 parents
Showing with 4865 additions and 0 deletions
{
"presets": [["env", { "modules": false }], "stage-3"],
"plugins": [
[
"component",
{
"libraryName": "element-ui",
"styleLibraryName": "theme-chalk"
}
]
]
}
root = true
[*]
charset = utf-8
indent_style = space
indent_size = 2
end_of_line = lf
insert_final_newline = true
trim_trailing_whitespace = true
\ No newline at end of file
/dist
\ No newline at end of file
/*
* @Description:
* @LastEditors: Please set LastEditors
* @Date: 2021-02-02 21:32:37
*/
module.exports = {
root: true,
env: {
node: true,
browser: true
},
extends: ['plugin:vue/essential', 'eslint:recommended', '@vue/prettier'],
plugins: ['prettier'],
parserOptions: {
parser: 'babel-eslint'
},
rules: {
'prettier/prettier': [
'error',
{
jsxBracketSameLine: false,
semi: true,
trailingComma: 'all',
singleQuote: true,
printWidth: 80,
tabWidth: 2,
endOfLine: 'auto',
trailingComma: 'none',
arrowParens: 'avoid',
htmlWhitespaceSensitivity: 'ignore'
}
],
'no-console': process.env.NODE_ENV === 'production' ? 'warn' : 'off',
'no-debugger': process.env.NODE_ENV === 'production' ? 'warn' : 'off',
quotes: [1, 'single'],
semi: [0],
'space-before-function-paren': [0, 'always']
}
};
.DS_Store
node_modules/
npm-debug.log
yarn-error.log
yarn.lock
.vscode/
# Editor directories and files
.idea
*.suo
*.ntvs*
*.njsproj
*.sln
/*
* @Description:
* @Date: 2021-02-02 21:48:47
*/
module.exports = {
jsxBracketSameLine: false,
semi: true,
trailingComma: "all",
singleQuote: true,
printWidth: 80,
tabWidth: 2,
endOfLine: "auto",
trailingComma: "none",
arrowParens: "avoid",
htmlWhitespaceSensitivity: "ignore"
};
No preview for this file type
No preview for this file type
[0301/100708.779:ERROR:directory_reader_win.cc(43)] FindFirstFile: 系统找不到指定的路径。 (0x3)
<!--
* @Description:
* @Date: 2021-03-02 20:19:43
-->
<!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,maximum-scale=1.0,user-scalable=no"
/>
<meta name="format-detection" content="telephone=no, email=no" />
<title>xrk</title>
</head>
<body>
<div id="app"></div>
<script src="https://cdn.bootcdn.net/ajax/libs/axios/0.21.1/axios.min.js"></script>
<script src="https://cdn.bootcdn.net/ajax/libs/es6-shim/0.35.6/es6-sham.min.js"></script>
<script src="https://cdn.bootcdn.net/ajax/libs/es7-shim/6.0.0/es7-shim.js"></script>
<script src="https://cdn.bootcdn.net/ajax/libs/json3/3.3.3/json3.js"></script>
<script src="https://cdn.bootcdn.net/ajax/libs/babel-polyfill/7.12.1/polyfill.min.js"></script>
<script src="https://cdn.bootcdn.net/ajax/libs/es5-shim/4.5.15/es5-sham.min.js"></script>
<script src="./dist/bundler.js"></script>
</body>
</html>
This diff could not be displayed because it is too large.
{
"name": "jml-bi",
"version": "0.1.2",
"description": "jml-bi",
"author": "xrk",
"main": "dist/bundler.js",
"keywords": [
"vue",
"xrk"
],
"repository": {
"type": "git",
"url": "http://wangjiaxing@git.jimijiayuan.cn/wangjiaxing/xrk-components.git"
},
"scripts": {
"dev": "cross-env NODE_ENV=development webpack-dev-server --open --hot",
"build": "cross-env NODE_ENV=production webpack --progress --hide-modules",
"lint": "eslint src/ --ext .js,.vue ",
"fix": "eslint --fix ./src --ext .js,.vue "
},
"dependencies": {
"echarts": "^5.1.2",
"element-ui": "^2.15.2",
"swiper": "^6.7.0",
"uuid": "^8.3.2",
"vue": "^2.5.11",
"vue-awesome-swiper": "^4.1.1",
"vue-echarts": "^6.0.0-rc.5",
"vue-photo-preview": "^1.1.3",
"vuedraggable": "^2.24.3"
},
"devDependencies": {
"@vue/cli-plugin-eslint": "~4.5.0",
"@vue/composition-api": "^1.0.0-rc.11",
"@vue/eslint-config-prettier": "^6.0.0",
"babel-core": "^6.26.0",
"babel-eslint": "^10.1.0",
"babel-loader": "^7.1.2",
"babel-plugin-component": "^1.1.1",
"babel-preset-env": "^1.6.0",
"babel-preset-stage-3": "^6.24.1",
"cross-env": "^5.2.1",
"css-loader": "^0.28.7",
"eslint": "^6.7.2",
"eslint-plugin-prettier": "^3.1.3",
"eslint-plugin-vue": "^6.2.2",
"file-loader": "^1.1.4",
"lint-staged": "^9.5.0",
"mockjs": "^1.1.0",
"node-sass": "^4.0.0",
"prettier": "^1.19.1",
"sass-loader": "^7.3.1",
"url-loader": "^1.0.1",
"vue-loader": "^13.0.5",
"vue-template-compiler": "^2.4.4",
"webpack": "^3.6.0",
"webpack-dev-server": "^2.11.5"
},
"browserslist": [
"> 1%",
"last 2 versions",
"not ie <= 8"
],
"engines": {
"node": ">= 6.0.0",
"npm": ">= 3.0.0"
},
"gitHooks": {
"pre-commit": "lint-staged"
},
"lint-staged": {
"src/*.{js,jsx,vue}": [
"npm run fix",
"git add"
]
}
}
<!--
* @Description:
* @LastEditors: Please set LastEditors
* @Date: 2021-01-28 23:29:19
-->
<template>
<div>
<XrkBi
:mobile="isMobile"
:print="isPrint"
:projectType="projectType"
></XrkBi>
</div>
<!-- <ul class="pervie">
<li name="任务记录">
<h1>任务记录</h1>
<TaskDetail :config="taskDetailOptions"></TaskDetail>
</li>
<li name="滑动组件">
<h1>滑动组件</h1>
<div style="padding:300px 0 30px 100px;width:350px;" class="block">
<input type="text" v-model="form.phone" />
<button @click="showVerify">submit</button>
<XrkSlideVerify
ref="verify"
title="12"
:options="options"
></XrkSlideVerify>
</div>
</li>
</ul> -->
</template>
<script>
import { getQueryVariable } from './packages/bi/src/chart-type/common';
export default {
name: 'App',
data() {
return {
isMobile: getQueryVariable('mobile') == 1,
isPrint: getQueryVariable('print') == 1,
projectType: getQueryVariable('projectType') || 6
};
},
components: {},
watch: {},
computed: {},
methods: {},
created() {},
beforeDestroy() {}
};
</script>
<style>
.block {
box-sizing: border-box;
border-radius: 8px;
box-shadow: 0 0 20px rgba(0, 0, 0, 0.2);
}
</style>
/*
* @Description:
* @LastEditors: Please set LastEditors
* @Date: 2021-01-28 23:29:19
*/
import Bi from '../packages/bi/index.js';
const components = [Bi];
const install = function(Vue) {
components.forEach(component => {
Vue.component(component.name, component);
});
};
if (typeof window !== 'undefined' && window.Vue) {
install(window.Vue);
}
export default {
install,
Bi
};
/*
* @Description:
* @LastEditors: jml
* @Date: 2021-01-28 23:29:19
*/
import Vue from 'vue';
import App from './App';
import Xrk from './lib/index.js';
Vue.config.productionTip = false;
Vue.use(Xrk);
/* eslint-disable no-new */
new Vue({
el: '#app',
render: h => h(App)
});
/*
* @Description:
* @Author: jml
* @Date: 2021-02-26 15:38:03
* @LastEditors: Please set LastEditors
* @LastEditTime: 2021-06-10 23:06:00
*/
import Bi from './src/main';
Bi.install = function(Vue) {
Vue.component(Bi.name, Bi);
};
export default Bi;
/*
* @Description:
* @Date: 2021-06-10 13:51:26
*/
import { dealString, dealFormatter, getInterval } from '../common';
const grid = {
containLabel: true,
left: 10,
right: 10,
bottom: 10,
top: 10
};
export const createBar = (Vue, chartData, axisData, yAxisUnit, colors = []) => {
const _axisData = dealString(axisData);
return {
animation: false,
grid: grid,
xAxis: {
type: 'category',
data: _axisData,
axisLabel: {
interval: getInterval(axisData),
color: '#A8B0BF',
fontSize: 12,
formatter: function(params) {
return dealFormatter(_axisData, params);
}
},
axisLine: {
lineStyle: {
color: '#F4F4F4'
}
},
axisTick: { show: false }
},
yAxis: {
splitNumber: 3,
axisLabel: {
formatter: '{value}' + (yAxisUnit || ''),
color: '#A8B0BF',
fontSize: 12
},
splitLine: {
lineStyle: {
color: '#F4F4F4'
}
}
},
series: chartData.map((item, index) => {
return {
type: 'bar',
barGap: 0,
data: item,
barMaxWidth: 30,
itemStyle: {
color: function(params) {
return chartData.length == 1
? colors[params.dataIndex % colors.length]
: colors[index];
}
},
label: {
show: true,
position: 'top',
color: '#2A3558',
fontSize: 12
}
};
})
};
};
export const createBarTransverse = (
Vue,
chartData,
axisData,
yAxisUnit,
colors = []
) => {
const _axisData = dealString(axisData);
return {
animation: false,
grid: grid,
xAxis: {
splitNumber: 3,
axisLabel: {
formatter: '{value}' + (yAxisUnit || ''),
margin: 8,
color: '#A8B0BF',
fontSize: 12
},
axisLine: {
lineStyle: {
color: '#F4F4F4'
}
}
},
yAxis: {
interval: getInterval(_axisData),
type: 'category',
data: _axisData,
axisLabel: {
color: '#A8B0BF',
fontSize: 12,
formatter: function(params) {
return _axisData.length > 20
? params
: dealFormatter(_axisData, params);
}
},
splitLine: {
lineStyle: {
color: '#F4F4F4'
}
},
axisLine: {
lineStyle: {
color: '#F4F4F4'
}
},
axisTick: { show: false }
},
series: chartData.map((item, index) => {
return {
type: 'bar',
barGap: 0,
data: item,
barMaxWidth: 30,
itemStyle: {
color: function(params) {
return chartData.length == 1
? colors[params.dataIndex % colors.length]
: colors[index];
}
},
label: {
show: true,
position: 'right',
color: '#2A3558',
fontSize: 12
}
};
})
};
};
export const createBarMultiple = (
Vue,
chartData,
axisData,
yAxisUnit,
colors = []
) => {
const _axisData = dealString(axisData);
return {
animation: false,
grid: grid,
calculable: true,
xAxis: {
type: 'category',
data: _axisData,
axisLabel: {
interval: getInterval(_axisData),
color: '#A8B0BF',
fontSize: 12,
formatter: function(params) {
return dealFormatter(_axisData, params);
}
},
splitLine: {
lineStyle: {
color: '#F4F4F4'
}
},
axisLine: {
lineStyle: {
color: '#F4F4F4'
}
},
axisTick: { show: false }
},
yAxis: {
splitNumber: 3,
axisLabel: {
formatter: '{value}' + (yAxisUnit || ''),
margin: 8,
color: '#A8B0BF',
fontSize: 12
},
axisLine: {
lineStyle: {
color: '#F4F4F4'
}
}
},
series: chartData.map((item, index) => {
return {
type: 'bar',
stack: '总量',
barMaxWidth: 60,
barGap: '10%',
itemStyle: {
color: colors[index]
},
label: {
show: true,
color: '#fff',
fontSize: 12
},
data: item
};
})
};
};
export const createBarMultipleTransverse = (
Vue,
chartData,
axisData,
yAxisUnit,
colors = []
) => {
const _axisData = dealString(axisData);
return {
animation: false,
grid: grid,
calculable: true,
xAxis: {
splitNumber: 3,
axisLabel: {
formatter: '{value}' + (yAxisUnit || ''),
margin: 8,
color: '#A8B0BF',
fontSize: 12
},
axisLine: {
lineStyle: {
color: '#F4F4F4'
}
}
},
yAxis: {
interval: getInterval(_axisData),
type: 'category',
data: _axisData,
axisLabel: {
color: '#A8B0BF',
fontSize: 12,
formatter: function(params) {
return dealFormatter(_axisData, params);
}
},
splitLine: {
lineStyle: {
color: '#F4F4F4'
}
},
axisLine: {
lineStyle: {
color: '#F4F4F4'
}
},
axisTick: { show: false }
},
series: chartData.map((item, index) => {
return {
type: 'bar',
stack: '总量',
barMaxWidth: 60,
barGap: '10%',
itemStyle: {
color: colors[index]
},
label: {
show: true,
color: '#fff',
fontSize: 12
},
data: item
};
})
};
};
/*
* @Description:
* @Date: 2021-06-10 15:30:08
*/
export const dealString = (axisData, maxLength = 15) => {
// return axisData;
return axisData.map(item => {
if (`${item}`.length > maxLength) {
return `${item}`.slice(0, maxLength) + '...';
} else {
return item;
}
});
};
const d = {
1: 50,
2: 28,
3: 19,
4: 20,
5: 18,
6: 14,
7: 12,
8: 10,
9: 9,
10: 8,
11: 7,
12: 6,
13: 6,
14: 5,
15: 5
};
export const axisFormatter = (params, count) => {
var newParamsName = ''; // 最终拼接成的字符串
var paramsNameNumber = params.length; // 实际标签的个数
var provideNumber = d[count] || 3; // 每行能显示的字的个数
var rowNumber = Math.ceil(paramsNameNumber / provideNumber); // 换行的话,需要显示几行,向上取整
/**
* 判断标签的个数是否大于规定的个数, 如果大于,则进行换行处理 如果不大于,即等于或小于,就返回原标签
*/
// 条件等同于rowNumber>1
if (paramsNameNumber > provideNumber) {
/** 循环每一行,p表示行 */
for (var p = 0; p < rowNumber; p++) {
var tempStr = ''; // 表示每一次截取的字符串
var start = p * provideNumber; // 开始截取的位置
var end = start + provideNumber; // 结束截取的位置
// 此处特殊处理最后一行的索引值
if (p == rowNumber - 1) {
// 最后一次不换行
tempStr = params.substring(start, paramsNameNumber);
} else {
// 每一次拼接字符串并换行
tempStr = `${params.substring(start, end)}\n`;
}
newParamsName += tempStr; // 最终拼成的字符串
}
} else {
// 将旧标签的值赋给新标签
newParamsName = params;
}
//将最终的字符串返回
return newParamsName;
};
export const getQueryVariable = variable => {
var query = window.location.search.substring(1);
var vars = query.split('&');
for (var i = 0; i < vars.length; i++) {
var pair = vars[i].split('=');
if (pair[0] == variable) {
return pair[1];
}
}
return false;
};
export const heightToPage = height => {
return Math.ceil(height / (Math.sqrt(2) * 1200));
};
export const computedPageSize = domArr => {
if (!Array.isArray(domArr)) {
return 0;
}
const prePageHeight = 1697;
let initHeight = 0;
let pageSize = 1;
for (let i = 0; i < domArr.length; ) {
if (initHeight + domArr[i] < prePageHeight) {
initHeight += domArr[i];
i++;
} else {
pageSize++;
initHeight = 0;
}
}
return pageSize;
};
export const hexColorToRgba = (hex, opacity = 1) => {
let rgbaColor = '';
const reg = /^#[\da-f]{6}$/i;
if (reg.test(hex)) {
rgbaColor = `rgba(${parseInt('0x' + hex.slice(1, 3))},${parseInt(
'0x' + hex.slice(3, 5)
)},${parseInt('0x' + hex.slice(5, 7))},${opacity})`;
}
return rgbaColor;
};
export const dealFormatter = (axisData, params) => {
return params;
// if (axisData.length > 30) {
// return params;
// }
// return axisFormatter(params, axisData.length);
};
export const getInterval = axisData => {
if (!Array.isArray(axisData)) {
return 0;
}
const { length } = axisData;
if (length < 20) {
return 0;
}
if (length < 40) {
return 1;
}
return 'auto';
};
{
"type": "FeatureCollection",
"features": [{
"id": "100000",
"type": "Feature",
"geometry": {
"type": "MultiPolygon",
"coordinates": [["@@š¦ŜiÀºƦ‘ƞò–ïè§ŞCêɕrŧůÇąĻõ™·ĉ³œ̅ó­@ċȧƒŧĥ‰Ľʉ­ƅſ“ȓÒ˦ŝE}ºƑ[ÍĜȋ AɞÏĤ¨êƺ\\Ɔ¸ĠĎvʄȀœÐ¾jNðĒĞȠzÐŘΰH¨ȔBĠ "], ["@@ƛĴÕƊÉɼģºðʀI̠ÔĚäœθؾNJŨxĚĮǂƺòƌ‚ĪŐĮXŦţƸZûЋƕƑ’ʳÛDžƝɉlÝƯֹÅŃ^Ó·śŃNjƏďíåɛGɉ™¿@ăƑŽ¥ĘWǬÏĶŁâ"], ["@@Óɖ± dƊ½ǒÂň×äı–§ĤƩ™¶hlçxĬŸĄŞkâ’ÌwøàIJaĞ‚fƠ¥Ž„Ŕdž˜®UɎÖ¢aƆúŪtŠųƠjd•ƺŠƺÅìnŽŢ¯äɝĦ]èpĄ¦´LƞĬŠ´ƤǬ˼Ēɸ¤rºǼìĴPðŀbþ¹ļD¢¹œ\\ĜÑ̔ùўÊ‰ȮŒǪűŽÀêZǚŐ¤qȂ\\`ºłĤ\\ºs|zºÿŐãѦvĪĺĺ†ĈłÈ͚FÞºĠUƢ¾ªì°`öøu®Ì¼ãÐUÞ˶¬æɒlʐߨvWʚ”ÖÕÁÜÅŵ­_«”E”ÍɪëÏ÷ÅyXo͂ĝĂÛÎf`Þ…¹ÂÿÐGĮÕĞXŪōŸMźÈƺQèĽôe|¿ƸJR¤ĘETėº¯ɀáMĺŝOéȇ¿ÖğǤǷŔ²å]­Ĥĝ‰œ¦EP}ûƥé¿İƷTėƫœŕƅ™ƱB»Đ±‚řü›]µȺrĦáŖuҞª«IJ‡πdƺÏɌ]͚œĐ™ǂZɔ¹ÚZצʥĪï|ÇĦMŔ»İĝLj‹ì¥Βœba­¯¥Ǖǚk˦ӷxūД̵nơԆ|DŽŽࡰţાíϲäʮW¬®ҌeרūȠkɬɻ̼ãɜRצɩςåȈHϚÎKdzͲOðÏȆƘ¼CϚǚ࢚˼ФԂ¤ƌžĞ̪Qʤ´ԜÃƲÀɠmǐnȺĸƠ´ǠNˠŜ‚¶ƌĆĘźʆȬμƒĞGȖƴƀj`ĢçĶȅŚē̃ĖćšYŒÀŎüôQÐÂŎŞdžŞêƖš˜oˆDƞŧǘÛۨĝȘIJžªǬ”¾äʀƪ¼Ð€Ĕǎ¨Ȕ»͠^ˮÊ˰ȎŜHĦðDĝŒ|ø˂˜ƮÐ¬ҌqjĔ²Äw°dždĞéĸdîàŎjɒĚŌ‡ŜWÈ|Ŗ‡¶îÎFC•ĊZĀēƄNĤ¶ŠłKĊOj“Ě”j´ĜYp˜{¦„ˆSĚÍ\\Tš×ªV–÷Šų¬K°ȧǵÂcḷ̌ĚǣȄɧ\\ĵœŇ‹ȣFέ̿ʏƶɷØ̫»ƽū¹Ʊő̝Ȩ§ȞʘĖiɜɶʦ}¨֪ࠜ̀ƇǬ¹ǨE˦ĥªÔDzlжøZh¤Ɛ E ĈDJ˜ì¸̚¸ƎGú´Pž¬WÄì–HsIJ¾wLVnƽCw`h`¥V”„¦U¤¸}€¾Ô[~âxh¢ªHÆÂr–iĐɘǜhÀoRzNy˜ÀDs~€bcfÌ`L–¾n‹|¾T‚°c¨È¢a‚ÈÄ[|òDȎŸÖdH„Ʈ–Àì~Ǝ†â•¦^¢ķ¶e”ÐÚEꖄɡČÅyġLû™ŇV®ŠÄ‰Ðź~ϰƂŤǒȦÒŬÂezÂvǴZ„{ĘFǜĴAΜĐȄEÔ¤ØQĄ–Ą»ΈZǺ¨ìSŊÄƸwŠn¼–c]—ܬì¯DŽ]ȘŏńzƺŷɄeeOĨS’Œfm Ɋ’̎ēz©þ†ÐÙÊmgŸÇsJ¥ƔˆŊśÎÔsÁtÃßGo—À­ xňË_½ä@êíuáĠ[ġ¥g“ɊדûÏWXáǠDZÌsNͽƎÁ§č՛AēeL³àydl›¦ĘVçŁpśdžĽĺſʃQíÜçÛġԏsĕ¬—Dz¡SíċġHµ ¡EŃļƒrĉŘóƢFƺ«øxÊk†”ƈdƬÌr|©ÛńRŀƒøďŊœŀ›ˆàŀU²ŕƀB‚Q£Ď}L¹Îk@©ĈuǰųǨ”Ú§ƈnTËÇéƟÊcfčŤ^gēĊĕƯǏx³ǔķÐċJā‚wİ_ĸ˜Ȁ^ôWr­°oú¬Ɏ‘~”ȰCĐ´Ƕ£’fNÎèâ_ÐŮeʆNJǘuȔ\\¤ÒĨA¢Ê͠æÔ ŬGƠ”ƦYê‹ŊàƆXvkmŸͥœ@čŅĻA“¶çÎqC½Ĉ»NŸăëK™ďÍQ“Ʌ›řęgßÔÇOÝáWáħ£˯ā¡ÑķĎÛ寰WKɱ_d_}}vyŸõu¬ïÏҽ@gÏ¿rýб…Cd‰µ—°MFYxw¿CG£ǧ«»ó¡Ɵš¿BÇƻğëšܭNJĭôµ}‰čÓpg±˜ƒǫŋRwŕnéÑƕfSŸŋ‹®ÍšD Ûǖ֍Ÿ]gr¡µŷzįm³~S«“„›þeo³l™•{iē¥yZ÷īŖõġMRÇģZ“mÃ|¡™ģTɟij“Â`À–çm‰‘FK¥ÚíÁbXš³ÌQґHof{‰]e€pt·GŋĜTNJŋB…h–¬ƩDoˆ±enq©G`™wGçǑ‚“K‰‹F‚“›uNĝw‡őXtW·Ýďæßa}xV•—XR‰ãQ`­©GŒM»­”ďϝd‡©ÑW_ÏǷr¡…é\\ƒɹ~ɍuØ©Bš¤ÝĤ½¢Å_Á¿•LŅñuT\\rÅIs®y}’ywdS™DZtCmûvašʋJr€Ư‚⦳P‡rbbÍzš€wBG’ĭ€T†Ák‘»ƒlY­ċ²z“Ç£—^§»d¯íŻŽ£ćGŵDžƍÓ]í“M^o•£Ã]ªUóo½~ŕ‘|ŋݘ¥ċh“¹·CÉ­Dřlg‡ȵë[‘’}ģS}xƃği©ĝ‡ɝǡF꼵áƣ©‚Hžĕoƫ€Ňqƒr³Ãg[„šÃS–ő_†±ÅFC¥Pq{‚ñg—¿įX…•ƝıĉNj•ûěʼn³F‘¦oĵ—hŸÕP{¯~TÍl¸ÓßYÏàs{ÃVU™™eĎwk±ʼnVÓ½ŽJūĉ»Jm°fϑdF~ˆ€ĀeĖ€O˜² Ĉ‰żĀiÂd^~ăÔHˆ¦\\§|ĄVez¤NP ǹӗR™ÆƇP[¦´Âghwm}ÐШźhI|žVVŽ—Ž|p[¦À¶èNä¶ÒCÀ¢^h—PfvƾĪ×òúNZÞÒKxpw|ÊEZŽI¨®œİFÜçmĩ‚WĪñt‘ÞʼnËÝ^³uL‚±|Əlĉ¥čn§ßÅc‘˜B× CNƒǟ‹_ñŧı¯Y]ăٟ™Ľѷť‹³ÃAR‹‡ZRlʑýSëÍDěïÿȧ¢ÙġƒěŗŷęŸUªhJˆƁ™ƅn³gF‹³HàŋÅÃƉÀKšť`ċŮÁõYėé÷`ٚ_Ïǵ—R§òoEÅąLœŐœƜVµąłíļĐ·ũ̈«ªdÎɜnb²ĦhņBĖ›žįĦåXćì@L¯´ywƕCéõė ƿäćú y±¨Mf~C¿`€à_ŒÿƌfQnð³ƬˆŲŎ¥ĠʦĘĒØ‰¼Â†±ŴPè¸ŔLƔÜƺ_T‘üÃĤBBċȉöA´fa„˜M¨{«Múīô‰Ö°ʊkŲÆM|²@¤u•ƒ¤Û´Œä«̰\\„}ēƒ‹ÅM•¼Ã­]NągoõľH‰yGă{{çrnÓE‰‹ƕZGª¹Fj¢ïW…uøC̍ƃhÛ­–Ň\\bÅxì²ƝýN‰īCȽĿǃšŖÕy\\‡¹kx‡Ã£Č×G¿Ï¤ÁçFQ¡„KtŵΥëÚź—Љ«ėn½ĉŀ—›Á¼zK›¶†G•­Y§Ëƒ@–´śÇµƕñžx———Z¯u™Œ…Ï•˜ï{éƵP—™_K«™pÍÁwƏčaE›U”£uݘāɌŁFŴu»¹İ×ȖħŴw̌ŵ²ǹǠ͛hĭłƕrçü±hǥ®jű¢KOķÅ}`åÂK­_Юƫ²ʯÊ^H{ǸÃĆēĤȍzȥݵċF͓ŸI©Õ͈ǫȌȥ¦ŋEӏ“†ıŪěřÀåżȟLƏ—ŽąđGǛģLjƧĎOłčȶʋÀBŖÕªˆŠÁŐTőŕåqûõi¨hÜ·ƒñt»¹ýv_[«²Kƒ{L¯‰SªƒGѵ¸•gÑpY´«•ęœƘʑcoċ\\œ­gěŧ«Āý¶ŧ·Å”KsËɏc¢Ù\\ĭƛëbf¹­ģSƒĜkáƉÔ­ĈZ~﵉fzʼnfåÂȝǷÕĕÊĉ{ğč±uƁí]Í»ęX\\­•Ip™¡éĥZE‹ãoP…þy—¸k³—†¡ƽŸ¿å³BRضˆœWlâþäą`“]aģc— ĹGµ¶H™åՌ‰¾xĨ‡ôȉðX«½đCIŇOK³Á‰Äţ¬OAwã»aLʼn‡ËĥW[“ÂGI—ÂNrį~IМ‘êĘÎG§Ė¥Ý™F{ WK}ùaH‘āÖ{OoužHEÅǍqĬuë±KEò£‰UplÀ÷tMāe£bYÂý¡a±Öcp©®^ö±q…ÇGjųªKy¬ŏ–®¤ÉEŸ–ĀåA¬ˆV{Xģ‰Đƒpě…¼³Ăp·¤ƒīyÚ¡ŅLĻŗž§qlŸÀh¬µ»åÇGnùčÙmÆß–ėu›ĕeûҍiÁŧSW¥˜QŠûŗ½ùěYÓ±]ÓđīkWó«íěCŸŇͱ™‘čvĭõĉ‚ę÷N¹³ĉoTĵËçŁYلǝŕ¹tȏģ·Ĕĭ|đėÊK™½R‘ē ó]™ĀęAx–ŸNk©|ām‡¡diď×YïYWªʼnOeÚtĐ«zđ¹T…ā‡úE™áÎÁąÏŸHcòßÎſ¿Çdğ·ùT×Çūʄ¡XgWÀLJƟψOj YÇ÷Sğ³kzőȝğ§õ¡VÙæÅöM̳¹pÁaËýý©D©Ü“JŹƕģGą¤{Ùū…ǘO²«BƱéA—Ò‰Ƈ׫BhlmtÃPµy‹ÓɉUīí}†€GBȅ‰ŹãĻFŷŽǩoo¿ē‹±ß}ŽwƋtƺ—CőØEîǻīƓʑã͘ƍ“DĈ±ÌŒÜӔĨ£LóɢVȞĆĖMĸĤfˆÜǗjđĆ»ýͥãğ¶ĞØO¤Ǜn³Žő}‹¦…·z€YŠwa™–šőűMę§ZĨ훘Û]é’ÛUćİȹ¯…dƒy¹TcÂĕ½A´µê÷wĻþÙ`K€¦˜…¢ÍeœĥR¡ˆã…‚Ĉu¼dl‰t‚†U¶¶ď\\zœ}ưŬ–{ÚfKš¶Ð_„ÂÒ¿C©Ö•TmuŸ¼ãl‰›ŇÕVåĤĵfÝYYįk‘ÒīØſNQĠ³r³øÓrŸÖͳgÍſGįÅ_—±he¡ÅM²Ɠ綾ßīZgmk„ǭƁć¦UĔťƒ×ëǟ…e˭ʔħǛāĘPªij¶‘Ņăw§n‰ď£S»şŒÍļɉŀ‰}ÛÞ»å£_ˆŸıęÏZ—÷`…[„ùx½}ÑRH‘YėĺďsÍn‘™é½Ya¤Ïm¬ĝg•ĂsA•ØÅwď‚õ¤q}—«Dx¿}UũlŸê™@•HÅ­F‰¨ÇoJ´Ónȯ×âpÒŌ“Ø Tˆêa²ËX€€c̋lLìģËŁkŻƑŷÉăP¹æƧÝ¡¦}•veèÆ´UvÅ~§‡½˜“Ġ²Ŵwæč\\Dƒ}O÷š£[ŽăŒá[™‚į‰ŷvŸœRsdĒƄwžŎĒo~t¾ÍŶÒtD¦Ú„iôö‰€z«Ųƭ¸Û±¯€ÿm·zR¦Ɵ`ªŊÃh¢rOԍ´£Ym¼èêf¯ŪĽn„†AĦw\\ưĆ ¦g–ʉË£¢ι‰ǫßK‘ÙIįóVesb‘aĕ ǠƺpªqŒ‚ďŒE˜®tŸôřk˜ȌwêżĔÂe‚nËÂQƞ´’¼ŲƝÎô¶R„ä’Q^Øu¬°š_Èôc´¹ò¨P΢hlϦ´Ħ“¬oêDŽŲÚr^¯°’^º{ªBHŒ²Ö¤ɦ§Țv€qĸ„ ­viļ€ndĜ­ĆfŒ“xÝgyށqóžSᝑ³X_ĞçêtrmÚ§z„¦c¦¥jnŞi˜¯´ÓH@ÂċĂჷÌ_þ·–¹_wzË£Z­¹|ŕWM‰“|O¥ÃWTÕ­ùÔQ†¥‡¥Rã»Ge†ŸeƃīQ•}J[ғK…¬Ə|o’ėjġĠÑN¡ð¯EBčnkòəėªƒ²œm˽ŏġǝʅįĭạ̃ūȹ]ΓͧŹəăЕ·ƭˆęgſ¶ҍć`ĘąŌJޚä¤rÅň¥ÖƝ^ęuůÞiĊÄÀ\\Æs¦ÓRäšřÌkÄŷ¶½÷ùCMÝۛĥ°G¬ĩ`£Øą‚ğ¯ß”§aëbéüÑOčœk£ÍI ïCċÀÕÕĻSŧʼnïŽŗãWÑăû‚··‘Q—òı}¯ã‰I•éÕÂZ¨īès¶ZÈsŽæĔŠƦ›Ú@îá¾ó@‰˜ÙwU±ÉT廣TđŸWxĉWù׌¯cĩv‡Œėŧ³BM|¹k‰ªħ—¥TzNYnݍßpęrñĠĉRÑÈěVVе‚õ‡«Œ¯ůĉ¥áºaeõ|uĐh`Ü³ç@šƋĿa©|z²Ý¼ŸĴ貋ŸƒIƒû›I ā€óK¥}rÝ_Á´éMaňæêSĈ½Ž½KÙóĿeƃÆBŽ·¬ƃV×ĴƳ˜lŒµ`bԑ¨ˆÐÓ@s¬ƿ‚ûws¡åQÑßÁ`ŋĴ{Ī“T•ÚÅTSÄį¤Ç[ǾµMW¢ĭiÕØ¿@ŠÂ…pÕ]j†éò¿OƇĆƇp€êĉâlØw–ěsˆǩ‚ĵ¸c…bU¹ř¨^“ƒ±ze…ė·¥Ó@~¯‹éīB™Š\\”āƚǗÀƷŘóQīÈáP•œǥ@ŗĸIæÅ„hnszÁCËìñšÏ·ąĚÝUm®ó­Z±đ[‰Âÿiñ¬‰Òj°ŁŤ_uµ^‘°ŒìÇÊĶĒ¡Æ‡MğźİĨƥôRŽāð©[wâ䥩Ô\\°ÝĄ̄Ƣ’ăk™néǀůŠ˜ĆK„ĒĬœ¶è‰âz¨u¦¥L~ƄýÎIƖߔµĔƱĐċņbÎՂĄæ_ƞZRÖíŽJ²öLĸҜcºƖÎ\\ñºÛqY–Ѩ`x¥’ù^•}ƒÌđYªƅ”Aйn~Ꝛf¤áÀz„gŠÇDIԝ´Aňńňĕuĩt[{ù°ŁÏ•|Soċxţ[õÔĥkŋÞŭZ˺óYËüċrw €ÞkrťË¿XGǣ@Dü·Ē÷Aê[Ää€I®BÕИÞ_¢āĠpŠÛÄȉĖġDKÕK‡ÄNô‡ŠfœƫVó¼dz—H‘‹QµâFšù­Âœ³¦{Y‹Â¢ĚÜO „€{Ö¦ÞͨJÜÄƨ€lŽU˧ªÍE˨¡ĐĬĬùÎRƠŸHÕŔ_ƪàÒKäȇĬə²ȕnáûl—÷eǛò•Ğ\\ªÑò˜Üìc\\üqˆÕ[ēdžċªbØ­Œø|€¶ȴZdÆÂšońéŒGšŠǚnìÈƲ‚ہȖưòTxÊǪMīИÖŲÃɎO̚ǰއRěò—¿ġ~åŊœú‰¬ô¸qŽ’Ę[Ĕ¶ÂćnÒPĒÜvúĀÊbÖ{Äî¸~Ŕünp¤ŀ¤ĄYÒ©ÊfºmԈȈ¡DŽ~¤„s²‚”ʘچžȂVƼîèW²æIJXŔþɔÖĚêϜêĮŢɨJ€˜¯ÎrDDšĤ€`€Q¾§~wâJÂ˜ñÈOú¤p¨ŪŊMǎÀW|ų ¿¾ɄĦƖAiƒ÷fØĶK¢ȝ˔"]],
"encodeOffsets": [[[112750, 20508]], [[123335, 22980]], [[82455, 44869]]]
},
"properties": {
"cp": [116.3683244, 39.915085],
"name": "中华人民共和国",
"childNum": 3
}
}],
"UTF8Encoding": true
}
\ No newline at end of file
/*
* @Description:
* @Date: 2021-06-10 13:51:26
*/
import { dealString, dealFormatter, getInterval } from '../common';
// const getInfo = Vue => {
// const { isMobile, isPrint, axisData } = Vue;
// return {
// isMobile: isMobile && !isPrint,
// isPrint,
// fontSize: isMobile && !isPrint ? 10 : 14,
// lineWidth: isMobile && !isPrint ? 2 : axisData.length > 30 ? 3 : 5,
// symbolSize: isMobile && !isPrint ? 7 : axisData.length > 30 ? 7 : 10
// };
// };
const grid = {
containLabel: true,
left: 0,
right: 10,
top: 10,
bottom: 0
};
export const createLine = (
Vue,
chartData,
axisData,
yAxisUnit,
colors = []
) => {
const isSingle = chartData.length == 1;
const _axisData = dealString(axisData);
return {
animation: false,
grid: grid,
xAxis: {
interval: getInterval(axisData),
type: 'category',
data: _axisData,
axisLabel: {
color: '#A8B0BF',
fontSize: 12,
formatter: function(params) {
return dealFormatter(_axisData, params);
}
},
axisLine: {
lineStyle: {
color: '#F4F4F4'
}
},
axisTick: { show: false }
},
yAxis: {
splitNumber: 3,
axisLabel: {
formatter: '{value}' + (yAxisUnit || ''),
color: '#A8B0BF',
fontSize: 12
},
splitLine: {
lineStyle: {
color: '#F4F4F4'
}
}
},
series: chartData.map((item, index) => {
return {
type: 'line',
data: item,
barWidth: '28px',
symbolSize: 7,
lineStyle: {
color: isSingle
? colors.length == 1
? colors[0]
: '#D8E5F2'
: colors[index],
width: 3
// shadowColor: hexColorToRgba(colors[index], 0.6),
// shadowBlur: isSingle ? 0 : 10
},
itemStyle: {
color: function(params) {
return isSingle
? colors[params.dataIndex % colors.length]
: colors[index];
}
},
label: {
show: true,
position: 'top',
color: isSingle ? '#2A3558' : colors[index],
fontSize: 12
},
emphasis: {
lineStyle: {
color: isSingle
? colors.length == 1
? colors[0]
: '#D8E5F2'
: colors[index],
width: 3
}
}
};
})
};
};
export const createLineSmooth = (
Vue,
chartData,
axisData,
yAxisUnit,
colors = []
) => {
const isSingle = chartData.length == 1;
const _axisData = dealString(axisData);
return {
animation: false,
grid: grid,
xAxis: {
interval: getInterval(_axisData),
type: 'category',
data: _axisData,
axisLabel: {
color: '#A8B0BF',
fontSize: 12,
formatter: function(params) {
return dealFormatter(_axisData, params);
}
},
axisLine: {
lineStyle: {
color: '#F4F4F4'
}
},
axisTick: { show: false }
},
yAxis: {
splitNumber: 3,
axisLabel: {
formatter: '{value}' + (yAxisUnit || ''),
color: '#A8B0BF',
fontSize: 12
},
splitLine: {
lineStyle: {
color: '#F4F4F4'
}
}
},
series: chartData.map((item, index) => {
return {
type: 'line',
data: item,
smooth: true,
symbolSize: 7,
lineStyle: {
color: isSingle
? colors.length == 1
? colors[0]
: '#D8E5F2'
: colors[index],
width: 3
// shadowColor: hexColorToRgba(colors[index], 0.6),
// shadowBlur: isSingle ? 0 : 10
},
itemStyle: {
color: function(params) {
return isSingle
? colors[params.dataIndex % colors.length]
: colors[index];
}
},
label: {
show: true,
position: 'top',
color: isSingle ? '#2A3558' : colors[index],
fontSize: 12
},
emphasis: {
lineStyle: {
color: isSingle
? colors.length == 1
? colors[0]
: '#D8E5F2'
: colors[index],
width: 3
}
}
};
})
};
};
/*
* @Description:
* @Date: 2021-06-20 01:16:17
*/
export const createMap = () => {
return {
visualMap: {
borderColor: '#fff',
min: 0,
max: 1000,
left: 26,
bottom: 40,
pieces: [
{
gt: 100,
label: '100以上',
color: '#6C71FF'
},
{
gte: 50,
lte: 100,
label: '51-100',
color: '#34CE9C'
},
{
gte: 11,
lt: 50,
label: '11-50',
color: '#3985FF'
},
{
gt: 0,
lt: 10,
label: '0-10',
color: '#00BAFF'
}
]
},
series: [
{
type: 'map',
mapType: 'china',
map: 'china',
label: {
show: true,
color: '#323235',
fontSize: 12
},
silent: true,
itemStyle: {
areaColor: 'rgba(0,0,0,0)',
borderColor: '#4C6286',
borderWidth: 1
},
top: 36,
left: 0,
data: [
{
name: '北京',
value: 54
},
{
name: '天津',
value: 13
},
{
name: '上海',
value: 40
},
{
name: '重庆',
value: 75
},
{
name: '河北',
value: 13
},
{
name: '河南',
value: 83
},
{
name: '云南',
value: 11
},
{
name: '辽宁',
value: 19
},
{
name: '黑龙江',
value: 15
},
{
name: '湖南',
value: 69
},
{
name: '安徽',
value: 60
},
{
name: '山东',
value: 39
},
{
name: '新疆',
value: 4
},
{
name: '江苏',
value: 31
},
{
name: '浙江',
value: 104
},
{
name: '江西',
value: 36
},
{
name: '湖北',
value: 1052
},
{
name: '广西',
value: 33
},
{
name: '甘肃',
value: 7
}
]
}
]
};
};
/*
* @Description:
* @Date: 2021-06-10 13:51:26
*/
const getInfo = Vue => {
const { isMobile, isPrint } = Vue;
return {
isMobile: isMobile && !isPrint,
isPrint,
fontSize: isMobile && !isPrint ? 10 : 12,
formatter: isMobile && !isPrint ? '{b}\n{d}%' : '{b}\n数量{c},占比{d}%'
};
};
export const createRing = (
Vue,
chartData,
axisData,
yAxisUnit,
colors = [],
legend = []
) => {
const { fontSize, formatter, isMobile, isPrint } = getInfo(Vue);
const isSingle = chartData.length == 1;
return {
animation: false,
grid: {
containLabel: true,
left: 20,
right: 0,
bottom: '5%'
},
title: isMobile
? {
borderColor: '#fff',
text: 10000 + '人',
textStyle: {
color: '#2A3558',
fontSize: isPrint ? 45 : 15
},
subtext: '答题人数',
subtextStyle: {
color: '#6F7A91',
fontSize: isPrint ? 30 : 10
},
itemGap: isPrint ? 12 : 4,
left: 'center',
top: isPrint ? '45%' : '42%'
}
: {
borderColor: '#fff'
},
series: chartData.map((item, index) => {
const maxWidth = 80;
const getRadius = index => {
if (isSingle) {
return isMobile ? ['35%', '55%'] : ['70%', '55%'];
}
const width = 15;
const gap = width * 1.5;
return [
`${maxWidth - gap * index}%`,
`${maxWidth - gap * index - width}%`
];
};
const _item = item.map((cItem, cIndex) => {
return {
name: isSingle
? `${axisData[cIndex]}`
: `${axisData[cIndex]}-${legend[index]}`,
value: cItem
};
});
return {
type: 'pie',
z: index,
zlevel: index,
center: ['50%', '50%'],
radius: getRadius(index),
clockwise: true,
avoidLabelOverlap: true,
hoverOffset: 15,
itemStyle: {
color: function(params) {
return colors[params.dataIndex % colors.length];
}
},
label: {
show: true,
position: 'outside',
fontSize: fontSize,
color: '#2A3558',
formatter: formatter
},
labelLine: {
length: isSingle ? (isMobile ? 10 : 40) : maxWidth + 30 * index,
length2: isSingle ? (isMobile ? 10 : 40) : 50 + 10 * index,
lineStyle: {
color: '#6E6E6E',
width: 1
}
},
data: _item
};
})
};
};
export const createPie = (
Vue,
chartData,
axisData,
yAxisUnit,
colors = [],
legend = []
) => {
const { fontSize, formatter, isMobile } = getInfo(Vue);
const isSingle = chartData.length == 1;
return {
animation: false,
grid: {
containLabel: true,
left: 20,
right: 0,
bottom: '5%'
},
series: [
{
type: 'pie',
center: ['50%', '50%'],
radius: isMobile ? '60%' : '70%',
hoverOffset: 15,
itemStyle: {
color: function(params) {
return colors[params.dataIndex % colors.length];
}
},
label: {
show: true,
position: 'outside',
fontSize: fontSize,
color: '#2A3558',
formatter: formatter
},
labelLine: {
length: isMobile ? 10 : 30,
length2: isMobile ? 10 : 30,
lineStyle: {
color: '#6E6E6E',
width: 1
}
},
data: chartData.reduce((pre, cur, index) => {
const _item = cur.map((cItem, cIndex) => {
return {
name: isSingle
? `${axisData[cIndex]}`
: `${axisData[cIndex]}-${legend[index]}`,
value: cItem
};
});
pre.push(..._item);
return pre;
}, [])
}
]
};
};
/*
* @Description:
* @Date: 2021-06-10 13:56:53
*/
import {
createBar,
createBarTransverse,
createBarMultiple,
createBarMultipleTransverse
} from './bar/createBar';
import { createLine, createLineSmooth } from './line/createLine';
import { createPie, createRing } from './pie/createPie';
import { createMap } from './map/createMap';
export default {
// 柱状
1: {
name: 'bar',
cnName: '柱状图',
icon: 'http://cdn.yxvzb.com/WEB/SaaS/images/bi/svg/zhuzhuang2.svg',
sort: 2,
create: createBar
},
// 柱状-横向
2: {
name: 'bar-transverse',
cnName: '柱状图',
icon: 'http://cdn.yxvzb.com/WEB/SaaS/images/bi/svg/zhuzhuang3.svg',
sort: 3,
create: createBarTransverse
},
// 柱状-多重
3: {
name: 'bar-multiple',
cnName: '柱状图',
icon: 'http://cdn.yxvzb.com/WEB/SaaS/images/bi/svg/zhuzhuang1.svg',
sort: 1,
create: createBarMultiple
},
// 柱状-多重-横向
4: {
name: 'bar-multiple-transverse',
cnName: '柱状图',
icon: 'http://cdn.yxvzb.com/WEB/SaaS/images/bi/svg/zhuzhuang4.svg',
sort: 4,
create: createBarMultipleTransverse
},
// 折线
5: {
name: 'line',
cnName: '折线图',
sort: 1,
icon: 'http://cdn.yxvzb.com/WEB/SaaS/images/bi/svg/zhexian2.svg',
create: createLineSmooth
},
// 折线-光滑
6: {
name: 'line-smooth',
cnName: '折线图',
sort: 2,
icon: 'http://cdn.yxvzb.com/WEB/SaaS/images/bi/svg/zhexian1.svg',
create: createLine
},
// 折线-光滑
// 7: {
// name: 'line-smooth',
// cnName: '折线图',
// sort: 3,
// icon: require('http://cdn.yxvzb.com/WEB/SaaS/images/bi/svg/zhexian1.svg')
// },
// // 折线-光滑-多重
// 8: {
// name: 'line-smooth-multiple',
// cnName: '折线图',
// sort: 4,
// icon: require('http://cdn.yxvzb.com/WEB/SaaS/images/bi/svg/zhexian2.svg')
// },
// 圆环
9: {
name: 'ring',
cnName: '饼图',
sort: 1,
icon: 'http://cdn.yxvzb.com/WEB/SaaS/images/bi/svg/bingtu2.svg',
create: createRing
},
// 饼图
10: {
name: 'circle',
cnName: '饼图',
sort: 2,
icon: 'http://cdn.yxvzb.com/WEB/SaaS/images/bi/svg/bingtu1.svg',
create: createPie
},
// 表格
11: {
name: 'table',
cnName: '表格',
sort: 1,
icon: 'http://cdn.yxvzb.com/WEB/SaaS/images/bi/svg/biaoge.svg'
},
// 男女ICON
12: {
name: 'icon',
cnName: '初始化',
sort: 1,
icon: 'http://cdn.yxvzb.com/WEB/SaaS/images/bi/svg/boyicon.svg?v=1'
},
// 地图
13: {
name: 'map',
cnName: '地图',
sort: 1,
icon: '',
create: createMap
}
};
<!--
* @Description:
* @Date: 2021-06-19 17:10:30
-->
<template>
<div class="bi-blank" :style="customStle"></div>
</template>
<script>
import mixin from '../mixin/index';
export default {
name: 'bi-blank',
mixins: [mixin],
props: {
height: {
type: [String, Number],
default: 0
},
usePrint: Boolean
},
computed: {
customStle() {
if (this.isPrint && !this.usePrint) {
return { height: '0px' };
}
if (this.isMobile) {
return { height: `${this.height / 2}px` };
}
return { height: `${this.height}px` };
}
}
};
</script>
<!--
* @Description:
* @Date: 2021-06-15 19:55:05
-->
<!--
* @Description:
* @Date: 2020-07-16 18:27:04
-->
<template>
<div class="ebox" :id="uuid"></div>
</template>
<script>
// import { v4 } from 'uuid';
/**
* echart 配置
*/
import { use, init, registerMap } from 'echarts/core';
import { SVGRenderer } from 'echarts/renderers';
import { PieChart, BarChart, LineChart, MapChart } from 'echarts/charts';
import china from '../chart-type/json/china.json';
// import chinaMapOutline from '../chart-type/json/chinaMapOutline.json';
import {
TitleComponent,
TooltipComponent,
LegendComponent,
GridComponent,
DatasetComponent,
PolarComponent,
VisualMapComponent
} from 'echarts/components';
use([
SVGRenderer,
BarChart,
PieChart,
LineChart,
MapChart,
TitleComponent,
TooltipComponent,
LegendComponent,
GridComponent,
DatasetComponent,
PolarComponent,
VisualMapComponent
]);
export default {
props: {
option: {
type: Object,
default: () => ({})
},
type: [Number, String],
autoresize: Boolean
},
data() {
return {
uuid: `${parseInt(Math.random())}-${new Date().getTime()}`,
myChart: null,
height: 0
};
},
watch: {
option: {
deep: true,
immediate: true,
handler(v) {
if (v) {
this.$nextTick(() => {
this.init();
});
}
}
}
},
methods: {
init() {
if (!this.myChart) {
if (this.type === 13) {
console.log(china);
registerMap('china', china);
// registerMap('chinaMapOutline', chinaMapOutline);
}
this.myChart = init(document.getElementById(this.uuid));
}
this.myChart.setOption(this.option);
}
},
mounted() {},
created() {}
};
</script>
<style scoped lang="scss">
.ebox {
display: flex;
max-width: '920px';
max-height: '450px';
width: '100%';
& + .ebox {
margin-top: 80px;
}
}
</style>
<!--
* @Description: file content
* @Author: jml
* @Date: 2021-03-24 10:22:27
* @LastEditors: Please set LastEditors
* @LastEditTime: 2021-06-20 00:46:51
-->
<template>
<div style="position:relative;" class="bi-chart-block">
<slot></slot>
<slot name="top"></slot>
<BiChartTitle
v-if="title.show"
v-bind="{
...title,
colors: chart.colors,
chartType: chart.type,
disableTypes: chart.disableTypes
}"
@change-colors="changeChartColors"
@change-chartkey="changeChartType"
@change-delete="deleteChart"
:showGuide="showGuide"
></BiChartTitle>
<BiChartChoiceMinxinToggleAxis
v-if="(chart.axis || []).every(item => item.names.length > 0)"
:axis="chart.axis"
@toggle-axis="toggleAxis"
></BiChartChoiceMinxinToggleAxis>
<template v-if="chart.show">
<BiTable
v-if="chart.type == 11"
v-bind="{
...chart,
title: title.name
}"
></BiTable>
<BiSexIcon v-else-if="chart.type == 12" v-bind="chart"></BiSexIcon>
<BiChart :showGuide="showGuide" v-else v-bind="chart"></BiChart>
</template>
<BiChartLegend
v-if="legend.show"
v-bind="{ ...legend, colors: chart.colors }"
></BiChartLegend>
<BiChartDesc
v-if="desc.show"
v-bind="desc"
@change-status="changeStatus('desc', '描述')"
@change-text="changeText"
></BiChartDesc>
<BiChartChoiceMinxinAnalysis
v-if="analysis.show"
v-bind="analysis"
@change-status="changeStatus('analysis', '卡方分析结果')"
></BiChartChoiceMinxinAnalysis>
<BiChartDesc
v-if="analysisDesc.show"
v-bind="analysisDesc"
@change-status="changeStatus('analysisDesc', '智能分析')"
></BiChartDesc>
<slot name="bottom"></slot>
</div>
</template>
<script>
import BiChartTitle from './chart-title.vue';
import BiChart from './chart.vue';
import BiTable from './table.vue';
import BiSexIcon from './sex-icon.vue';
import BiChartLegend from './chart-legend.vue';
import BiChartDesc from './chart-desc.vue';
import BiChartChoiceMinxinToggleAxis from './chart-choice-mixin-toggle-axis.vue';
import BiChartChoiceMinxinAnalysis from './chart-choice-mixin-analysis.vue';
export default {
name: 'bi-chart-block',
components: {
BiChartTitle,
BiChart,
BiTable,
BiSexIcon,
BiChartDesc,
BiChartLegend,
BiChartChoiceMinxinToggleAxis,
BiChartChoiceMinxinAnalysis
},
props: {
showGuide: Boolean,
chartConfig: {
type: Object,
default: () => ({})
}
},
computed: {
analysis() {
return this.chartConfig.analysis || {};
},
analysisDesc() {
return this.chartConfig.analysisDesc || {};
},
chart() {
return this.chartConfig.chart || {};
},
desc() {
return this.chartConfig.desc || {};
},
legend() {
return this.chartConfig.legend || {};
},
title() {
return this.chartConfig.title || {};
}
},
methods: {
changeChartColors(colors) {
this.chartConfig.chart['colors'] = colors;
console.log(`${this.title.name}-图表-颜色`, colors);
},
deleteChart() {
this.chartConfig['isDelete'] = 1;
console.log(`${this.title.name}-图表-删除`);
},
changeChartType(chartKey) {
this.chartConfig.chart['type'] = chartKey;
console.log(`${this.title.name}-图表-格式`, chartKey);
},
changeStatus(keyName, typeName) {
// 设置附加文字是否显示
this.chartConfig[keyName]['setShow'] = !this.chartConfig[keyName][
'setShow'
];
console.log(`${this.title.name}-${typeName}-是否显示`);
},
changeText(text) {
// 修改附加文字的内容
console.log(`${this.title.name}-用户自定义描述`, text);
},
toggleAxis() {
// 交换X轴与Y轴
const { data, axis } = this.chart;
this.chartConfig.chart['axis'] = axis.reverse();
this.chartConfig.chart['data'] = data[0].reduce((pre, cur, index) => {
pre.push(
data.reduce((cPre, cCur) => {
cPre.push(cCur[index]);
return cPre;
}, [])
);
return pre;
}, []);
console.log(`${this.title.name}-交换X轴与Y轴`);
}
}
};
</script>
<style lang="scss" scoped>
.bi-chart-block {
& > div {
page-break-inside: avoid;
}
}
</style>
<!--
* @Description:
* @Date: 2021-06-10 10:34:38
-->
<template>
<div>
<BiBlank height="17" :usePrint="true"></BiBlank>
<div class="bi-choice-mixin-analysis" :class="{ hide: !setShow }">
<template v-if="setShow">
<div class="bi-choice-mixin-analysis_title" v-if="title">
{{ title }}
</div>
<table
cellspacing="0"
cellpadding="0"
border="0"
class="bi-choice-mixin-analysis_table"
>
<tr class="" v-for="(item, index) in tableConfig" :key="index">
<td
v-for="(cItem, cIndex) in item"
:key="cIndex"
:colspan="index == 0 && cIndex == 2 ? xLength : 1"
>
{{ cItem }}
</td>
</tr>
</table>
</template>
<el-button
class="bi-choice-mixin-analysis_btn"
v-if="!hideBtn && !isPrint"
@click="toggleShow"
>
{{ setShow ? '隐藏' : '显示' }}
</el-button>
</div>
</div>
</template>
<script>
import mixin from '../mixin/index';
import { Button } from 'element-ui';
import BiBlank from './blank.vue';
export default {
name: 'bi-choice-mixin-analysis',
mixins: [mixin],
components: {
[Button.name]: Button,
BiBlank
},
data() {
return {
test: {
title: [
{
name: '患者年龄',
axis: ['小于18岁', '18-40岁', '18-40岁']
},
{
name: '患者发病状态',
axis: ['新发疾病', '旧病复发', '旧病复发2', '旧病复发3']
}
],
arr: [
['50%', '100%', '100%', '60%'],
['50%', '0%', '100%', '20%'],
['50%', '10%', '100%', '10%'],
['50%', '20%', '100%', '10%'],
[4, 1, 2, 5]
],
res: {
x: '0.923',
p: '0.342'
}
}
};
},
props: {
hideBtn: Boolean,
setShow: Boolean,
title: String
},
computed: {
xLength() {
return this.test.title[0].axis.length;
},
tableConfig() {
const {
title,
arr,
res: { x, p }
} = this.test;
const _arr = arr.slice(0, -1);
const c = [
['', '', title[0].name, '', '', '', ''],
['题目', '名称', ...title[0].axis, '总计', 'X²', 'p'],
..._arr.map((item, index) => {
if (index === 0) {
return [
title[1].name,
title[1].axis[index],
..._arr[index],
'',
''
];
} else if (index === _arr.length - 1) {
return ['', title[1].axis[index], ...arr[1], x, p];
} else {
return ['', title[1].axis[index], ...arr[1], '', ''];
}
}),
['总计', '', ...arr.slice(-1)[0], '', ''],
['*p>0.05**p>0.01', '', ...title[0].axis.map(() => ''), '', '', '', '']
];
return c;
}
},
methods: {
toggleShow() {
this.$emit('change-status');
}
},
mounted() {}
};
</script>
<style lang="scss" scoped>
@keyframes fadeIn {
0% {
opacity: 0;
}
100% {
opacity: 1;
}
}
.bi-choice-mixin-analysis {
position: relative;
border: 1px solid #ededed;
border-radius: 4px;
padding: 0 40px;
padding-bottom: 25px;
padding-top: 15px;
transition: all 0.3s;
&.hide {
border-color: transparent;
min-height: 35px;
}
&_title {
font-size: 16px;
font-weight: 500;
line-height: 1;
color: #2a3558;
text-align: center;
}
&_table {
width: 1058px;
margin-top: 27px;
tr {
height: 44px;
font-size: 14px;
color: #6f7a91;
text-align: center;
td {
max-width: 50px;
}
&:nth-child(2n + 1) {
background-color: #f9fafc;
}
&:first-child {
background-color: transparent;
td {
border-bottom: 1px solid #a5a5a5;
&[colspan='1'] {
border-color: transparent;
}
}
}
&:nth-child(2) {
background-color: transparent;
td {
border-bottom: 1px solid #a5a5a5;
}
}
&:last-child {
background-color: transparent;
td {
border-top: 1px solid #a5a5a5;
}
}
}
}
&_btn {
padding: 0;
position: absolute;
width: 73px;
height: 29px;
border: 1px solid #d9dfea;
border-radius: 4px;
top: 7px;
right: 8px;
font-size: 14px;
font-weight: 500;
line-height: 29px;
color: #6f7a91;
text-align: center;
cursor: pointer;
}
}
</style>
<!--
* @Description:
* @Date: 2021-06-11 01:21:29
-->
<template>
<div class="bi-chart-choice-mixin-toggle-axis">
<BiBlank height="25" :usePrint="true"></BiBlank>
<div class="bi-chart-choice-mixin-toggle-axis_sub_title">
{{ dealAxis.join('与') }}
</div>
<div class="bi-chart-choice-mixin-toggle-axis_text">
<span>X轴:</span>
<span>{{ dealAxis[0] }}</span>
<span style="margin-left:38px;">Y轴:</span>
<span>{{ dealAxis[1] }}</span>
</div>
<el-button icon="el-icon-sort" v-if="!isPrint" @click="toggle">
切换
</el-button>
</div>
</template>
<script>
import mixin from '../mixin/index';
import { Button } from 'element-ui';
import BiBlank from './blank.vue';
export default {
name: 'bi-chart-choice-mixin-toggle-axis',
mixins: [mixin],
components: {
[Button.name]: Button,
BiBlank
},
props: {
axis: {
type: Array,
default: () => []
}
},
computed: {
dealAxis() {
return this.axis.map(item => item.name);
}
},
methods: {
toggle() {
this.$emit('toggle-axis');
}
}
};
</script>
<style lang="scss" scoped>
.bi-chart-choice-mixin-toggle-axis {
&_sub_title {
width: 1138px;
min-height: 80px;
border: 1px solid #ededed;
border-radius: 4px;
padding: 30px;
font-size: 14px;
line-height: 1.2;
color: #6f7a91;
margin-bottom: 25px;
}
&_text {
height: 40px;
line-height: 40px;
border: 1px solid #efefef;
border-radius: 4px;
display: inline-block;
vertical-align: top;
padding: 0 25px;
margin-right: 16px;
span {
font-size: 14px;
color: #6f7a91;
&:nth-child(2n + 1) {
font-weight: 500;
color: #2a3558;
}
}
}
}
</style>
<!--
* @Description:
* @Date: 2021-06-10 10:34:38
-->
<template>
<div>
<BiBlank height="17" :usePrint="true"></BiBlank>
<div class="bi-chart-desc" :class="{ hide: !setShow, print: isPrint }">
<template v-if="setShow">
<div class="bi-chart-desc_title" v-if="title">{{ title }}</div>
<div
type="text"
class="bi-chart-desc_textarea"
@click="blur"
:style="{ paddingTop: title ? '20px' : '35px' }"
>
<span>
{{ text }}
</span>
<span
ref="input"
class="bi-chart-desc_textarea"
:contenteditable="!isPrint"
@input="input"
>
{{ localText }}
</span>
</div>
<div class="bi-chart-desc_text" v-if="resText">
{{ resText }}
</div>
</template>
<el-button
class="bi-chart-desc_btn"
v-if="!hideBtn && !isPrint"
@click="toggleShow"
>
{{ setShow ? '隐藏' : '显示' }}
</el-button>
</div>
</div>
</template>
<script>
import mixin from '../mixin/index';
import { Button } from 'element-ui';
import BiBlank from './blank.vue';
export default {
name: 'bi-chart-desc',
mixins: [mixin],
components: {
[Button.name]: Button,
BiBlank
},
data() {
return {
localText: ''
};
},
props: {
hideBtn: Boolean,
setShow: Boolean,
title: String,
text: String,
resText: String,
maxLength: {
type: Number,
default: 20
}
},
methods: {
keepLastIndex(obj) {
if (window.getSelection) {
obj.focus(); //解决ff不获取焦点无法定位问题
var range = window.getSelection(); //创建range
range.selectAllChildren(obj); //range 选择obj下所有子内容
range.collapseToEnd(); //光标移至最后
} else if (document.selection) {
var rangeForIE = document.selection.createRange(); //创建选择对象
rangeForIE.moveToElementText(obj); //range定位到obj
rangeForIE.collapse(false); //光标移至最后
rangeForIE.select();
}
},
toggleShow() {
this.$emit('change-status');
},
blur() {
this.$refs['input'].focus();
},
input(event) {
try {
const { innerText } = event.target;
if (
`${event.target.innerText}`.length > this.maxLength &&
this.localText.length === this.maxLength
) {
event.target.innerText = this.localText;
this.keepLastIndex(event.target);
return;
}
const text = `${innerText}`.slice(0, this.maxLength);
this.localText = text;
this.$emit('change-text', this.localText);
} catch (error) {
console.log(error);
}
}
},
mounted() {
this.$refs['input'] &&
this.$refs['input'].addEventListener('paste', function(e) {
e.stopPropagation();
e.preventDefault();
var text = '',
event = e.originalEvent || e;
if (event.clipboardData && event.clipboardData.getData) {
text = event.clipboardData.getData('text/plain');
} else if (window.clipboardData && window.clipboardData.getData) {
text = window.clipboardData.getData('Text');
}
if (document.queryCommandSupported('insertText')) {
document.execCommand('insertText', false, text);
} else {
document.execCommand('paste', false, text);
}
});
}
};
</script>
<style lang="scss" scoped>
@keyframes fadeIn {
0% {
opacity: 0;
}
100% {
opacity: 1;
}
}
.bi-chart-desc {
position: relative;
border: 1px solid #ededed;
border-radius: 4px;
padding-left: 40px;
transition: all 0.3s;
&.hide {
border-color: transparent;
min-height: 35px;
&.print {
min-height: 0;
}
}
&_title {
font-size: 16px;
font-weight: 500;
line-height: 1;
color: #2a3558;
padding-top: 15px;
text-align: center;
}
&_textarea {
animation: fadeIn 1s;
width: 1050px;
font-size: 14px;
line-height: 1.5;
color: #6f7a91;
outline: none;
border-color: rgba(82, 168, 236, 0.8);
padding: 35px 0;
word-break: break-all;
&.mobile {
font-size: 0.16rem;
}
}
&_text {
animation: fadeIn 1s;
font-size: 14px;
color: #1989fa;
margin-bottom: 35px;
}
&_btn {
padding: 0;
position: absolute;
width: 73px;
height: 29px;
border: 1px solid #d9dfea;
border-radius: 4px;
top: 7px;
right: 8px;
font-size: 14px;
font-weight: 500;
line-height: 29px;
color: #6f7a91;
text-align: center;
cursor: pointer;
}
}
</style>
<!--
* @Description: file content
* @Author: jml
* @Date: 2021-03-24 10:22:27
* @LastEditors: Please set LastEditors
* @LastEditTime: 2021-06-20 01:59:10
-->
<template>
<div class="bi-chart-legend">
<BiBlank height="20" :usePrint="true"></BiBlank>
<div class="bi-chart-legend_title" v-if="title">{{ title }}</div>
<div
class="bi-chart-legend_group"
:style="{ textAlign: title ? '' : 'center' }"
>
<div
class="bi-chart-legend_item"
v-for="(item, index) in data"
:key="index"
>
<div
class="bi-chart-legend_item_color"
:style="{ background: colors[index % colors.length] }"
></div>
<div class="bi-chart-legend_item_text">{{ item }}</div>
</div>
</div>
</div>
</template>
<script>
import mixin from '../mixin/index';
import BiBlank from './blank.vue';
export default {
mixins: [mixin],
name: 'bi-chart-legend',
components: { BiBlank },
props: {
title: String,
data: {
type: Array,
default: () => []
},
colors: {
type: Array,
default: () => []
}
},
data() {
return {};
}
};
</script>
<style lang="scss" scoped>
.bi-chart-legend {
line-height: 1.2;
font-size: 0;
&_title {
font-size: 14px;
font-weight: 500;
color: #2a3558;
margin-bottom: 12px;
}
&_item {
vertical-align: top;
display: inline-block;
font-size: 14px;
line-height: 14px;
color: #6f7a91;
margin: 12px 0;
padding-right: 60px;
&.mobile {
font-size: 0.2rem;
line-height: 1.2;
}
& > div {
display: inline-block;
&:nth-child(2) {
display: inline;
}
}
&_color {
width: 12px;
height: 12px;
border-radius: 2px;
}
}
}
</style>
<!--
* @Description:
* @Date: 2021-06-10 10:04:59
-->
<template>
<div class="bi-chart-title">
<div class="bi-chart-title_hr" v-if="!hideHr"></div>
<div class="bi-chart-title_name">
{{ name }}
</div>
<div class="bi-chart-title_btn_group" v-if="!isPrint">
<el-popover
class="bi-chart-title_btn_group_item"
placement="bottom"
trigger="click"
v-model="visibleColors"
v-if="!hideColor"
>
<BiTypesColor
@change="changeColors"
:initColors="colors"
></BiTypesColor>
<el-button
slot="reference"
class="bi-chart-title_color bi-chart-title_btn"
style="line-height:50px;"
>
<img
src="http://cdn.yxvzb.com/WEB/SaaS/images/bi/svg/colorSelector.svg"
alt=""
/>
</el-button>
</el-popover>
<el-button
class="bi-chart-title_delete bi-chart-title_btn bi-chart-title_btn_group_item"
v-if="!hideDelete"
@click="dialogVisible = true"
:disabled="guideStepShow(2) || guide.use"
:style="{
zIndex: guideStepShow(2) ? 11 : ''
}"
>
<img
src="http://cdn.yxvzb.com/WEB/SaaS/images/bi/svg/delete.svg"
alt=""
/>
删除
</el-button>
<el-popover
class="bi-chart-title_btn_group_item"
placement="bottom"
trigger="click"
v-model="visibleCharts"
v-if="!hideChangeChart"
>
<BiTypesChart
@change="changeChart"
:initType="chartType"
:disableTypes="disableTypes"
:extendTypes="extendTypes"
></BiTypesChart>
<el-button
:disabled="guideStepShow(1) || guide.use"
slot="reference"
class="bi-chart-title_change_chart bi-chart-title_btn"
:style="{
zIndex: guideStepShow(1) ? 11 : ''
}"
>
{{ typesName || '柱状图' }}
<i class="el-icon-caret-bottom el-icon--right"></i>
</el-button>
</el-popover>
</div>
<el-dialog
class="custom-dialog"
title="提示"
:visible.sync="dialogVisible"
:close-on-press-escape="false"
:close-on-click-modal="false"
width="400px"
>
<span>是否确认删除 ?删除后可在撤销删除里面恢复该分析</span>
<span slot="footer" class="dialog-footer">
<el-button @click="dialogVisible = false"></el-button>
<el-button type="primary" @click="deleteChart">
</el-button>
</span>
</el-dialog>
</div>
</template>
<script>
import { Popover, Dialog, Button } from 'element-ui';
import BiTypesColor from './types-color.vue';
import BiTypesChart from './types-chart.vue';
import mixin from '../mixin/index';
import types from '../chart-type/types';
import eventBus from '../eventBus';
export default {
name: 'bi-chart-title',
mixins: [mixin],
components: {
[Popover.name]: Popover,
[Dialog.name]: Dialog,
[Button.name]: Button,
BiTypesColor,
BiTypesChart
},
props: {
showGuide: Boolean,
hideHr: Boolean,
name: String,
hideDelete: Boolean,
hideColor: Boolean,
hideChangeChart: Boolean,
colors: Array,
chartType: [Number, String],
disableTypes: {
type: Array,
default: () => []
},
extendTypes: {
type: Array,
default: () => []
}
},
data() {
return {
visibleColors: false,
visibleCharts: false,
dialogVisible: false
};
},
computed: {
guideStepShow() {
return step =>
this.showGuide && this.guide.use && this.guide.step == step;
},
typesName() {
return (types[+this.chartType] || {}).cnName;
}
},
methods: {
changeColors(colors) {
this.visibleColors = false;
this.$emit('change-colors', colors);
},
changeChart(chartKey) {
this.visibleCharts = false;
this.$emit('change-chartkey', chartKey);
},
deleteChart() {
this.dialogVisible = false;
this.$emit('change-delete');
}
},
mounted() {
if (this.showGuide) {
eventBus.$on('addStep', () => {
this.guide.step += 1;
});
eventBus.$on('hideGuide', () => {
this.guide.use = false;
});
}
}
};
</script>
<style lang="scss" scoped>
.bi-chart-title {
height: 82px;
background: #f9fafc;
border-radius: 4px;
position: relative;
padding-left: 16px;
font-size: 0;
&_hr {
width: 5px;
height: 26px;
background: #1989fa;
position: absolute;
left: 0;
top: 28px;
}
&_name {
font-size: 22px;
color: #2a3558;
line-height: 82px;
&.mobile {
font-size: 0.26rem;
}
}
&_btn {
display: inline-block;
min-width: 42px;
height: 42px;
border: 1px solid #bac1ce;
border-radius: 4px;
vertical-align: top;
text-align: center;
line-height: 42px;
padding: 0 15px;
font-size: 16px;
font-weight: 500;
color: #6f7a91;
cursor: pointer;
position: relative;
&_group {
position: absolute;
right: 16px;
top: 20px;
&_item {
& + .bi-chart-title_btn_group_item {
margin-left: 8px;
}
}
}
}
}
</style>
<!--
* @Description: file content
* @Author: jml
* @Date: 2021-03-24 10:22:27
* @LastEditors: Please set LastEditors
* @LastEditTime: 2021-06-20 11:13:55
-->
<template>
<div>
<BiBlank height="40" :usePrint="true"></BiBlank>
<v-chart
class="chart"
:option="option"
style="margin:0 auto;"
:style="customStyle"
:autoresize="true"
:key="`${type}-${JSON.stringify(data)}`"
:type="type"
/>
<BiBlank height="40" :usePrint="true"></BiBlank>
</div>
</template>
<script>
import VChart from './chart-base.vue';
import chartTypes from '../chart-type/types';
import mixin from '../mixin/index';
import BiBlank from './blank.vue';
const isNumber = val => {
return !isNaN(val / 2);
};
export default {
name: 'bi-chart',
components: { 'v-chart': VChart, BiBlank },
mixins: [mixin],
provide: {
ecTheme: 'light'
},
props: {
width: {
type: [Number, String],
default: '100%'
},
height: {
type: [Number, String],
default: '400px'
},
yAxisUnit: {
type: String,
default: ''
},
axis: {
type: Array,
default: () => []
},
data: {
type: Array,
default: () => []
},
colors: {
type: Array,
default: () => []
},
type: {
type: [Number, String],
default: 1
}
},
data() {
return {
option: {}
};
},
computed: {
chartsConfig() {
return chartTypes[this.type] || { name: '', create: () => {} };
},
length() {
return this.data.reduce((pre, cur) => {
pre += cur.length;
return pre;
}, 0);
},
cHeight() {
const { type, data, length } = this;
let _height = this.height;
let maxHeight = data.length > 1 ? 1300 : 1400;
if (this.isMobile && !this.isPrint) {
maxHeight = maxHeight / 2;
}
if (+type === 2) {
const baseHeight = data.length * (data.length == 1 ? 40 : 15);
// 横向图表,根据数据量计算高度
_height = Math.min(Math.max(_height, length * baseHeight), maxHeight);
}
if (+type === 4) {
const baseHeight = data.length * (data.length == 1 ? 30 : 15);
// 横向图表,根据数据量计算高度
_height = Math.min(
Math.max(_height, data.length * baseHeight),
maxHeight
);
}
return _height;
},
cWidth() {
const { width, length } = this;
return Math.min(width, Math.max(length * 50, 800));
},
customStyle() {
const { cWidth, cHeight } = this;
const customStyle = {
width: isNumber(cWidth) ? `${cWidth}px` : cWidth,
height: isNumber(cHeight) ? `${cHeight}px` : cHeight
};
return customStyle;
}
},
methods: {
createChart() {
this.option = this.chartsConfig.create(
this,
this.data,
this.axis[0].names,
this.yAxisUnit,
this.colors,
this.axis[1].names,
this.cWidth,
this.cHeight
);
}
},
created() {
this.createChart();
},
watch: {
colors: {
handler() {
this.createChart();
}
},
type: {
handler() {
this.createChart();
}
},
data: {
handler() {
this.createChart();
}
}
}
};
</script>
<!--
* @Description:
* @Date: 2021-06-15 17:47:19
-->
<!--
* @Description: file content
* @Author: jml
* @Date: 2021-03-24 10:22:27
* @LastEditors: Please set LastEditors
* @LastEditTime: 2021-06-19 23:56:39
-->
<template>
<div class="bi-sex-icon">
<div class="bi-sex-icon_item">
<img src="http://cdn.yxvzb.com/WEB/SaaS/images/bi/svg/boy.svg" alt="" />
<p>{{ axis[0].name }} {{ data[0][0] }}</p>
</div>
<div class="bi-sex-icon_item">
<img src="http://cdn.yxvzb.com/WEB/SaaS/images/bi/svg/girl.svg" alt="" />
<p>{{ axis[1].name }} {{ data[0][1] }}</p>
</div>
</div>
</template>
<script>
export default {
name: 'bi-sex-icon',
props: {
data: {
type: Array,
default: () => []
},
axis: {
type: Array,
default: () => []
}
},
data() {
return {
option: {}
};
}
};
</script>
<style lang="scss" scoped>
.bi-sex-icon {
text-align: center;
padding-top: 110px;
height: 350px;
&_item {
display: inline-block;
margin: 0 45px;
p {
margin-top: 15px;
}
}
}
</style>
<!--
* @Description: file content
* @Author: jml
* @Date: 2021-03-24 10:22:27
* @LastEditors: Please set LastEditors
* @LastEditTime: 2021-06-19 22:39:37
-->
<template>
<div class="bi-table">
<BiBlank height="60" :usePrint="true"></BiBlank>
<table cellspacing="0" cellpadding="0" style="border-collapse:collapse;">
<tbody>
<tr
v-for="(item, index) in dealData"
:key="index"
:style="{
backgroundColor: index == 0 ? colors[0] : '',
color: index == 0 ? '#fff' : ''
}"
>
<template v-for="(cItem, cIndex) in item">
<td v-if="Array.isArray(cItem)" id="lineTd" :key="cIndex">
<span style="float:left;margin-top:20px;padding-left:5px;">
{{ cItem[0] }}
</span>
<span style="float:right;margin-top:-15px;padding-right:5px;">
{{ cItem[1] }}
</span>
</td>
<td
v-else
:key="cIndex"
:style="{
backgroundColor:
cIndex == 0 ? colors[isSingle && index === 0 ? 0 : 1] : '',
color: cIndex == 0 && colors.length > 1 ? '#fff' : ''
}"
>
{{ cItem }}
</td>
</template>
</tr>
</tbody>
</table>
<BiBlank height="40" :usePrint="true"></BiBlank>
</div>
</template>
<script>
import BiBlank from './blank.vue';
export default {
name: 'bi-table',
components: { BiBlank },
props: {
yAxisUnit: {
type: String,
default: ''
},
title: {
type: String,
default: ''
},
axis: {
type: Array,
default: () => []
},
data: {
type: Array,
default: () => []
},
colors: {
type: Array,
default: () => []
}
},
data() {
return {
option: {}
};
},
computed: {
isSingle() {
return this.data.length == 1;
},
dealData() {
const { data, isSingle, title, axis } = this;
return [
[isSingle ? '题干' : [axis[0].name, axis[1].name], ...axis[0].names],
...data.map((item, index) => {
return [isSingle ? title : axis[1].names[index], ...item];
})
];
}
}
};
</script>
<style lang="scss" scoped>
table {
width: 100%;
max-width: 980px;
margin: 0 auto;
}
tbody {
border: 1px solid #bfd8f2;
}
td {
padding: 27px 10px;
width: 50px;
text-align: center;
font-size: 14px;
border-right: 1px solid #bfd8f2;
&:last-child {
border-right: none;
}
}
#lineTd {
background: #fff url('http://cdn.yxvzb.com/WEB/SaaS/images/bi/svg/hr.svg')
no-repeat 100% center;
color: #2a3558;
max-width: 100px;
padding-bottom: 15px;
}
</style>
<!--
* @Description:
* @Date: 2021-06-15 15:52:53
-->
<template>
<div class="bi-tips">
<div class="bi-tips_item" style="top:-200px;" v-if="guide.step == 1">
<div class="bi-tips_btn" @click="next">继续引导</div>
<div class="bi-tips_content">
<p>不满意样式?</p>
<p>在此处切换该分析模块的其他图表展现形式</p>
</div>
</div>
<div
class="bi-tips_item"
style="top:-149px;right:143px;"
v-if="guide.step == 2"
>
<div class="bi-tips_btn" @click="next">继续引导</div>
<div class="bi-tips_content">
<p>不需要该题目的分析展示,可直接删除</p>
</div>
</div>
<div class="bi-tips_item" style="top:-224px;" v-if="guide.step == 3">
<div class="bi-tips_btn" @click="finish">
已了解,关闭引导
</div>
<div class="bi-tips_content">
<p>想更好展示分析报告见的关联性?可以拖动每个题目分析的先后顺序</p>
</div>
</div>
<div class="shadow"></div>
</div>
</template>
<script>
import eventBus from '../eventBus/index';
import mixin from '../mixin/index';
export default {
name: 'bi-tips',
mixins: [mixin],
methods: {
next() {
this.guide.step += 1;
eventBus.$emit('addStep');
},
finish() {
this.guide.use = false;
document.body.style.overflow = '';
document.getElementsByClassName(
'xrk-components-bi'
)[0].parentElement.parentElement.parentElement.style.overflow = '';
eventBus.$emit('hideGuide');
}
},
watch: {
'guide.use': {
handler(v) {
if (v) {
try {
this.$nextTick(() => {
setTimeout(() => {
document
.getElementsByClassName('xrk-components-bi')[0]
.parentElement.parentElement.parentElement.scrollTo(
0,
document.getElementsByClassName(
'bi-single-choice_item_block'
)[0].offsetTop - 300
);
document.body.style.overflow = 'hidden';
document.getElementsByClassName(
'xrk-components-bi'
)[0].parentElement.parentElement.parentElement.style.overflow =
'hidden';
}, 500);
});
} catch (error) {
eventBus.$emit('hideGuide');
console.log(error);
}
} else {
document.body.style.overflow = '';
document.getElementsByClassName(
'xrk-components-bi'
)[0].parentElement.parentElement.parentElement.style.overflow = '';
}
},
immediate: true
}
}
};
</script>
<style lang="scss" scoped>
.bi-tips {
position: absolute;
width: 100%;
height: 100%;
left: 0;
top: 0;
&_content {
background: linear-gradient(270deg, #41a0ff 0%, #1989fa 100%);
padding: 18px 30px;
border-radius: 5px;
max-width: 400px;
position: relative;
&::after {
content: '';
width: 0;
height: 0;
position: absolute;
border-left: 10px solid transparent;
border-right: 10px solid transparent;
border-bottom: none;
border-top: 10px solid #50a7ff;
bottom: -10px;
right: 40px;
}
&::before {
content: '';
width: 4px;
height: 78px;
position: absolute;
right: 47px;
bottom: -78px;
background-color: #50a7ff;
}
}
&_item {
position: absolute;
z-index: 15;
top: 0;
color: #fff;
font-size: 18px;
font-weight: 500;
line-height: 25px;
&:nth-child(1) {
right: 50px;
}
}
&_btn {
display: inline-block;
height: 40px;
background: rgba($color: #ffffff, $alpha: 0.15);
border-radius: 4px;
border: 1px solid #ffffff;
padding: 0 16px;
line-height: 40px;
color: #fff;
cursor: pointer;
left: 100%;
transform: translateX(-100%);
position: relative;
margin-bottom: 20px;
}
}
.shadow {
position: fixed;
width: 100vw;
height: 100vh;
background-color: rgba($color: #000000, $alpha: 0.7);
top: 0;
left: 0;
z-index: 9;
}
</style>
<!--
* @Description:
* @Date: 2021-06-15 15:52:53
-->
<template>
<div class="bi-tips">
<div class="bi-tips_item">
<div class="bi-tips_content">
<slot></slot>
</div>
<div class="bi-tips_btn">继续引导</div>
</div>
</div>
</template>
<script>
export default {
name: 'bi-tips'
};
</script>
<style lang="scss" scoped>
.bi-tips {
width: 100%;
height: 100%;
left: 0;
top: 0;
&_item {
color: #fff;
font-size: 18px;
font-weight: 500;
line-height: 25px;
&:nth-child(1) {
right: 50px;
}
}
&_btn {
display: inline-block;
height: 40px;
background: rgba($color: #ffffff, $alpha: 0.15);
border-radius: 4px;
border: 1px solid #ffffff;
padding: 0 16px;
line-height: 40px;
color: #fff;
cursor: pointer;
}
}
</style>
<!--
* @Description:
* @Date: 2021-06-09 20:37:58
-->
<template>
<div class="bi_title">
<div class="bi_title_text">
<div class="bi_title_text_index">{{ `${index}`.padStart(2, 0) }}</div>
{{ name }}
<img
src="http://cdn.yxvzb.com/WEB/SaaS/images/bi/svg/title.svg"
alt=""
class="bi_title_text_icon"
/>
</div>
</div>
</template>
<script>
export default {
name: 'bi-title',
props: {
index: String,
name: String
}
};
</script>
<style lang="scss" scoped>
$bluecolor: #1989fa;
.bi {
&_title {
line-height: 0;
height: 88px;
border-bottom: 2px solid #f4f4f4;
padding-left: 29px;
&_text {
margin-top: 32px;
height: 33px;
background: $bluecolor;
font-size: 22px;
line-height: 33px;
color: #fff;
padding-left: 60px;
padding-right: 20px;
min-width: 237px;
box-sizing: border-box;
display: inline-block;
position: relative;
&_index {
position: absolute;
width: 35px;
height: 35px;
background: #ffffff;
border: 2px solid $bluecolor;
border-radius: 4px;
font-size: 22px;
line-height: 33px;
color: $bluecolor;
text-align: center;
left: 16px;
top: -7px;
}
&_icon {
position: absolute;
right: -61px;
top: 0;
}
}
}
}
</style>
<!--
* @Description:
* @Date: 2021-06-10 12:44:14
-->
<template>
<div class="bi-types-chart">
<div
class="bi-types-chart_group"
v-for="(value, key) in chartTypes"
:key="key"
>
<div class="bi-types-chart_group_title">{{ value.name }}</div>
<div class="bi-types-chart_group_icons">
<div
class="bi-types-chart_group_icons_item"
:class="{ active: initType == item.key, disabled: item.disabled }"
@click="changeChart(item.key, item.disabled)"
v-for="item in value.list"
:key="item.name"
>
<img :src="item.icon" alt="" />
</div>
</div>
</div>
</div>
</template>
<script>
import chartTypes from '../chart-type/types';
const chartSort = {
柱状图: 0,
饼图: 1,
折线图: 2,
表格: 3,
初始化: 4
};
export default {
name: 'bi-types-chart',
props: {
initType: [Number, String],
extendTypes: {
type: Array,
default: () => []
},
disableTypes: {
type: Array,
default: () => []
}
},
data() {
return {
chartTypes: Object.entries(chartTypes)
.filter(item => {
if (this.extendTypes.includes(+item[0])) {
return true;
} else {
return item[0] != 12;
}
})
.reduce((pre, [key, value]) => {
const { cnName } = value;
if (pre[chartSort[cnName]]) {
pre[chartSort[cnName]].list.push({
...value,
disabled:
this.disableTypes.indexOf(+key) > -1 ||
this.disableTypes.indexOf(`${key}`) > -1,
key: key
});
} else {
pre[chartSort[cnName]] = {
name: cnName,
list: [
{
...value,
disabled:
this.disableTypes.indexOf(+key) > -1 ||
this.disableTypes.indexOf(`${key}`) > -1,
key: key
}
]
};
}
return pre;
}, [])
.map(item => {
item.list = item.list.sort((a, b) => {
if (a.sort - b.sort < 0) {
return -1;
} else {
return 1;
}
});
return item;
})
};
},
methods: {
changeChart(chartKey, disabled) {
if (disabled) {
return;
}
this.$emit('change', chartKey);
}
},
created() {}
};
</script>
<style lang="scss" scoped>
.bi-types-chart {
&_title {
text-align: center;
font-size: 16px;
font-weight: 500;
color: #2a3558;
margin-bottom: 15px;
}
&_group {
font-size: 16px;
padding: 0 5px;
border: 2px solid transparent;
cursor: pointer;
transition: all 0.3s;
&.active {
padding: 5px;
border-color: #1989fa;
box-shadow: 0px 3px 6px rgba(0, 0, 0, 0.16);
}
& + .bi-colors_group {
margin-top: 5px;
}
&_title {
font-size: 16px;
font-weight: 500;
color: #2a3558;
text-align: center;
margin-bottom: 10px;
margin-top: 10px;
}
&_icons {
&_item {
display: inline-flex;
width: 50px;
height: 50px;
align-items: center;
justify-content: center;
border: 2px solid transparent;
margin: 0 5px;
&.active {
border-color: #1989fa;
box-shadow: 0px 3px 6px rgba(0, 0, 0, 0.16);
}
&.disabled {
filter: grayscale(1);
cursor: not-allowed;
}
}
}
}
}
</style>
<!--
* @Description:
* @Date: 2021-06-10 12:44:14
-->
<template>
<div class="bi-colors">
<div class="bi-colors_title">修改图表颜色</div>
<div
:class="{ active: localColorIndex === index }"
class="bi-colors_group"
v-for="(item, index) in colors"
:key="`${item[0]}-${index}`"
@click="changeColors(index)"
>
<div
class="bi-colors_item"
v-for="(color, cIndex) in item"
:key="`${color}-${cIndex}`"
:style="{ background: color }"
></div>
</div>
</div>
</template>
<script>
import colors from '../config/colors';
export default {
name: 'bi-types-colors',
props: {
initColors: {
type: Array,
default: () => []
}
},
data() {
return {
localColorIndex: 0,
colors: colors
};
},
methods: {
changeColors(index) {
this.localColorIndex = index;
this.$emit('change', this.colors[index]);
}
},
created() {
const index = this.colors.findIndex(
item => item.join(',') === this.initColors.join(',')
);
if (index === -1 && this.initColors.length === 10) {
this.colors.unshift(this.initColors);
}
this.localColorIndex = index === -1 ? 0 : index;
}
};
</script>
<style lang="scss" scoped>
.bi-colors {
&_title {
text-align: center;
font-size: 16px;
font-weight: 500;
color: #2a3558;
margin-bottom: 15px;
}
&_group {
font-size: 0;
padding: 0 5px;
border: 2px solid transparent;
cursor: pointer;
transition: all 0.3s;
&.active {
padding: 5px;
border-color: #1989fa;
box-shadow: 0px 3px 6px rgba(0, 0, 0, 0.16);
}
& + .bi-colors_group {
margin-top: 5px;
}
}
&_item {
display: inline-block;
width: 44px;
height: 44px;
}
}
</style>
<!--
* @Description:
* @Date: 2021-06-09 19:05:20
-->
<template>
<div class="bi-catalogue" ref="bi-catalogue">
<div class="bi-catalogue-title">
<div class="bi-catalogue-title_cn_name">目录</div>
<div class="bi-catalogue-title_en_name">Contents</div>
<div class="bi-catalogue-title_hr"></div>
</div>
<div class="bi-catalogue_list">
<div
class="bi-catalogue_list_item"
v-for="({ name, child }, index) in catalogueArr"
:key="index"
>
<div class="bi-catalogue_list_item_name">
<span style="margin-right:20px;">
{{ `${index + 1}`.padStart(2, 0) }}
</span>
{{ name }}
</div>
<div class="bi-catalogue_list_item_hr"></div>
<div class="bi-catalogue_list_item_child">
<div
class="bi-catalogue_list_item_child_item"
v-for="({ name, page }, cIndex) in child"
:key="cIndex"
>
<div>
<p
class="bi-catalogue_list_item_child_item_name"
style="float:left;"
>
<span style="margin-right:5px;">
{{ `${index + 1}.${cIndex + 1}` }}
</span>
{{ name }}
</p>
<div class="bi-catalogue_list_item_child_item_hr"></div>
<span class="bi-catalogue_list_item_child_item_page">
{{ `${+page + cataloguePageSize}`.padStart(2, 0) }}
</span>
</div>
</div>
</div>
</div>
</div>
</div>
</template>
<script>
import { heightToPage } from '../chart-type/common';
import mixin from '../mixin/index';
export default {
name: 'bi-catalogue',
mixins: [mixin],
props: {
catalogueArr: {
type: Array,
default: () => []
}
},
data() {
return {
cataloguePageSize: 0
};
},
computed: {
// cataloguePageSize() {
// const catalogueCount =
// 5 +
// this.catalogueArr.slice(2).reduce((pre, cur) => {
// pre.push(...cur.child);
// return pre;
// }, []).length -
// 10;
// const cataloguePageSize = 1 + Math.ceil(catalogueCount / 17);
// return cataloguePageSize;
// }
},
created() {},
watch: {
catalogueArr: {
handler() {
this.$nextTick(() => {
this.cataloguePageSize = heightToPage(
this.$refs['bi-catalogue'].offsetHeight
);
});
},
immediate: true,
deep: true
}
}
};
</script>
<style lang="scss" scoped>
.bi-catalogue {
$color: #2a3558;
$colorNormal: #6f7a91;
padding: 0 50px;
box-sizing: border-box;
color: $color;
&-title {
padding-top: 44px;
&_cn_name {
font-size: 55px;
line-height: 1.5;
}
&_en_name {
font-size: 28px;
line-height: 45px;
padding-left: 10px;
}
&_hr {
width: 1090px;
height: 3px;
background: $color;
margin-top: 17px;
}
}
&_list {
margin-top: 133px;
&_item {
& + .bi-catalogue_list_item {
padding-top: 65px;
}
&_name {
font-size: 25px;
}
&_hr {
width: 1090px;
height: 2px;
background: $color;
margin-top: 17px;
}
&_child {
padding-top: 30px;
&_item {
padding: 30px 0;
font-size: 21px;
position: relative;
page-break-inside: avoid;
&_hr {
width: 1096px;
height: 30px;
position: relative;
&::after {
content: '';
position: absolute;
left: 0;
top: 15px;
width: 1096px;
height: 0;
border-top: 1px dashed #707070;
}
}
&_name {
height: 30px;
line-height: 30px;
background: #fff;
position: absolute;
left: 0;
top: 30px;
z-index: 1;
padding-right: 20px;
max-width: 950px;
}
&_page {
height: 30px;
line-height: 30px;
padding-left: 10px;
background: #fff;
position: absolute;
right: 0;
top: 30px;
}
}
}
&:last-child {
.bi-catalogue_list_item_child {
&_item:last-child {
padding-bottom: 77px;
}
}
}
}
}
}
.mobile {
padding: 0.59rem 0.43rem;
.bi-catalogue-title {
&_cn_name {
font-size: 0.44rem;
}
&_en_name {
font-size: 0.27rem;
line-height: 0.36rem;
padding-left: 0;
}
&_hr {
width: 9.09rem;
height: 0.03rem;
margin-top: 0.15rem;
}
}
.bi-catalogue_list {
margin-top: 0.95rem;
&_item {
padding-top: 0.3rem;
&_name {
font-size: 0.35rem;
span {
margin-right: 0.1rem !important;
}
}
&_hr {
width: 9.09rem;
height: 0.03rem;
margin-top: 0.11rem;
}
&_child {
padding-top: 0.35rem;
&_item {
padding: 0.3rem 0;
overflow: hidden;
&_name {
top: 0.3rem;
font-size: 0.32rem;
padding-right: 0.2rem;
max-width: 8rem;
}
&_hr {
width: 9.09rem;
}
&_page {
top: 0.3rem;
font-size: 0.32rem;
padding-left: 0.2rem;
}
}
}
& + .bi-catalogue_list_item {
margin-top: 0.59rem;
}
}
}
}
</style>
<!--
* @Description:
* @Date: 2021-06-09 19:05:20
-->
<template>
<div class="bi-cover-2">
<BiBlank :height="42" :usePrint="true"></BiBlank>
<slot></slot>
<div class="bi-cover-2-content">
<p>服务公司声明</p>
<div>
<p>
本公司以勤勉的职=职业态度,独立、客观地出具本报告。本报告所采用的数据和信息均来自项目采集,本公司不保证该等信息的准确性或完整性。分析逻辑基于团队的职业理解,清晰
准确地反映了本公司的观点,结论不受任何第三方的授意或影响,特此声明。
</p>
</div>
<p class="t">法律声明</p>
<div>
<p>
本报告仅供本公司的客户使用。本公司不会因接收人收到本报告而视其为本公司的当然客户。
</p>
<p>
本报告所载的资料仅反映本公司截止发布本报告当日的判断。在不同时期,本公司可发出与本报告所载资料不一致的报告。
</p>
<p>
本报告的版权归本公司所有,未经书面许可,任何机构和个人不得以任何形式翻版、复制、发表或引用,或再次分发给任何其他人,或以任何侵犯本公司版权的其他方式使用。
</p>
<p>
向日葵将尽商业上合理水平的技能和注意义务为平台用户提供稳定的技术服务,但不对服务内容本身承担责任。
</p>
</div>
</div>
</div>
</template>
<script>
import BiBlank from '../commonComponents/blank.vue';
export default {
name: 'bi-cover-end',
components: { BiBlank },
props: {
title: String
}
};
</script>
<style lang="scss" scoped>
.bi-cover {
width: 1200px;
height: 1697px;
background: #1989fa;
page-break-before: always;
font-size: 50px;
color: #ffffff;
text-align: center;
padding: 0 50px;
padding-top: 562px;
letter-spacing: 3px;
text-indent: 3px;
}
.bi-cover-2 {
page-break-before: always;
&-content {
width: 100%;
border: 4px solid #f4f4f4;
border-radius: 4px;
padding: 40px 26px;
background: #fff;
p {
font-size: 18px;
color: #2a3558;
}
.t {
margin-top: 60px;
}
div {
margin-top: 24px;
p {
font-size: 14px;
line-height: 1.5;
color: #989898;
}
}
}
&.mobile {
.bi-cover-2-content {
border-width: 2px;
padding-top: 20px;
p {
font-size: 0.32rem;
}
.t {
margin-top: 30px;
}
div {
margin-top: 15px;
p {
font-size: 0.32rem;
}
}
}
}
}
</style>
<!--
* @Description:
* @Date: 2021-06-09 19:05:20
-->
<template>
<div class="bi-mission" ref="bi-mission">
<BiTitle index="2" :name="name"></BiTitle>
<div class="bi-mission_group">
<div class="bi-mission_item">
<BiChartBlock :chartConfig="data[0]"></BiChartBlock>
</div>
<div class="bi-mission_item">
<BiChartBlock :chartConfig="data[1]"></BiChartBlock>
</div>
<BiChartBlock
style="margin-top:30px;"
:chartConfig="data[2]"
></BiChartBlock>
<template name="项目参与人完成任务区间分布">
<BiChartBlock
style="margin-top:44px;"
:chartConfig="data[3]"
></BiChartBlock>
</template>
</div>
</div>
</template>
<script>
import BiTitle from '../commonComponents/title.vue';
import BiChartBlock from '../commonComponents/chart-block.vue';
import { heightToPage } from '../chart-type/common';
export default {
name: 'bi-mission',
components: { BiTitle, BiChartBlock },
props: {
name: String,
data: {
default: () => [],
type: Array
}
},
data() {
return {};
},
methods: {},
mounted() {
this.$emit('page', heightToPage(this.$refs['bi-mission'].offsetHeight));
}
};
</script>
<style lang="scss" scoped>
.bi-mission {
page-break-before: always;
padding-bottom: 50px;
&_group {
padding: 0 30px;
padding-top: 35px;
position: relative;
&::before {
content: '';
position: absolute;
width: 1px;
height: 417px;
background-color: #e5e5e5;
left: 596px;
top: 163px;
}
}
&_item {
vertical-align: top;
display: inline-block;
width: 544px;
min-height: 550px;
& + .bi-mission_item {
margin-left: 42px;
}
}
}
</style>
<!--
* @Description:
* @Date: 2021-06-16 16:52:35
-->
<template>
<div class="bi-mobile-base-info">
<BiMobileTitle index="1" title="基础信息"></BiMobileTitle>
<div class="bi-mobile-base-info_content">
<div
class="bi-mobile-base-info_content_item"
v-for="(item, index) in info"
:key="index"
>
<div class="bi-mobile-base-info_content_item_label">
{{ item.label }}
</div>
<div class="bi-mobile-base-info_content_item_value">
{{ item.value }}
</div>
</div>
</div>
</div>
</template>
<script>
import BiMobileTitle from './title.vue';
export default {
name: 'bi-mobile-base-info',
components: { BiMobileTitle },
data() {
return {
info: [
{
label: '项目参与人:',
value: '张三'
},
{
label: '发起方:',
value: '葵花医疗集团'
},
{
label: '服务商:',
value: '杭州大江工作室'
},
{
label: '提交日期:',
value: '2021-05-30'
},
{
label: '可供采购量:',
value: '100'
},
{
label: '本期采购量:',
value: '20'
},
{
label: '数据收集:',
value: '20'
},
{
label: '报表成时间:',
value: '2021-05-21 22:21:12'
}
]
};
}
};
</script>
<style lang="scss" scoped>
.bi-mobile-base-info {
page-break-before: always;
&_content {
width: 9.15rem;
border: 0.03rem solid #e8e8e8;
border-radius: 0.2rem;
margin: 0.34rem auto 0.6rem auto;
padding: 0.57rem 0.32rem;
&_item {
font-size: 0.35rem;
color: #9d9d9d;
& > div {
display: inline-block;
}
&_value {
float: right;
color: #2d2d2d;
}
& + .bi-mobile-base-info_content_item {
margin-top: 0.5rem;
}
}
}
}
</style>
<!--
* @Description:
* @Date: 2021-06-16 18:21:11
-->
<template>
<div class="bi-mobile-chart-block">
<div class="bi-mobile-chart-block_title">{{ chartConfig.title.name }}</div>
<BiChart
v-bind="{
...chartConfig.chart,
colors: colors,
width: width,
height: height
}"
></BiChart>
<div
class="bi-mobile-chart-block_legend"
style="padding-top:0.5rem;"
v-if="chartConfig.legend.show"
>
<div class="bi-mobile-chart-block_legend_item">
<div class="bi-mobile-chart-block_legend_left">选项</div>
<div class="bi-mobile-chart-block_legend_right">回复情况</div>
</div>
<div
class="bi-mobile-chart-block_legend_item"
v-for="(item, index) in chartConfig.legend.data"
:key="index"
>
<div class="bi-mobile-chart-block_legend_left">
<span :style="{ background: colors[index % colors.length] }"></span>
<span>{{ item }}</span>
</div>
<div class="bi-mobile-chart-block_legend_right">
{{ chartConfig.chart.data[0][index] }}
</div>
</div>
</div>
<div style="padding-top:0.5rem;" v-if="chartConfig.desc.show">
<div class="bi-mobile-chart-block_desc">{{ chartConfig.desc.text }}</div>
</div>
</div>
</template>
<script>
import BiChart from '../../commonComponents/chart.vue';
import mixin, { printWidth } from '../../mixin/index';
import { getQueryVariable } from '../../chart-type/common';
const chartTypes = [1, 2, 5, 6, 9];
const isPrint = getQueryVariable('print') == 1;
const baseFontSize = Math.min(window.innerWidth / 10, 75);
export default {
name: 'bi-mobile-chart-block',
components: { BiChart },
mixins: [mixin],
data() {
return {
width: this.dealPos(9),
chartType:
chartTypes[
Math.min(
parseInt(Math.random() * chartTypes.length),
chartTypes.length - 1
)
],
colors: [
'#FFEA00',
'#FE7A03',
'#FFC200',
'#FF9400',
'#FF9DAD',
'#FF6761',
'#FFD8B2',
'#7A7BF5',
'#04B2BB'
]
};
},
props: {
chartConfig: {
type: Object,
default: () => ({})
}
},
computed: {
height() {
if (this.chartConfig.chart.type == 2) {
const { length } = this.chartConfig.chart.data;
return this.dealPos(Math.max(6, length));
}
return this.dealPos(7);
}
},
methods: {
dealPos(dis) {
return dis * (isPrint ? printWidth : baseFontSize);
}
}
};
</script>
<style lang="scss" scoped>
.bi-mobile-chart-block {
border-top: 0.13rem solid #f4f4f6;
padding: 0.4rem;
page-break-before: always;
& > div {
page-break-inside: avoid;
}
&_title {
font-size: 0.4rem;
color: #2d2d2d;
line-height: 1.3;
}
&_desc {
padding: 0.4rem;
background: #f7f7f7;
font-size: 0.32rem;
line-height: 0.75rem;
color: #2a3558;
border-radius: 0.2rem;
&:empty {
display: none;
}
}
&_legend {
width: 8.6rem;
margin-left: 0.5rem;
font-size: 0.35rem;
color: #1a1818;
&_item {
& > div {
display: inline-block;
}
& + .bi-mobile-chart-block_legend_item {
margin-top: 0.3rem;
}
}
&_left {
max-width: 5.5rem;
span {
&:first-child {
display: inline-block;
width: 0.21rem;
height: 0.21rem;
border-radius: 50%;
margin-right: 0.1rem;
}
}
}
&_right {
width: 3rem;
float: right;
text-align: center;
}
}
}
</style>
<!--
* @Description:
* @Date: 2021-06-16 17:57:41
-->
<template>
<div style="background:#fff;padding-bottom: 0.54rem; border-radius: 4px;">
<BiMobileTitle :index="index" :title="title"></BiMobileTitle>
<div class="bi-mobile-single-choice_content" v-if="info.length > 0">
<div
class="bi-mobile-single-choice_content_item"
:class="{ more: info.length > 2 }"
v-for="(item, index) in info"
:key="index"
>
<div class="bi-mobile-single-choice_content_item_name">
{{ item.name }}
<span v-if="item.desc">{{ item.desc }}</span>
</div>
<div class="bi-mobile-single-choice_content_item_number">
<span>{{ item.value }}</span>
<span>{{ item.unit }}</span>
</div>
</div>
</div>
</div>
</template>
<script>
import BiMobileTitle from './title.vue';
export default {
name: 'bi-mobile-single-choice',
components: {
BiMobileTitle
},
props: {
index: [String, Number],
title: String,
info: {
type: Array,
default: () => []
}
},
methods: {}
};
</script>
<style lang="scss" scoped>
.bi-mobile-single-choice {
&_content {
width: 9.15rem;
border: 0.03rem solid #e8e8e8;
border-radius: 0.2rem;
margin: 0.34rem auto 0 auto;
padding: 0.57rem 0.32rem;
padding-top: 0.52rem;
padding-bottom: 0.54rem;
page-break-after: always;
&_item {
width: 4rem;
display: inline-block;
&.more {
width: 100%;
display: block;
height: 1rem;
line-height: 1rem;
& > div {
font-size: 0.35rem;
color: #9d9d9d;
display: inline-block;
vertical-align: top;
}
.bi-mobile-single-choice_content_item_number {
float: right;
margin-top: 0;
span {
font-size: 0.35rem !important;
color: #2d2d2d !important;
}
}
}
&_name {
text-align: center;
font-size: 0.4rem;
color: #1a1818;
span {
font-size: 0.24rem;
color: #a3a3a6;
}
}
&_number {
color: #2d2d2d;
font-size: 0.4rem;
text-align: center;
margin-top: 0.25rem;
span:first-child {
font-size: 0.61rem;
color: #ff8200;
}
}
}
}
}
</style>
<!--
* @Description:
* @Date: 2021-06-16 17:57:41
-->
<template>
<div class="bi-mobile-single-choice">
<slot></slot>
<BiMobileChartBlock
:class="{ wrap: pageWrap }"
ref="bi-single-choice_item"
class="bi-single-choice_item"
v-for="(item, index) in singleChoice"
:key="index"
:chartConfig="item"
></BiMobileChartBlock>
</div>
</template>
<script>
import { getQueryVariable } from '../../chart-type/common';
import BiMobileChartBlock from './chart-block.vue';
import BiChartBlock from '../../commonComponents/chart-block.vue';
export default {
name: 'bi-mobile-single-choice',
components: {
BiMobileChartBlock:
getQueryVariable('print') == 1 ? BiChartBlock : BiMobileChartBlock
},
props: {
singleChoice: {
type: Array,
default: () => []
},
pageWrap: Boolean
},
methods: {
getPageSize() {
const topDom = (this.$slots.default || [{}])[0].elm || {
offsetHeight: 0
};
const domArr = [
{
$el: topDom
},
...(this.$refs['bi-single-choice_item'] || []).map(item => {
let height = 0;
item.pervPage = item.$children.reduce(
(pre, { $el: { offsetHeight } }) => {
height += offsetHeight;
if (height >= 1697) {
pre += 1;
height = offsetHeight;
}
return pre;
},
0
);
return item;
})
];
const pageSizeInfo = {
pervHeight: 0,
pervPage: 0,
height: 0,
page: this.pageWrap ? 0 : 1
};
const catalogueInfoArr = [];
domArr.forEach(
({ $el: { offsetHeight }, chartConfig, pervPage = 0 }, index) => {
pageSizeInfo.height += offsetHeight;
if (this.pageWrap) {
if (index == 1) {
// 遍历到第二个时,如果存在顶部标题,则将两个高度相加(汇总标题和表格不做强制分页)
pageSizeInfo.pervHeight = offsetHeight + topDom.offsetHeight;
if (offsetHeight + topDom.offsetHeight > 1697) {
// pageSizeInfo.pervPage = 1;
pageSizeInfo.page += 1;
}
} else {
pageSizeInfo.page += pageSizeInfo.pervPage + 1;
pageSizeInfo.pervPage = pervPage;
}
} else if (pageSizeInfo.height >= 1697) {
pageSizeInfo.page += 1;
pageSizeInfo.height = offsetHeight;
}
catalogueInfoArr.push({
name: ((chartConfig || {}).title || {}).name,
page: pageSizeInfo.page
});
}
);
this.$emit('page', {
pageSize: pageSizeInfo.page,
info: catalogueInfoArr
});
}
},
watch: {
singleChoice: {
handler() {
this.$nextTick(this.getPageSize);
},
deep: true,
immediate: true
}
}
};
</script>
<style lang="scss" scoped>
.bi-mobile-single-choice {
background: transparent;
border: none;
page-break-before: always;
.bi-single-choice_item {
padding: 20px;
border-radius: 4px;
border: 1px solid #f4f4f4;
box-shadow: 0px 3px 6px rgba(27, 39, 64, 0.04);
background-color: #fff;
page-break-inside: avoid;
margin-top: 8px;
& + .bi-single-choice_item {
&.wrap {
page-break-before: always;
}
}
}
&_content {
width: 9.15rem;
border: 0.03rem solid #e8e8e8;
border-radius: 0.2rem;
margin: 0.34rem auto 0.6rem auto;
padding: 0.57rem 0.32rem;
padding-top: 0.52rem;
padding-bottom: 0.54rem;
&_item {
width: 4rem;
display: inline-block;
&.more {
width: 100%;
display: block;
height: 1rem;
line-height: 1rem;
& > div {
font-size: 0.35rem;
color: #9d9d9d;
display: inline-block;
vertical-align: top;
}
.bi-mobile-single-choice_content_item_number {
float: right;
margin-top: 0;
span {
font-size: 0.35rem !important;
color: #2d2d2d !important;
}
}
}
&_name {
text-align: center;
font-size: 0.4rem;
color: #1a1818;
span {
font-size: 0.24rem;
color: #a3a3a6;
}
}
&_number {
color: #2d2d2d;
font-size: 0.4rem;
text-align: center;
margin-top: 0.25rem;
span:first-child {
font-size: 0.61rem;
color: #ff8200;
}
}
}
}
}
</style>
<!--
* @Description:
* @Date: 2021-06-16 17:02:53
-->
<template>
<div class="bi-mobile-title">
<div class="bi-mobile-title_content">
<div class="bi-mobile-title_index">{{ `${index}`.padStart(2, 0) }}</div>
<div class="bi-mobile-title_name">{{ title }}</div>
</div>
</div>
</template>
<script>
export default {
name: 'bi-mobile-title',
props: {
index: [String, Number],
title: String
}
};
</script>
<style lang="scss" scoped>
.bi-mobile-title {
background-color: #fff;
font-size: 0.43rem;
color: #2d2d2d;
&_index {
font-size: 0.4rem;
color: #fff;
width: 0.64rem;
height: 0.64rem;
background: #ff8200;
line-height: 0.64rem;
text-align: center;
margin-right: 0.1rem;
}
&_content {
display: inline-block;
min-width: 5.7rem;
height: 0.84rem;
line-height: 0.84rem;
background-color: #f4f4f6;
padding-left: 0.4rem;
padding-right: 0.4rem;
position: relative;
& > div {
display: inline-block;
}
&::after {
content: '';
width: 0;
height: 0;
position: absolute;
right: -0.44rem;
top: 0;
border-top: 0.85rem solid #f4f4f6;
border-left: 0.43rem solid transparent;
border-right: 0.43rem solid transparent;
border-bottom: none;
}
}
}
</style>
<!--
* @Description:
* @Date: 2021-06-17 20:27:55
-->
<template>
<div>
<div class="fixed-btn" v-if="!isPrint">
<div
class=""
@click="dialogVisible = true"
v-if="questionData.findIndex(item => item.isDelete == 1) > -1"
>
<img src="../lib/svg/chexiao.svg" />
撤销删除
</div>
<div class="">
<img src="../lib/svg/baocun.svg" />
保存
</div>
<div class="">
<img src="../lib/svg/daochu-tianchong.svg" />
导出
</div>
</div>
<el-dialog
class="custom-dialog"
title="选择撤销删除的题目"
:visible.sync="dialogVisible"
:close-on-press-escape="false"
:close-on-click-modal="false"
width="420px"
>
<el-checkbox-group v-model="resetDeleteArr">
<el-checkbox
class="reset-delete-item"
v-for="(item, index) in questionData.filter(
item => item.isDelete == 1
)"
:label="item"
:key="index"
>
<div class="reset-delete-item_text">{{ item.title.name }}</div>
</el-checkbox>
</el-checkbox-group>
<span slot="footer" class="dialog-footer">
<el-button
type="primary"
@click="resetDelete"
:disabled="resetDeleteArr.length == 0"
>
撤销删除
</el-button>
</span>
</el-dialog>
</div>
</template>
<script>
import mixin from '../mixin/index';
import { Dialog, Button, Checkbox, CheckboxGroup } from 'element-ui';
export default {
name: 'bi-operate',
mixins: [mixin],
components: {
[Dialog.name]: Dialog,
[Button.name]: Button,
[CheckboxGroup.name]: CheckboxGroup,
[Checkbox.name]: Checkbox
},
props: {
questionData: {
type: Array,
default: () => []
}
},
data() {
return {
dialogVisible: false,
resetDeleteArr: []
};
},
methods: {
resetDelete() {
this.dialogVisible = false;
this.resetDeleteArr.forEach(item => {
item.isDelete = 0;
});
this.resetDeleteArr = [];
}
}
};
</script>
<style lang="scss" scoped>
.fixed-btn {
position: fixed;
top: 50%;
right: 30px;
transform: translateY(-50%);
z-index: 10;
& > div {
width: 100px;
height: 95px;
background: #ffffff;
border: 1px solid #e6e6e6;
border-radius: 4px;
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
flex-direction: column;
color: #6f7a91;
font-size: 16px;
img {
margin-bottom: 5px;
}
& + div {
margin-top: 8px;
}
}
}
.reset-delete-item {
width: 360px;
overflow: hidden;
display: flex;
align-items: center;
& + .reset-delete-item {
margin-top: 15px;
}
&_text {
width: 340px;
text-align: left;
overflow: hidden;
text-overflow: ellipsis;
-webkit-box-orient: vertical;
-webkit-line-clamp: 1;
}
}
</style>
<!--
* @Description:
* @Date: 2021-06-09 19:05:20
-->
<template>
<div class="bi-overview" ref="bi-overview">
<BiTitle index="1" :name="name"></BiTitle>
<div class="bi-overview_content">
<div class="bi-overview_content_title">
{{ title }}
</div>
<div
class="bi-overview_content_text"
v-for="(item, index) in data"
:key="index"
>
<div
v-for="(cItem, cIndex) in item"
:key="cIndex"
:class="{ wrap: !textWrap }"
>
<div>{{ cItem.name }}{{ textWrap ? '' : ':' }}</div>
<div>{{ cItem.value }}</div>
</div>
</div>
</div>
</div>
</template>
<script>
import BiTitle from '../commonComponents/title.vue';
import eventBus from '../eventBus/index';
export default {
name: 'bi-overview',
props: {
textWrap: Boolean,
name: String,
title: String,
data: {
type: Array,
default: () => []
}
},
components: { BiTitle },
mounted() {
eventBus.$emit(
'overview-page-height',
this.$refs['bi-overview'].offsetHeight
);
}
};
</script>
<style lang="scss" scoped>
$bluecolor: #1989fa;
.bi-overview {
page-break-before: always;
border: 1px solid #f4f4f4;
&_content {
padding: 16px 29px;
& > div {
&:nth-child(2n + 1) {
width: 1146px;
height: 90px;
background: #f9fafc;
}
}
&_title {
font-size: 22px;
line-height: 1.2;
color: #2a3558;
padding-left: 9px;
padding-top: 23px;
}
&_text {
height: 90px;
padding-left: 16px;
padding-top: 24px;
& > div {
display: inline-block;
width: 450px;
&:nth-child(3) {
width: 200px;
}
& > div {
font-size: 14px;
&:nth-child(1) {
color: #6f7a91;
}
&:nth-child(2) {
color: #2a3558;
margin-top: 13px;
}
}
}
.wrap {
& > div {
display: inline-block;
}
}
}
}
}
</style>
<!--
* @Description:
* @Date: 2021-06-10 18:57:34
-->
<template>
<div class="bi-single-choice" ref="bi-single-choice">
<slot></slot>
<vue-draggable
class="bi-single-choice_group"
:class="{ wrap: pageWrap }"
handle=".bi-chart-title_name"
v-model="copySingleChoice"
:disabled="disabled"
chosen-class="chosen"
force-fallback="true"
:group="groupName"
animation="500"
touchStartThreshold="0"
@start="onStart"
@end="onEnd"
>
<transition-group v-for="(item, index) in copySingleChoice" :key="index">
<div
:key="index"
style="position:relative;"
class="bi-single-choice_item_block"
>
<BiChartBlock
ref="bi-single-choice_item"
class="bi-single-choice_item"
:style="{
zIndex: guideStepShow(index, 3) ? 11 : ''
}"
:class="{ dragging: drag }"
:showGuide="index === 0"
:chartConfig="item"
>
<BiBlank height="28" slot="top"></BiBlank>
<BiBlank height="28" slot="bottom"></BiBlank>
</BiChartBlock>
<BiTips v-if="guide.use && index === 0"></BiTips>
</div>
</transition-group>
</vue-draggable>
</div>
</template>
<script>
import BiBlank from '../commonComponents/blank.vue';
import BiChartBlock from '../commonComponents/chart-block.vue';
import BiTips from '../commonComponents/tips.vue';
import eventBus from '../eventBus/index';
import mixin from '../mixin/index';
import { getQueryVariable } from '../chart-type/common';
export default {
name: 'bi-single-choice',
mixins: [mixin],
components: {
BiBlank,
BiTips,
BiChartBlock,
'vue-draggable':
this.isPrint || getQueryVariable('print') == 1
? {
template: '<div><slot></slot></div>'
}
: require('vuedraggable')
},
props: {
singleChoice: {
type: Array,
default: () => []
},
pageWrap: Boolean,
disabled: Boolean
},
data() {
return {
drag: false,
groupName: `single-choice-chart-${parseInt(
Math.random() * new Date().getTime()
)}`,
copySingleChoice: []
};
},
computed: {
guideStepShow() {
return (index, step) =>
index === 0 && this.guide.use && this.guide.step == step;
}
},
methods: {
onStart() {
this.drag = true;
document
.getElementsByClassName('xrk-components-bi')[0]
.parentElement.parentElement.parentElement.scrollTo(
0,
this.$refs['bi-single-choice'].offsetTop
);
},
onEnd() {
this.drag = false;
this.$emit('sort', this.copySingleChoice);
},
getPageSize() {
const topDom = (this.$slots.default || [{}])[0].elm || {
offsetHeight: 0
};
const domArr = [
{
$el: topDom
},
...(this.$refs['bi-single-choice_item'] || []).map(item => {
let height = 0;
item.pervPage = item.$children.reduce(
(pre, { $el: { offsetHeight } }) => {
height += offsetHeight;
if (height >= 1697) {
pre += 1;
height = offsetHeight;
}
return pre;
},
0
);
return item;
})
];
const pageSizeInfo = {
pervHeight: 0,
pervPage: 0,
height: 0,
page: this.pageWrap ? 0 : 1
};
const catalogueInfoArr = [];
domArr.forEach(
({ $el: { offsetHeight }, title, pervPage = 0 }, index) => {
pageSizeInfo.height += offsetHeight;
if (this.pageWrap) {
if (index == 1) {
// 遍历到第二个时,如果存在顶部标题,则将两个高度相加(汇总标题和表格不做强制分页)
pageSizeInfo.pervHeight = offsetHeight + topDom.offsetHeight;
if (offsetHeight + topDom.offsetHeight > 1697) {
pageSizeInfo.page += 1;
}
} else {
pageSizeInfo.page += pageSizeInfo.pervPage + 1;
pageSizeInfo.pervPage = pervPage;
}
} else if (pageSizeInfo.height >= 1697) {
pageSizeInfo.page += 1;
pageSizeInfo.height = offsetHeight;
}
catalogueInfoArr.push({
name: (title || {}).name,
page: pageSizeInfo.page
});
}
);
this.$emit('page', {
pageSize: pageSizeInfo.page,
info: catalogueInfoArr
});
}
},
mounted() {
eventBus.$on('addStep', () => {
this.guide.step += 1;
});
eventBus.$on('hideGuide', () => {
this.guide.use = false;
});
},
watch: {
singleChoice: {
handler(v) {
this.copySingleChoice = v;
this.$nextTick(this.getPageSize);
},
deep: true,
immediate: true
}
}
};
</script>
<style lang="scss" scoped>
.bi-single-choice {
page-break-before: always;
&_group {
& > span {
display: block;
margin-top: 8px;
page-break-inside: avoid;
// & + span {
// }
&.chosen {
border: 2px solid #016cd6;
z-index: 9;
position: relative;
}
&.sortable-fallback {
height: 150px !important;
overflow: hidden;
}
}
&.wrap {
& > span {
& + span {
page-break-before: always;
}
}
}
}
&_item {
padding: 0 28px;
border-radius: 4px;
border: 1px solid #f4f4f4;
box-shadow: 0px 3px 6px rgba(27, 39, 64, 0.04);
background-color: #fff;
&_block {
page-break-inside: avoid;
// margin-top: 8px;
}
&.dragging {
height: 140px;
overflow: hidden;
}
}
}
</style>
Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!