feat: 测试报表功能

This commit is contained in:
caoqianming 2023-05-31 15:36:18 +08:00
parent a7c2c7478c
commit f2e1f450ef
14 changed files with 1895 additions and 6 deletions

View File

@ -19,15 +19,14 @@
"d3": "^7.6.1", "d3": "^7.6.1",
"dagre": "^0.8.5", "dagre": "^0.8.5",
"dagre-d3": "^0.6.4", "dagre-d3": "^0.6.4",
"echarts": "5.3.2",
"element-plus": "2.2.3",
"html2canvas": "^1.4.1",
"json-editor-vue3": "^1.0.6",
"xlsx": "^0.18.5",
"echarts": "5.4.1", "echarts": "5.4.1",
"element-plus": "2.2.32", "element-plus": "2.2.32",
"file-saver": "^2.0.5",
"html2canvas": "^1.4.1",
"json-editor-vue3": "^1.0.6",
"jspdf": "^2.5.1", "jspdf": "^2.5.1",
"nprogress": "0.2.0", "nprogress": "0.2.0",
"print-js": "^1.6.0",
"qrcodejs2": "0.0.2", "qrcodejs2": "0.0.2",
"sortablejs": "1.15.0", "sortablejs": "1.15.0",
"tinymce": "6.3.2", "tinymce": "6.3.2",
@ -38,6 +37,7 @@
"vuex": "4.1.0", "vuex": "4.1.0",
"xgplayer": "2.32.2", "xgplayer": "2.32.2",
"xgplayer-hls": "2.5.2", "xgplayer-hls": "2.5.2",
"xlsx": "^0.18.5",
"xlsx-style": "^0.8.13" "xlsx-style": "^0.8.13"
}, },
"devDependencies": { "devDependencies": {

92
src/api/model/bi.js Normal file
View File

@ -0,0 +1,92 @@
import config from "@/config"
import http from "@/utils/request"
/*BI接口*/
export default {
dataset: {
list: {
name: "获取数据集列表",
req: async function(data){
return await http.get(
`${config.API_URL}/bi/dataset/`,
data
);
}
},
item: {
name: "获取某个数据集详情",
req: async function(id){
return await http.get(
`${config.API_URL}/bi/dataset/${id}/`
);
}
},
update: {
name: "更新数据集",
req: async function(id, data){
return await http.put(
`${config.API_URL}/bi/dataset/${id}/`,
data);
}
},
create: {
name: "创建数据集",
req: async function(data){
return await http.post(
`${config.API_URL}/bi/dataset/`,
data);
}
},
exec: {
name: "执行",
req: async function(id, data){
return await http.post(
`${config.API_URL}/bi/dataset/${id}/exec/`,
data);
}
},
},
report: {
list: {
name: "获取列表",
req: async function(data){
return await http.get(
`${config.API_URL}/bi/report/`,
data
);
}
},
item: {
name: "获取详情",
req: async function(id){
return await http.get(
`${config.API_URL}/bi/report/${id}/`
);
}
},
update: {
name: "更新",
req: async function(id, data){
return await http.put(
`${config.API_URL}/bi/report/${id}/`,
data);
}
},
create: {
name: "创建",
req: async function(data){
return await http.post(
`${config.API_URL}/bi/report/`,
data);
}
},
exec: {
name: "执行",
req: async function(id, data){
return await http.post(
`${config.API_URL}/bi/report/${id}/exec/`,
data);
}
},
},
}

76
src/api/model/em.js Normal file
View File

@ -0,0 +1,76 @@
import config from "@/config"
import http from "@/utils/request"
/*EM接口*/
export default {
equipment: {
list: {
name: "获取列表",
req: async function(data){
return await http.get(
`${config.API_URL}/em/equipment/`,
data
);
}
},
item: {
name: "获取详情",
req: async function(id){
return await http.get(
`${config.API_URL}/em/equipment/${id}/`
);
}
},
update: {
name: "更新",
req: async function(id, data){
return await http.put(
`${config.API_URL}/em/equipment/${id}/`,
data);
}
},
create: {
name: "创建",
req: async function(data){
return await http.post(
`${config.API_URL}/em/equipment/`,
data);
}
}
},
mpoint: {
list: {
name: "获取列表",
req: async function(data){
return await http.get(
`${config.API_URL}/em/mpoint/`,
data
);
}
},
item: {
name: "获取详情",
req: async function(id){
return await http.get(
`${config.API_URL}/em/mpoint/${id}/`
);
}
},
update: {
name: "更新",
req: async function(id, data){
return await http.put(
`${config.API_URL}/em/mpoint/${id}/`,
data);
}
},
create: {
name: "创建",
req: async function(data){
return await http.post(
`${config.API_URL}/em/mpoint/`,
data);
}
}
},
}

View File

@ -93,9 +93,83 @@ const routes = [
"perms": ["userCenter"] "perms": ["userCenter"]
}, },
"component": "userCenter" "component": "userCenter"
},
]
},
{
"name": "bi",
"path": "/bi",
"meta": {
"title": "报表",
"icon": "el-icon-grid",
"type": "menu",
"perms": ["bi"]
},
"children": [
{
"name": "dataset",
"path": "/bi/dataset",
"meta": {
"title": "数据集",
"icon": "el-icon-grid",
"perms": ["dataset"]
},
"component": "bi/dataset"
},
{
"name": "graph",
"path": "/bi/graph",
"meta": {
"title": "测试图",
"icon": "el-icon-grid",
"perms": ["dataset"]
},
"component": "bi/graph"
} }
] ]
}, },
{
"name": "em",
"path": "/em",
"meta": {
"title": "设备",
"icon": "el-icon-grid",
"type": "menu",
"perms": ["em"]
},
"children": [
{
"name": "equipment",
"path": "/em/equipment",
"meta": {
"title": "生产设备",
"icon": "el-icon-grid",
"perms": ["equipment"]
},
"component": "em/equipment"
},
{
"name": "equipment2",
"path": "/em/equipment2",
"meta": {
"title": "计量设备",
"icon": "el-icon-grid",
"perms": ["equipment"]
},
"component": "em/equipment"
},
{
"name": "em",
"path": "/em/mpoint",
"meta": {
"title": "测点管理",
"icon": "el-icon-grid",
"perms": ["mpoint"]
},
"component": "em/equipment"
},
]
},
{ {
"name": "ecm", "name": "ecm",
"path": "/ecm", "path": "/ecm",

View File

@ -10,6 +10,8 @@ import store from './store'
import App from './App.vue' import App from './App.vue'
import * as ElementPlusIconsVue from '@element-plus/icons-vue' import * as ElementPlusIconsVue from '@element-plus/icons-vue'
import preventReClick from './utils/preventReClick' import preventReClick from './utils/preventReClick'
import Print from './utils/print2'
import Xlsx from './utils/xlsx'
const app = createApp(App); const app = createApp(App);
@ -19,7 +21,9 @@ app.use(ElementPlus);
app.use(i18n); app.use(i18n);
app.use(scui); app.use(scui);
app.use(ehsui); app.use(ehsui);
app.use(preventReClick) app.use(preventReClick);
app.use(Print);
app.use(Xlsx);
//挂载app //挂载app
app.mount('#app'); app.mount('#app');
for (const [key, component] of Object.entries(ElementPlusIconsVue)) { for (const [key, component] of Object.entries(ElementPlusIconsVue)) {

171
src/utils/print2.js Normal file
View File

@ -0,0 +1,171 @@
// 打印类属性、方法定义
/* eslint-disable */
const Print = function (dom, options) {
if (!(this instanceof Print)) return new Print(dom, options);
this.options = this.extend({
'noPrint': '.no-print'
}, options);
if ((typeof dom) === "string") {
this.dom = document.querySelector(dom);
} else {
this.isDOM(dom)
this.dom = this.isDOM(dom) ? dom : dom.$el;
}
this.init();
};
Print.prototype = {
init: function () {
var content = this.getStyle() + this.getHtml();
this.writeIframe(content);
},
extend: function (obj, obj2) {
for (var k in obj2) {
obj[k] = obj2[k];
}
return obj;
},
getStyle: function () {
var str = "",
styles = document.querySelectorAll('style,link');
for (var i = 0; i < styles.length; i++) {
str += styles[i].outerHTML;
}
str += "<style>" + (this.options.noPrint ? this.options.noPrint : '.no-print') + "{display:none;}</style>";
// 去除height100%样式,解决分页下,样式混乱问题
str += "<style>html,body,div{height: auto!important;}</style>";
return str;
},
getHtml: function () {
var inputs = document.querySelectorAll('input');
var textareas = document.querySelectorAll('textarea');
var selects = document.querySelectorAll('select');
var canvass = document.querySelectorAll('canvas');
for (var k = 0; k < inputs.length; k++) {
if (inputs[k].type == "checkbox" || inputs[k].type == "radio") {
if (inputs[k].checked == true) {
inputs[k].setAttribute('checked', "checked")
} else {
inputs[k].removeAttribute('checked')
}
} else if (inputs[k].type == "text") {
inputs[k].setAttribute('value', inputs[k].value)
} else {
inputs[k].setAttribute('value', inputs[k].value)
}
}
for (var k2 = 0; k2 < textareas.length; k2++) {
if (textareas[k2].type == 'textarea') {
textareas[k2].innerHTML = textareas[k2].value
}
}
for (var k3 = 0; k3 < selects.length; k3++) {
if (selects[k3].type == 'select-one') {
var child = selects[k3].children;
for (var i in child) {
if (child[i].tagName == 'OPTION') {
if (child[i].selected == true) {
child[i].setAttribute('selected', "selected")
} else {
child[i].removeAttribute('selected')
}
}
}
}
}
//canvass echars图表转为图片
for (var k4 = 0; k4 < canvass.length; k4++) {
var imageURL = canvass[k4].toDataURL("image/png");
var img = document.createElement("img");
img.src = imageURL;
img.setAttribute('style', 'max-width: 100%;');
img.className = 'isNeedRemove'
// canvass[k4].style.display = 'none'
// canvass[k4].parentNode.style.width = '100%'
// canvass[k4].parentNode.style.textAlign = 'center'
canvass[k4].parentNode.insertBefore(img,canvass[k4].nextElementSibling);
}
// 包裹要打印的元素
// fix: https://github.com/xyl66/vuePlugs_printjs/issues/36
// return this.wrapperRefDom(this.dom).outerHTML;
return this.dom.outerHTML;
},
// 向父级元素循环,包裹当前需要打印的元素
// 防止根级别开头的 css 选择器不生效
wrapperRefDom: function (refDom) {
let prevDom = null
let currDom = refDom
while (currDom && currDom.tagName.toLowerCase() !== 'body') {
if (prevDom) {
let element = currDom.cloneNode(false)
element.appendChild(prevDom)
prevDom = element
} else {
prevDom = currDom.cloneNode(true)
}
currDom = currDom.parentElement
}
return currDom.tagName.toLowerCase() === 'body' ? currDom : prevDom
},
writeIframe: function (content) {
var w, doc, iframe = document.createElement('iframe'),
f = document.body.appendChild(iframe);
iframe.id = "myIframe";
//iframe.style = "position:absolute;width:0;height:0;top:-10px;left:-10px;";
iframe.setAttribute('style', 'position:absolute;width:0;height:0;top:-10px;left:-10px;');
w = f.contentWindow || f.contentDocument;
doc = f.contentDocument || f.contentWindow.document;
doc.open();
doc.write(content);
doc.close();
var _this = this
iframe.onload = function(){
_this.toPrint(w);
setTimeout(function () {
document.body.removeChild(iframe)
}, 100)
}
},
toPrint: function (frameWindow) {
try {
setTimeout(function () {
frameWindow.focus();
try {
if (!frameWindow.document.execCommand('print', false, null)) {
frameWindow.print();
}
} catch (e) {
frameWindow.print();
}
frameWindow.close();
}, 10);
} catch (err) {
console.log('err', err);
}
},
isDOM: (typeof HTMLElement === 'object') ?
function (obj) {
return obj instanceof HTMLElement;
} :
function (obj) {
return obj && typeof obj === 'object' && obj.nodeType === 1 && typeof obj.nodeName === 'string';
}
};
export default (app) => {
app.config.globalProperties.$PRINT = Print;
}

11
src/utils/xlsx.js Normal file
View File

@ -0,0 +1,11 @@
import * as XLSX from "xlsx";
const ExportExcel = function(domId, name) {
const table = document.querySelector(domId);
const workbook = XLSX.utils.table_to_book(table);
XLSX.writeFile(workbook, `${name}.xlsx`);
}
export default (app) => {
app.config.globalProperties.$XLSX = ExportExcel;
}

230
src/views/bi/dataset.vue Normal file
View File

@ -0,0 +1,230 @@
<template>
<el-container>
<el-aside width="40%">
<el-container>
<el-header>
<div class="left-panel">
<el-button type="primary" icon="el-icon-plus" @click="add" v-auth="'dataset.create'"></el-button>
</div>
<div class="right-panel">
<div class="right-panel-search">
<el-input
v-model="query.search"
placeholder="名称"
clearable
@keyup.enter="handleQuery"
></el-input>
<el-button
type="primary"
icon="el-icon-search"
@click="handleQuery"
></el-button>
</div>
</div>
</el-header>
<el-main class="nopadding">
<scTable
ref="table"
:apiObj="apiObj"
row-key="id"
stripe
>
<el-table-column label="#" type="index" width="50"></el-table-column>
<el-table-column label="名称" prop="name" width="200" :show-overflow-tooltip="true"></el-table-column>
<el-table-column label="sql语句" prop="sql_query" :show-overflow-tooltip="true"></el-table-column>
<el-table-column label="操作" fixed="right" align="left" width="200">
<template #default="scope">
<el-button
type="primary"
plain
size="small"
@click="handleShow(scope.row)"
v-auth="'dataset.exec'"
>预览</el-button
>
<el-button
plain
type="warning"
size="small"
@click="table_edit(scope.row, scope.$index)"
v-auth="'dataset.update'"
>编辑</el-button
>
<el-popconfirm
title="确定删除吗?"
@confirm="table_del(scope.row, scope.$index)"
>
<template #reference>
<el-button plain type="danger" size="small" v-auth="'dataset.delete'">删除</el-button>
</template>
</el-popconfirm>
</template>
</el-table-column>
</scTable>
</el-main>
</el-container>
</el-aside>
<el-main>
<div style="background-color: white;">
<scEcharts height="360px" :option="myOption" v-if="chartShow"></scEcharts>
</div>
</el-main>
</el-container>
<save-dialog
v-if="dialog.save"
ref="saveDialog"
@success="handleSaveSuccess"
@closed="dialog.save = false"
></save-dialog>
</template>
<script>
import scEcharts from "@/components/scEcharts";
import saveDialog from "./dataset_form.vue";
export default {
name: "dataset",
components: {
saveDialog,
scEcharts,
},
data() {
return {
chartShow: false,
myOption: null,
dialog: {
save: false,
permission: false,
},
adminform:{
admin: null,
username:"",
},
apiObj: this.$API.bi.dataset.list,
query: {},
selection: [],
search: {
keyword: null,
},
datasetID:"",
adminvisible:false,
//
rules: {
phone: [
{required: true, message: '请输入'}
],
name: [
{required: true, message: '请输入'}
],
username: [
{required: true, message: '请输入'}
],
},
};
},
methods: {
handleShow(row) {
// this.$router.push({
// path: "graph",
// query: {
// datasetId: row.id,
// },
// });
this.chartShow = false;
this.$API.bi.dataset.exec
.req(row.id)
.then((res) => {
this.myOption = JSON.parse(res.echart_options);
this.chartShow = true;
});
},
//
add() {
this.dialog.save = true;
this.$nextTick(() => {
this.$refs.saveDialog.open("add");
});
},
getAdmin(data){
this.adminform.admin=data.id;
this.adminform.admin_name=data.name;
this.adminform.name = data.name;
this.adminform.phone = data.phone;
this.adminform.username = data.username;
},
//
table_edit(row) {
this.dialog.save = true;
this.$nextTick(() => {
this.$refs.saveDialog.open("edit").setData(row);
});
},
//
table_show(row) {
this.dialog.save = true;
this.$nextTick(() => {
this.$refs.saveDialog.open("show").setData(row);
});
},
//
table_admin(row)
{
this.adminvisible=true;
this.datasetID=row.id;
},
//FROM
submitAdmin(){
this.$API.rpm.dataset.admin.req(
this.datasetID,
this.adminform
).then((res) => {
this.$message.success("账号分配成功");
this.adminvisible = false;
this.$refs.table.refresh()
})
.catch((err) => {
return err;
});;
},
//
permission() {
this.dialog.permission = true;
this.$nextTick(() => {
this.$refs.permissionDialog.open();
});
},
//
async table_del(row) {
this.$API.rpm.dataset.delete
.req(row.id)
.then((res) => {
this.$message.success("删除成功");
return res;
})
.catch((err) => {
return err;
});
},
//
handleSaveSuccess(data, mode) {
if (mode == "add") {
this.$refs.table.refresh();
} else if (mode == "edit") {
this.$refs.table.refresh();
}
},
handleQuery() {
this.$refs.table.queryData(this.query)
},
resetQuery() {
this.query = {};
},
},
};
</script>

View File

@ -0,0 +1,162 @@
<template>
<el-drawer
:title="titleMap[mode]"
v-model="visible"
:size="1000"
destroy-on-close
@closed="$emit('closed')"
>
<el-container v-loading="loading">
<el-main style="padding: 0 20px 20px 20px">
<el-form
ref="dialogForm"
:model="form"
:rules="rules"
:disabled="mode == 'show'"
label-width="80px"
>
<el-row>
<el-col :md="8" :sm="12" :xs="24">
<el-form-item label="名称" prop="name">
<el-input
v-model="form.name"
type="text"
clearable
></el-input>
</el-form-item>
</el-col>
<el-col :md="8" :sm="12" :xs="24">
<el-form-item label="编号" prop="code">
<el-input
v-model="form.code"
type="text"
clearable
></el-input>
</el-form-item>
</el-col>
<el-col :md="24" :sm="24" :xs="24">
<el-form-item label="说明">
<el-input
v-model="form.description"
clearable
type="textarea"
></el-input>
</el-form-item>
</el-col>
<el-col :md="24" :sm="24" :xs="24">
<el-form-item label="sql语句">
<el-input
v-model="form.sql_query"
clearable
type="textarea"
:rows="10"
></el-input>
</el-form-item>
</el-col>
<el-col :md="24" :sm="24" :xs="24">
<el-form-item label="图表配置">
<el-input
v-model="form.echart_options"
clearable
type="textarea"
:rows="10"
></el-input>
</el-form-item>
</el-col>
</el-row>
</el-form>
</el-main>
<el-footer>
<el-button type="primary" :loading="isSaveing" @click="submit"
>保存</el-button
>
<el-button @click="visible = false">取消</el-button>
</el-footer>
</el-container>
</el-drawer>
</template>
<script>
export default {
emits: ["success", "closed"],
data() {
return {
loading: false,
mode: "add",
titleMap: {
add: "新增",
edit: "编辑",
show: "查看",
},
form: {},
rules: {
name: [{ required: true, message: "请输入" }],
},
visible: false,
isSaveing: false,
selectionFilters: [],
setFiltersVisible: false,
belong_dept_options: []
};
},
mounted() {
},
methods: {
//
open(mode = "add") {
this.mode = mode;
this.visible = true;
return this;
},
//
submit() {
this.$refs.dialogForm.validate(async (valid) => {
if (valid) {
this.isSaveing = true;
try {
var res;
if (this.mode == "add") {
res = await this.$API.bi.dataset.create.req(this.form);
} else if (this.mode == "edit") {
res = await this.$API.bi.dataset.update.req(
this.form.id,
this.form
);
}
this.isSaveing = false;
this.$emit("success", this.form, this.mode);
this.visible = false;
this.$message.success("操作成功");
return res;
} catch (err) {
//
this.isSaveing = false;
return err;
}
}
});
},
//
setData(data) {
// this.loading = true
// const params = {
// id: data.id
// }
// setTimeout(async ()=>{
// var res = await this.$API.system.table.info.get(params)
// this.loading = false
// this.form = res.data
// },400)
Object.assign(this.form, data);
},
//
setFilters(filters) {
this.selectionFilters = filters;
this.setFiltersVisible = true;
},
},
};
</script>
<style>
</style>

349
src/views/bi/graph.vue Normal file
View File

@ -0,0 +1,349 @@
<template>
<div class="container a4-endwise" style="margin: auto; background-color: white;" >
<!-- :class="[ isLand? 'a4-broadwise' : '', 'a4-endwise']" -->
<div style="padding: 8px; display: flex;">
<el-select v-model="isLand" style="margin-right: auto; width: 80px; margin-left:4px">
<el-option
v-for="item in viewOptions"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</el-select>
<el-select v-model="isLand" style="margin-left: auto; width: 80px; margin-right:4px">
<el-option
v-for="item in viewOptions"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</el-select>
<el-button
type="primary"
@click="exportExcel()"
:loading = "exportLoading"
>导出xlsx</el-button
>
<el-button
type="primary"
@click="handlePrint"
>打印</el-button
>
</div>
<div id="myReport" style="padding: 20px">
<table id="myTable" style="width:100%" v-loading="tableLoading">
<thead>
<tr>
<th rowspan="2">编号</th>
<th rowspan="2">姓名</th>
<th colspan="3">成绩</th>
</tr>
<tr>
<th>语文</th>
<th>数学</th>
<th>外语</th>
</tr>
</thead>
<tbody>
<tr>
<td>1</td>
<td>张三</td>
<td>80</td>
<td>90</td>
</tr>
<tr>
<td>2</td>
<td>李四</td>
<td>75</td>
<td>85</td>
</tr>
<tr>
<td>2</td>
<td>李四</td>
<td>75</td>
<td>85</td>
</tr>
<tr>
<td>2</td>
<td>李四</td>
<td>75</td>
<td>85</td>
</tr>
<tr>
<td>2</td>
<td>李四</td>
<td>75</td>
<td>85</td>
</tr>
<tr>
<td>2</td>
<td>李四</td>
<td>75</td>
<td>85</td>
</tr>
<tr>
<td>2</td>
<td>李四</td>
<td>75</td>
<td>85</td>
</tr>
<tr>
<td>2</td>
<td>李四</td>
<td>75</td>
<td>85</td>
</tr>
<tr>
<td>2</td>
<td>李四</td>
<td>75</td>
<td>85</td>
</tr>
<tr>
<td>2</td>
<td>李四</td>
<td>75</td>
<td>85</td>
</tr>
<tr>
<td>2</td>
<td>李四</td>
<td>75</td>
<td>85</td>
</tr>
<tr>
<td>2</td>
<td>李四</td>
<td>75</td>
<td>85</td>
</tr>
<tr>
<td>2</td>
<td>李四</td>
<td>75</td>
<td>85</td>
</tr>
<tr>
<td>2</td>
<td>李四</td>
<td>75</td>
<td>85</td>
</tr>
<tr>
<td>2</td>
<td>李四</td>
<td>75</td>
<td>85</td>
</tr>
<tr>
<td>2</td>
<td>李四</td>
<td>75</td>
<td>85</td>
</tr>
<tr>
<td>2</td>
<td>李四</td>
<td>75</td>
<td>85</td>
</tr>
<tr>
<td>2</td>
<td>李四</td>
<td>75</td>
<td>85</td>
</tr>
<tr>
<td>2</td>
<td>李四</td>
<td>75</td>
<td>85</td>
</tr>
<tr>
<td>2</td>
<td>李四</td>
<td>75</td>
<td>85</td>
</tr>
<tr>
<td>2</td>
<td>李四</td>
<td>75</td>
<td>85</td>
</tr>
<tr>
<td>2</td>
<td>李四</td>
<td>75</td>
<td>85</td>
</tr>
<tr>
<td>2</td>
<td>李四</td>
<td>75</td>
<td>85</td>
</tr>
<tr>
<td>2</td>
<td>李四</td>
<td>75</td>
<td>85</td>
</tr>
<tr>
<td>2</td>
<td>李四</td>
<td>75</td>
<td>85</td>
</tr>
<tr>
<td>2</td>
<td>李四</td>
<td>75</td>
<td>85</td>
</tr>
<tr>
<td>2</td>
<td>李四</td>
<td>75</td>
<td>85</td>
</tr>
<tr>
<td>2</td>
<td>李四</td>
<td>75</td>
<td>85</td>
</tr>
<tr>
<td>2</td>
<td>李四</td>
<td>75</td>
<td>85</td>
</tr>
<tr>
<td>2</td>
<td>李四</td>
<td>75</td>
<td>85</td>
</tr>
<tr>
<td>2</td>
<td>李四</td>
<td>75</td>
<td>85</td>
</tr>
<tr>
<td>2</td>
<td>李四</td>
<td>75</td>
<td>85</td>
</tr>
</tbody>
</table>
</div>
<scEcharts height="360px" :option="myOption" style="margin-top: 8px"></scEcharts>
</div>
</template>
<script>
import scEcharts from "@/components/scEcharts";
export default {
title: "测试图表",
components: {
scEcharts,
},
data() {
return {
tableLoading: false,
isLand: false,
viewOptions: [
{ label: "横向", value: true },
{ label: "纵向", value: false },
],
exportLoading: false,
tableData: [
{
day: 11,
name: "Tom",
month: 111,
year: 1111,
},
],
myOption: {},
};
},
created() {
this.initGraph();
},
methods: {
handlePrint() {
this.$PRINT('#myReport');
},
initGraph() {
this.tableLoading = true;
this.$API.bi.dataset.exec
.req("3322567213885833216")
.then((res) => {
this.myOption = JSON.parse(res.echart_options);
})
.finally(() => {
this.tableLoading = false;
});
},
exportExcel() {
this.exportLoading = true;
this.$XLSX('#myTable', 'test')
this.exportLoading = false;
// try {
// // const $e = this.$refs["myTable"].$el;
// let $table = document.querySelector("#print-area");
// if (!$table) {
// $table = $e;
// }
// const wb = XLSX.utils.table_to_book($table, { raw: true });
// const wbout = XLSX.write(wb, {
// bookType: "xlsx",
// bookSST: true,
// type: "array",
// });
// FileSaver.saveAs(
// new Blob([wbout], { type: "application/octet-stream" }),
// `${excelName}.xlsx`
// );
// } catch (e) {
// if (typeof console !== "undefined") console.error(e);
// }
},
},
};
</script>
<style scoped>
table {
border-collapse: collapse;
width: 100%;
}
th,
td {
border: 1px solid black;
padding: 8px;
text-align: left;
}
.a4-endwise {
width: 1075px;
/* height: 1567px; */
/* border: 1px #000 solid; */
overflow: hidden;
padding: 0;
word-break: break-all;
}
.a4-broadwise {
width: 1569px;
/* height: 1073px; */
/* border: 1px #000 solid; */
overflow: hidden;
padding: 0;
word-break: break-all;
}
</style>

190
src/views/bi/report.vue Normal file
View File

@ -0,0 +1,190 @@
<template>
<el-container>
<el-header>
<div class="left-panel">
<el-button type="primary" icon="el-icon-plus" @click="add" v-auth="'report.create'"></el-button>
</div>
<div class="right-panel">
<div class="right-panel-search">
<el-input
v-model="query.search"
placeholder="名称/标识"
clearable
@keyup.enter="handleQuery"
></el-input>
<el-button
type="primary"
icon="el-icon-search"
@click="handleQuery"
></el-button>
</div>
</div>
</el-header>
<el-main class="nopadding">
<scTable
ref="table"
:apiObj="apiObj"
row-key="id"
stripe
>
<el-table-column label="#" type="index" width="50"></el-table-column>
<el-table-column label="名称" prop="name" width="300" :show-overflow-tooltip="true"></el-table-column>
<el-table-column label="标识" prop="code" width="300" :show-overflow-tooltip="true"></el-table-column>
<el-table-column label="操作" fixed="right" align="left" width="200">
<template #default="scope">
<el-button
link
type="warning"
size="small"
@click="table_edit(scope.row, scope.$index)"
v-auth="'report.update'"
>编辑</el-button
>
<el-popconfirm
title="确定删除吗?"
@confirm="table_del(scope.row, scope.$index)"
>
<template #reference>
<el-button link type="danger" size="small" v-auth="'report.delete'">删除</el-button>
</template>
</el-popconfirm>
</template>
</el-table-column>
</scTable>
</el-main>
</el-container>
<save-dialog
v-if="dialog.save"
ref="saveDialog"
@success="handleSaveSuccess"
@closed="dialog.save = false"
></save-dialog>
</template>
<script>
import saveDialog from "./report_form.vue";
export default {
name: "report",
components: {
saveDialog,
},
data() {
return {
dialog: {
save: false,
permission: false,
},
apiObj: this.$API.bi.report.list,
query: {},
selection: [],
search: {
keyword: null,
},
reportID:"",
adminvisible:false,
//
rules: {
phone: [
{required: true, message: '请输入'}
],
name: [
{required: true, message: '请输入'}
],
username: [
{required: true, message: '请输入'}
],
},
};
},
methods: {
//
add() {
this.dialog.save = true;
this.$nextTick(() => {
this.$refs.saveDialog.open("add");
});
},
getAdmin(data){
this.adminform.admin=data.id;
this.adminform.admin_name=data.name;
this.adminform.name = data.name;
this.adminform.phone = data.phone;
this.adminform.username = data.username;
},
//
table_edit(row) {
this.dialog.save = true;
this.$nextTick(() => {
this.$refs.saveDialog.open("edit").setData(row);
});
},
//
table_show(row) {
this.dialog.save = true;
this.$nextTick(() => {
this.$refs.saveDialog.open("show").setData(row);
});
},
//
table_admin(row)
{
this.adminvisible=true;
this.reportID=row.id;
},
//FROM
submitAdmin(){
this.$API.rpm.report.admin.req(
this.reportID,
this.adminform
).then((res) => {
this.$message.success("账号分配成功");
this.adminvisible = false;
this.$refs.table.refresh()
})
.catch((err) => {
return err;
});;
},
//
permission() {
this.dialog.permission = true;
this.$nextTick(() => {
this.$refs.permissionDialog.open();
});
},
//
async table_del(row) {
this.$API.rpm.report.delete
.req(row.id)
.then((res) => {
this.$message.success("删除成功");
return res;
})
.catch((err) => {
return err;
});
},
//
handleSaveSuccess(data, mode) {
if (mode == "add") {
this.$refs.table.refresh();
} else if (mode == "edit") {
this.$refs.table.refresh();
}
},
handleQuery() {
this.$refs.table.queryData(this.query)
},
resetQuery() {
this.query = {};
},
},
};
</script>

View File

@ -0,0 +1,159 @@
<template>
<el-dialog
:title="titleMap[mode]"
v-model="visible"
:size="1000"
destroy-on-close
@closed="$emit('closed')"
>
<el-container v-loading="loading">
<el-main style="padding: 0 20px 20px 20px">
<el-form
ref="dialogForm"
:model="form"
:rules="rules"
:disabled="mode == 'show'"
label-width="80px"
>
<el-row>
<el-col :md="8" :sm="12" :xs="24">
<el-form-item label="名称" prop="name">
<el-input
v-model="form.name"
style="width:100%"
type="text"
clearable
></el-input>
</el-form-item>
</el-col>
<el-col :md="24" :sm="24" :xs="24">
<el-form-item label="标识">
<el-input
v-model="form.code"
type="text"
></el-input>
</el-form-item>
</el-col>
<el-col :md="24" :sm="24" :xs="24">
<el-form-item label="数据集">
<el-transfer v-model="form.datasets" :data="datasetOptions" :titles="['可选', '已选']" filterable/>
</el-form-item>
</el-col>
<el-col :md="24" :sm="24" :xs="24">
<el-form-item label="js方法">
<el-input
v-model="form.js_function"
clearable
type="textarea"
:rows="4"
></el-input>
</el-form-item>
</el-col>
</el-row>
</el-form>
</el-main>
<el-footer style="text-align: right;">
<el-button type="primary" :loading="isSaveing" @click="submit"
>保存</el-button
>
<el-button @click="visible = false">取消</el-button>
</el-footer>
</el-container>
</el-dialog>
</template>
<script>
export default {
emits: ["success", "closed"],
data() {
return {
datasetOptions:[],
loading: false,
mode: "add",
titleMap: {
add: "新增",
edit: "编辑",
show: "查看",
},
form: {},
rules: {
name: [{ required: true, message: "请输入" }],
},
visible: false,
isSaveing: false,
selectionFilters: [],
setFiltersVisible: false,
belong_dept_options: []
};
},
mounted() {
this.getDatasets()
},
methods: {
getDatasets() {
this.$API.bi.dataset.list.req({page:0}).then(res=>{
let datasetOptions = []
for(let i=0; i<res.length; i++){
datasetOptions.push({key: res[i].id, label: res[i].name, disabled: false})
}
this.datasetOptions = datasetOptions
})
},
//
open(mode = "add") {
this.mode = mode;
this.visible = true;
return this;
},
//
submit() {
this.$refs.dialogForm.validate(async (valid) => {
if (valid) {
this.isSaveing = true;
try {
var res;
if (this.mode == "add") {
res = await this.$API.bi.report.create.req(this.form);
} else if (this.mode == "edit") {
res = await this.$API.bi.report.update.req(
this.form.id,
this.form
);
}
this.isSaveing = false;
this.$emit("success", this.form, this.mode);
this.visible = false;
this.$message.success("操作成功");
return res;
} catch (err) {
//
this.isSaveing = false;
return err;
}
}
});
},
//
setData(data) {
// this.loading = true
// const params = {
// id: data.id
// }
// setTimeout(async ()=>{
// var res = await this.$API.system.table.info.get(params)
// this.loading = false
// this.form = res.data
// },400)
Object.assign(this.form, data);
},
//
setFilters(filters) {
this.selectionFilters = filters;
this.setFiltersVisible = true;
},
},
};
</script>
<style>
</style>

171
src/views/em/equipment.vue Normal file
View File

@ -0,0 +1,171 @@
<template>
<el-container>
<el-header>
<div class="left-panel">
<el-button type="primary" icon="el-icon-plus" @click="add" v-auth="'rparty.create'"></el-button>
<!-- <el-button type="danger" plain icon="el-icon-delete" :disabled="selection.length==0" @click="batch_del"></el-button>
<el-button type="primary" plain :disabled="selection.length!=1" @click="permission">权限设置</el-button> -->
</div>
<div class="right-panel">
<div class="right-panel-search">
<el-input
v-model="query.search"
placeholder="名称"
clearable
@keyup.enter="handleQuery"
></el-input>
<el-button
type="primary"
icon="el-icon-search"
@click="handleQuery"
></el-button>
</div>
</div>
</el-header>
<el-main class="nopadding">
<scTable
ref="table"
:apiObj="apiObj"
row-key="id"
stripe
>
<el-table-column label="#" type="index" width="50"></el-table-column>
<el-table-column label="名称" prop="name" width="240" :show-overflow-tooltip="true"></el-table-column>
<el-table-column label="信用代码" prop="number" width="180">
</el-table-column>
<el-table-column
label="联系人"
prop="contacter"
></el-table-column>
<el-table-column
label="联系电话"
prop="phone"
></el-table-column>
<el-table-column
label="所属部门"
prop="belong_dept"
width="180"
>
<template #default="scope">
{{scope.row.belong_dept_name}}
</template>
</el-table-column>
<el-table-column
label="管理员"
>
<template #default="scope">
<span v-if="scope.row.admin">{{ scope.row.admin_.name }}-{{scope.row.admin_.phone}}</span>
</template>
</el-table-column>
<el-table-column label="操作" fixed="right" align="left" width="200">
<template #default="scope">
<el-button
link
type="primary"
size="small"
@click="table_show(scope.row, scope.$index)"
>查看</el-button
>
<el-button
link
type="warning"
size="small"
@click="table_edit(scope.row, scope.$index)"
v-auth="'rparty.update'"
>编辑</el-button
>
<el-popconfirm
title="确定删除吗?"
@confirm="table_del(scope.row, scope.$index)"
>
<template #reference>
<el-button link type="danger" size="small" v-auth="'rparty.delete'">删除</el-button>
</template>
</el-popconfirm>
</template>
</el-table-column>
</scTable>
</el-main>
</el-container>
<save-dialog
v-if="dialog.save"
ref="saveDialog"
@success="handleSaveSuccess"
@closed="dialog.save = false"
></save-dialog>
</template>
<script>
import saveDialog from "./equipment_form.vue";
export default {
name: "rparty",
components: {
saveDialog,
},
data() {
return {
dialog: {
save: false,
permission: false,
},
apiObj: this.$API.rpm.rparty.list,
query: {},
selection: [],
};
},
methods: {
//
add() {
this.dialog.save = true;
this.$nextTick(() => {
this.$refs.saveDialog.open("add");
});
},
//
table_edit(row) {
this.dialog.save = true;
this.$nextTick(() => {
this.$refs.saveDialog.open("edit").setData(row);
});
},
//
table_show(row) {
this.dialog.save = true;
this.$nextTick(() => {
this.$refs.saveDialog.open("show").setData(row);
});
},
//
async table_del(row) {
this.$API.rpm.rparty.delete
.req(row.id)
.then((res) => {
this.$message.success("删除成功");
return res;
})
.catch((err) => {
return err;
});
},
//
handleSaveSuccess(data, mode) {
if (mode == "add") {
this.$refs.table.refresh();
} else if (mode == "edit") {
this.$refs.table.refresh();
}
},
handleQuery() {
this.$refs.table.queryData(this.query)
},
resetQuery() {
this.query = {};
},
},
};
</script>

View File

@ -0,0 +1,200 @@
<template>
<el-drawer
:title="titleMap[mode]"
v-model="visible"
:size="1000"
destroy-on-close
@closed="$emit('closed')"
>
<el-container v-loading="loading">
<el-main style="padding: 0 20px 20px 20px">
<el-form
ref="dialogForm"
:model="form"
:rules="rules"
:disabled="mode == 'show'"
label-width="80px"
>
<el-row>
<el-col :md="8" :sm="12" :xs="24">
<el-form-item label="公司名称" prop="name">
<el-input
v-model="form.name"
type="text"
clearable
:disabled="mode != 'add'"
></el-input>
</el-form-item>
</el-col>
<el-col :md="8" :sm="12" :xs="24">
<el-form-item label="信用代码" prop="number">
<el-input
v-model="form.number"
type="text"
clearable
></el-input>
</el-form-item>
</el-col>
<el-col :md="8" :sm="12" :xs="24">
<el-form-item label="法人">
<el-input v-model="form.lawer" type="text" clearable></el-input>
</el-form-item>
</el-col>
<el-col :md="8" :sm="12" :xs="24">
<el-form-item label="联系人" prop="contacter">
<el-input
v-model="form.contacter"
type="text"
clearable
></el-input>
</el-form-item>
</el-col>
<el-col :md="8" :sm="12" :xs="24">
<el-form-item label="联系电话" prop="phone">
<el-input v-model="form.phone" type="text" clearable></el-input>
</el-form-item>
</el-col>
<el-col :md="8" :sm="12" :xs="24">
<el-form-item label="联系邮箱">
<el-input v-model="form.email" type="text" clearable></el-input>
</el-form-item>
</el-col>
<el-col :md="12" :sm="12" :xs="24">
<el-form-item label="归属部门">
<el-cascader
v-model="form.belong_dept"
:options="belong_dept_options"
:props="{
expandTrigger: 'hover', //
label: 'label', //
value: 'value', //
checkStrictly: true,
emitPath: false, // false
}"
clearable
style="width: 100%;">
</el-cascader>
</el-form-item>
</el-col>
<el-col :md="24" :sm="24" :xs="24">
<el-form-item label="企业地址">
<el-input v-model="form.address" clearable></el-input>
</el-form-item>
</el-col>
<el-col :md="24" :sm="24" :xs="24">
<el-form-item label="其他说明">
<el-input
v-model="form.description"
clearable
type="textarea"
></el-input>
</el-form-item>
</el-col>
</el-row>
</el-form>
</el-main>
<el-footer>
<el-button type="primary" :loading="isSaveing" @click="submit"
>保存</el-button
>
<el-button @click="visible = false">取消</el-button>
</el-footer>
</el-container>
</el-drawer>
</template>
<script>
import {genTree} from "@/utils/verificate";
export default {
emits: ["success", "closed"],
data() {
return {
loading: false,
mode: "add",
titleMap: {
add: "新增",
edit: "编辑",
show: "查看",
},
form: {},
rules: {
name: [{ required: true, message: "请输入" }],
number: [{ required: true, message: "请输入" }],
contacter: [{ required: true, message: "请输入" }],
phone: [{ required: true, message: "请输入" }],
},
visible: false,
isSaveing: false,
selectionFilters: [],
setFiltersVisible: false,
belong_dept_options: []
};
},
mounted() {
this.getDeptOptions()
},
methods: {
getDeptOptions() {
this.$API.system.dept.list.req({page:0, type__in:'dept'}).then(res=>{
this.belong_dept_options = genTree(res);
})
},
//
open(mode = "add") {
this.mode = mode;
this.visible = true;
return this;
},
//
submit() {
this.$refs.dialogForm.validate(async (valid) => {
if (valid) {
this.isSaveing = true;
try {
var res;
if (this.mode == "add") {
res = await this.$API.rpm.rparty.create.req(this.form);
} else if (this.mode == "edit") {
res = await this.$API.rpm.rparty.update.req(
this.form.id,
this.form
);
}
this.isSaveing = false;
this.$emit("success", this.form, this.mode);
this.visible = false;
this.$message.success("操作成功");
return res;
} catch (err) {
//
this.isSaveing = false;
return err;
}
}
});
},
//
setData(data) {
// this.loading = true
// const params = {
// id: data.id
// }
// setTimeout(async ()=>{
// var res = await this.$API.system.table.info.get(params)
// this.loading = false
// this.form = res.data
// },400)
Object.assign(this.form, data);
},
//
setFilters(filters) {
this.selectionFilters = filters;
this.setFiltersVisible = true;
},
},
};
</script>
<style>
</style>