用户管理添加导出到文件;一些改动;删除多余页面
This commit is contained in:
parent
14907e3e26
commit
ac885fb06b
@ -35,7 +35,7 @@ public class FieldBuilder {
|
|||||||
* @param addType 新增弹窗中该字段显示为什么类型 <br>
|
* @param addType 新增弹窗中该字段显示为什么类型 <br>
|
||||||
* @param editType 修改弹窗中该字段显示为什么类型 <br>
|
* @param editType 修改弹窗中该字段显示为什么类型 <br>
|
||||||
* @param fieldRuleListBuilder 提交时的表单验证 <br>
|
* @param fieldRuleListBuilder 提交时的表单验证 <br>
|
||||||
* @param mockDataPattern mock数据正则 <br>
|
* @param mockDataPattern mock数据正则 <a href="http://mockjs.com/examples.html">文档</a> <br>
|
||||||
* @return FieldBuilder
|
* @return FieldBuilder
|
||||||
*/
|
*/
|
||||||
public FieldBuilder add(String field, String prop, String fieldName, Object defaultValue,
|
public FieldBuilder add(String field, String prop, String fieldName, Object defaultValue,
|
||||||
|
@ -23,6 +23,9 @@ import org.springframework.beans.factory.annotation.Autowired;
|
|||||||
import org.springframework.stereotype.Controller;
|
import org.springframework.stereotype.Controller;
|
||||||
import org.springframework.web.bind.annotation.*;
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
|
import java.text.SimpleDateFormat;
|
||||||
|
import java.util.Calendar;
|
||||||
|
import java.util.Date;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
@ -92,6 +95,9 @@ public class UserController {
|
|||||||
// 新增、修改弹窗时,使用该列作为主键列进行操作
|
// 新增、修改弹窗时,使用该列作为主键列进行操作
|
||||||
String idFieldName = "id";
|
String idFieldName = "id";
|
||||||
|
|
||||||
|
// 当前管理页面
|
||||||
|
String pageName = "用户管理";
|
||||||
|
|
||||||
// 指定前端表格显示列
|
// 指定前端表格显示列
|
||||||
JSONArray columns = FieldBuilder.create()
|
JSONArray columns = FieldBuilder.create()
|
||||||
.add("username", "username", "账号", "",
|
.add("username", "username", "账号", "",
|
||||||
@ -185,6 +191,7 @@ public class UserController {
|
|||||||
map.put("columns", columns);
|
map.put("columns", columns);
|
||||||
map.put("fieldMapper", fieldMapper);
|
map.put("fieldMapper", fieldMapper);
|
||||||
map.put("idFieldName", idFieldName);
|
map.put("idFieldName", idFieldName);
|
||||||
|
map.put("pageName", pageName);
|
||||||
|
|
||||||
// 返回结果
|
// 返回结果
|
||||||
return Res.success(map);
|
return Res.success(map);
|
||||||
@ -213,6 +220,7 @@ public class UserController {
|
|||||||
}
|
}
|
||||||
String passwordHash = DigestUtils.sha512Hex(password);
|
String passwordHash = DigestUtils.sha512Hex(password);
|
||||||
user.setPassword(passwordHash);
|
user.setPassword(passwordHash);
|
||||||
|
user.setId(null);
|
||||||
userService.addUser(user);
|
userService.addUser(user);
|
||||||
} else {
|
} else {
|
||||||
// 修改用户
|
// 修改用户
|
||||||
@ -250,4 +258,28 @@ public class UserController {
|
|||||||
boolean b = userService.deleteUser(existUser.getId());
|
boolean b = userService.deleteUser(existUser.getId());
|
||||||
return Res.success(b);
|
return Res.success(b);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 导出用户列表
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
@GetMapping("/manage/exportUserList")
|
||||||
|
@ResponseBody
|
||||||
|
public Res exportUserList(UserVO userVO) {
|
||||||
|
List<User> userList = userService.getUserList(userVO);
|
||||||
|
List<UserVO> userVOList = UserVO.convertFrom(userList);
|
||||||
|
|
||||||
|
// 当前时间
|
||||||
|
Date now = Calendar.getInstance().getTime();
|
||||||
|
SimpleDateFormat format = new SimpleDateFormat("yyyyMMdd_HHmmss");
|
||||||
|
String dateTime = format.format(now);
|
||||||
|
|
||||||
|
HashMap<String, Object> map = new HashMap<>();
|
||||||
|
map.put("list", userVOList);
|
||||||
|
map.put("sheetName", "用户表-" + System.currentTimeMillis());
|
||||||
|
map.put("fileName", "用户表_导出时间_" + dateTime);
|
||||||
|
|
||||||
|
return Res.success(map);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
21
frontend/components.d.ts
vendored
21
frontend/components.d.ts
vendored
@ -9,16 +9,10 @@ declare module '@vue/runtime-core' {
|
|||||||
export interface GlobalComponents {
|
export interface GlobalComponents {
|
||||||
Calender: typeof import('./src/components/calender.vue')['default']
|
Calender: typeof import('./src/components/calender.vue')['default']
|
||||||
ContextMenu: typeof import('./src/components/context-menu.vue')['default']
|
ContextMenu: typeof import('./src/components/context-menu.vue')['default']
|
||||||
ElAffix: typeof import('element-plus/es')['ElAffix']
|
ElAlert: typeof import('element-plus/es')['ElAlert']
|
||||||
ElAvatar: typeof import('element-plus/es')['ElAvatar']
|
ElAvatar: typeof import('element-plus/es')['ElAvatar']
|
||||||
ElButton: typeof import('element-plus/es')['ElButton']
|
ElButton: typeof import('element-plus/es')['ElButton']
|
||||||
ElCard: typeof import('element-plus/es')['ElCard']
|
|
||||||
ElCheckbox: typeof import('element-plus/es')['ElCheckbox']
|
|
||||||
ElCheckboxGroup: typeof import('element-plus/es')['ElCheckboxGroup']
|
|
||||||
ElCol: typeof import('element-plus/es')['ElCol']
|
|
||||||
ElDatePicker: typeof import('element-plus/es')['ElDatePicker']
|
|
||||||
ElDialog: typeof import('element-plus/es')['ElDialog']
|
ElDialog: typeof import('element-plus/es')['ElDialog']
|
||||||
ElDivider: typeof import('element-plus/es')['ElDivider']
|
|
||||||
ElDropdown: typeof import('element-plus/es')['ElDropdown']
|
ElDropdown: typeof import('element-plus/es')['ElDropdown']
|
||||||
ElDropdownItem: typeof import('element-plus/es')['ElDropdownItem']
|
ElDropdownItem: typeof import('element-plus/es')['ElDropdownItem']
|
||||||
ElDropdownMenu: typeof import('element-plus/es')['ElDropdownMenu']
|
ElDropdownMenu: typeof import('element-plus/es')['ElDropdownMenu']
|
||||||
@ -26,33 +20,20 @@ declare module '@vue/runtime-core' {
|
|||||||
ElForm: typeof import('element-plus/es')['ElForm']
|
ElForm: typeof import('element-plus/es')['ElForm']
|
||||||
ElFormItem: typeof import('element-plus/es')['ElFormItem']
|
ElFormItem: typeof import('element-plus/es')['ElFormItem']
|
||||||
ElIcon: typeof import('element-plus/es')['ElIcon']
|
ElIcon: typeof import('element-plus/es')['ElIcon']
|
||||||
ElImage: typeof import('element-plus/es')['ElImage']
|
|
||||||
ElInput: typeof import('element-plus/es')['ElInput']
|
ElInput: typeof import('element-plus/es')['ElInput']
|
||||||
ElInputNumber: typeof import('element-plus/es')['ElInputNumber']
|
|
||||||
ElMenu: typeof import('element-plus/es')['ElMenu']
|
ElMenu: typeof import('element-plus/es')['ElMenu']
|
||||||
ElMenuItem: typeof import('element-plus/es')['ElMenuItem']
|
ElMenuItem: typeof import('element-plus/es')['ElMenuItem']
|
||||||
ElOption: typeof import('element-plus/es')['ElOption']
|
ElOption: typeof import('element-plus/es')['ElOption']
|
||||||
ElPagination: typeof import('element-plus/es')['ElPagination']
|
ElPagination: typeof import('element-plus/es')['ElPagination']
|
||||||
ElProgress: typeof import('element-plus/es')['ElProgress']
|
|
||||||
ElRadio: typeof import('element-plus/es')['ElRadio']
|
ElRadio: typeof import('element-plus/es')['ElRadio']
|
||||||
ElRadioButton: typeof import('element-plus/es')['ElRadioButton']
|
|
||||||
ElRadioGroup: typeof import('element-plus/es')['ElRadioGroup']
|
ElRadioGroup: typeof import('element-plus/es')['ElRadioGroup']
|
||||||
ElRow: typeof import('element-plus/es')['ElRow']
|
|
||||||
ElSelect: typeof import('element-plus/es')['ElSelect']
|
ElSelect: typeof import('element-plus/es')['ElSelect']
|
||||||
ElSubMenu: typeof import('element-plus/es')['ElSubMenu']
|
ElSubMenu: typeof import('element-plus/es')['ElSubMenu']
|
||||||
ElSwitch: typeof import('element-plus/es')['ElSwitch']
|
|
||||||
ElTable: typeof import('element-plus/es')['ElTable']
|
ElTable: typeof import('element-plus/es')['ElTable']
|
||||||
ElTableColumn: typeof import('element-plus/es')['ElTableColumn']
|
ElTableColumn: typeof import('element-plus/es')['ElTableColumn']
|
||||||
ElTabPane: typeof import('element-plus/es')['ElTabPane']
|
|
||||||
ElTabs: typeof import('element-plus/es')['ElTabs']
|
|
||||||
ElTag: typeof import('element-plus/es')['ElTag']
|
|
||||||
ElTimePicker: typeof import('element-plus/es')['ElTimePicker']
|
|
||||||
ElTooltip: typeof import('element-plus/es')['ElTooltip']
|
ElTooltip: typeof import('element-plus/es')['ElTooltip']
|
||||||
ElTree: typeof import('element-plus/es')['ElTree']
|
|
||||||
ElUpload: typeof import('element-plus/es')['ElUpload']
|
|
||||||
Header: typeof import('./src/components/header.vue')['default']
|
Header: typeof import('./src/components/header.vue')['default']
|
||||||
ManageList: typeof import('./src/components/manage-list.vue')['default']
|
ManageList: typeof import('./src/components/manage-list.vue')['default']
|
||||||
Popover: typeof import('./src/components/popover.vue')['default']
|
|
||||||
RouterLink: typeof import('vue-router')['RouterLink']
|
RouterLink: typeof import('vue-router')['RouterLink']
|
||||||
RouterView: typeof import('vue-router')['RouterView']
|
RouterView: typeof import('vue-router')['RouterView']
|
||||||
Sidebar: typeof import('./src/components/sidebar.vue')['default']
|
Sidebar: typeof import('./src/components/sidebar.vue')['default']
|
||||||
|
@ -61,3 +61,15 @@ export function deleteUser(params) {
|
|||||||
params: params,
|
params: params,
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 导出用户列表
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
export function exportUserList(params) {
|
||||||
|
return send_request({
|
||||||
|
url: '/user/manage/exportUserList',
|
||||||
|
method: 'GET',
|
||||||
|
params: params,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
@ -6,17 +6,24 @@
|
|||||||
<div class="handle-box">
|
<div class="handle-box">
|
||||||
<template v-for="field in searchFields">
|
<template v-for="field in searchFields">
|
||||||
<el-input v-if="field.searchType == 'input'" v-model="query[field.field]"
|
<el-input v-if="field.searchType == 'input'" v-model="query[field.field]"
|
||||||
@keyup.enter.native="handleSearch" :placeholder="field.placeholder"
|
@keyup.enter.native="handleSearch" :placeholder="field.placeholder" :prefix-icon="Filter"
|
||||||
class="handle-input mr10"></el-input>
|
class="handle-input mr10"></el-input>
|
||||||
<el-select v-else-if="field.searchType == 'select'" v-model="query[field.field]" :clearable="true"
|
<el-select v-else-if="field.searchType == 'select'" v-model="query[field.field]" :clearable="true"
|
||||||
@change="handleSearch" :placeholder="field.placeholder" class="handle-select mr10">
|
@change="handleSearch" :placeholder="field.placeholder" class="handle-select mr10">
|
||||||
|
<template #prefix>
|
||||||
|
<el-icon>
|
||||||
|
<Filter />
|
||||||
|
</el-icon>
|
||||||
|
</template>
|
||||||
<el-option v-for="optKey in Object.keys(field.options)" :key="optKey" :label="field.options[optKey]"
|
<el-option v-for="optKey in Object.keys(field.options)" :key="optKey" :label="field.options[optKey]"
|
||||||
:value="optKey"></el-option>
|
:value="optKey"></el-option>
|
||||||
</el-select>
|
</el-select>
|
||||||
<template v-else>{{ field }}</template>
|
<template v-else>{{ field }}</template>
|
||||||
</template>
|
</template>
|
||||||
<el-button type="primary" :icon="Search" @click="handleSearch">搜索</el-button>
|
<el-button type="primary" :icon="Search" @click="handleSearch">查询</el-button>
|
||||||
<el-button type="primary" :icon="Plus" @click="handleNew" v-permiss="props.editPermiss">新增</el-button>
|
<el-button type="primary" :icon="Plus" @click="handleNew" v-permiss="props.editPermiss">新增记录</el-button>
|
||||||
|
<el-button type="primary" :icon="Download" @click="exportFormVisible = true"
|
||||||
|
v-permiss="props.editPermiss">导出到文件</el-button>
|
||||||
</div>
|
</div>
|
||||||
<!-- 表格 -->
|
<!-- 表格 -->
|
||||||
<el-table :data="tableData" border class="table" ref="multipleTable" header-cell-class-name="table-header">
|
<el-table :data="tableData" border class="table" ref="multipleTable" header-cell-class-name="table-header">
|
||||||
@ -72,14 +79,38 @@
|
|||||||
</span>
|
</span>
|
||||||
</template>
|
</template>
|
||||||
</el-dialog>
|
</el-dialog>
|
||||||
|
|
||||||
|
<!-- 导出 Excel 弹窗 -->
|
||||||
|
<el-dialog v-model="exportFormVisible" title="导出选项">
|
||||||
|
<el-form :model="form" label-width="80px">
|
||||||
|
<el-form-item label="数据范围">
|
||||||
|
<el-radio-group v-model="exportConfig.withFilter">
|
||||||
|
<el-radio :label="false">全部数据</el-radio>
|
||||||
|
<el-radio :label="true">满足筛选条件的数据</el-radio>
|
||||||
|
</el-radio-group>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="文件格式">
|
||||||
|
<el-radio-group v-model="exportConfig.ext">
|
||||||
|
<el-radio v-for="ext in supportExportFormatList" :label="ext">{{ ext }}</el-radio>
|
||||||
|
</el-radio-group>
|
||||||
|
</el-form-item>
|
||||||
|
<el-alert v-if="exportInfo" :title="exportInfo.info" :type="exportInfo.type" :closable="false" show-icon />
|
||||||
|
</el-form>
|
||||||
|
<template #footer>
|
||||||
|
<span class="dialog-footer">
|
||||||
|
<el-button @click="exportFormVisible = false">取消</el-button>
|
||||||
|
<el-button type="primary" @click="handleExport">导出</el-button>
|
||||||
|
</span>
|
||||||
|
</template>
|
||||||
|
</el-dialog>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { ref, reactive, onMounted } from 'vue';
|
import { ref, reactive, onMounted, computed } from 'vue';
|
||||||
import { FormInstance, FormRules, ElMessage, ElMessageBox } from 'element-plus';
|
import { FormInstance, FormRules, ElMessage, ElMessageBox } from 'element-plus';
|
||||||
import { Delete, Edit, Search, Plus } from '@element-plus/icons-vue';
|
import { Delete, Edit, Search, Plus, Filter, Download } from '@element-plus/icons-vue';
|
||||||
import send_request from '../utils/send_request';
|
import * as xlsx from 'xlsx';
|
||||||
import Mock from 'mockjs';
|
import Mock from 'mockjs';
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
@ -103,7 +134,12 @@ const props = defineProps({
|
|||||||
type: Function,
|
type: Function,
|
||||||
required: true,
|
required: true,
|
||||||
},
|
},
|
||||||
// 修改、删除权限
|
// 导出 接口函数
|
||||||
|
'exportFunc': {
|
||||||
|
type: Function,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
// 修改、删除、导出权限
|
||||||
'editPermiss': {
|
'editPermiss': {
|
||||||
type: String,
|
type: String,
|
||||||
required: true,
|
required: true,
|
||||||
@ -118,6 +154,9 @@ const query = reactive({
|
|||||||
// 其他筛选条件
|
// 其他筛选条件
|
||||||
}); // 筛选条件的值
|
}); // 筛选条件的值
|
||||||
|
|
||||||
|
// 字段翻译字典(如 roleId -> roleName)
|
||||||
|
let fieldsMapper: any;
|
||||||
|
|
||||||
// 表格
|
// 表格
|
||||||
const tableData: any = ref(null); // 表格数据
|
const tableData: any = ref(null); // 表格数据
|
||||||
const tableFields: any = ref([]); // 表格列
|
const tableFields: any = ref([]); // 表格列
|
||||||
@ -136,9 +175,34 @@ const editForm = ref<FormInstance>();
|
|||||||
// const rules: FormRules = {};
|
// const rules: FormRules = {};
|
||||||
const rules = ref({} as FormRules);
|
const rules = ref({} as FormRules);
|
||||||
|
|
||||||
//
|
// mock数据
|
||||||
let mockData: any = []
|
let mockData: any = []
|
||||||
|
|
||||||
|
// 导出 Excel 弹窗
|
||||||
|
const exportFormVisible: any = ref(false);
|
||||||
|
let exportFields: any = [] // 导出 excel 列表对应中文
|
||||||
|
const supportExportFormatList = ref(['xlsx', 'xls', 'csv', 'html', 'txt', 'json', 'rtf'] as Array<String>); // 支持的导出格式
|
||||||
|
const exportConfig = ref({
|
||||||
|
withFilter: false, // 导出时是否携带筛选条件
|
||||||
|
ext: "xlsx", // 所选导出格式
|
||||||
|
} as any);
|
||||||
|
const exportInfo = computed(() => {
|
||||||
|
if (['xlsx', 'xls'].includes(exportConfig.value.ext)) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
let info = '建议选择 xlsx 或 xls 格式'
|
||||||
|
let type = 'info'
|
||||||
|
if (['rtf'].includes(exportConfig.value.ext)) {
|
||||||
|
// 不推荐的导出格式
|
||||||
|
info = '该格式易出现编码问题,' + info
|
||||||
|
type = 'warning'
|
||||||
|
} else if (['json'].includes(exportConfig.value.ext)) {
|
||||||
|
info = '该格式方便程序读取,若您不了解该格式,建议选择其他格式进行导出'
|
||||||
|
type = 'warning'
|
||||||
|
}
|
||||||
|
return { info, type }
|
||||||
|
})
|
||||||
|
|
||||||
// 获取表格数据
|
// 获取表格数据
|
||||||
const getData = async () => {
|
const getData = async () => {
|
||||||
props.listFunc(query).then((data: any) => {
|
props.listFunc(query).then((data: any) => {
|
||||||
@ -147,15 +211,15 @@ const getData = async () => {
|
|||||||
// 深拷贝一份
|
// 深拷贝一份
|
||||||
let _tableData = JSON.parse(JSON.stringify(data.list));
|
let _tableData = JSON.parse(JSON.stringify(data.list));
|
||||||
// 字段映射
|
// 字段映射
|
||||||
let fieldsMapper = data.fieldMapper;
|
fieldsMapper = data.fieldMapper;
|
||||||
if (fieldsMapper) {
|
if (fieldsMapper) {
|
||||||
// 对于每一个需要映射的字段
|
// 对于每一个需要映射的字段
|
||||||
for (let m of fieldsMapper) {
|
for (let m of fieldsMapper) {
|
||||||
// console.log("mapper", m)
|
// console.log("mapper", m)
|
||||||
_tableData = _tableData.map((row: any) => {
|
_tableData = _tableData.map((row: any) => {
|
||||||
let oldValue = row[m.key]
|
let oldValue = row[m.key] // 取得旧值
|
||||||
let newValue = m.mapper[oldValue]
|
let newValue = m.mapper[oldValue] // 翻译新值
|
||||||
row[m.value] = newValue
|
row[m.value] = newValue // 塞回新值
|
||||||
return row
|
return row
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -167,6 +231,10 @@ const getData = async () => {
|
|||||||
tableFields.value = data.columns
|
tableFields.value = data.columns
|
||||||
.filter((field: any) => field.showInTable)
|
.filter((field: any) => field.showInTable)
|
||||||
.map((field: any) => {
|
.map((field: any) => {
|
||||||
|
// query 填充默认空字符串
|
||||||
|
if (typeof (query[field.field]) === "undefined") {
|
||||||
|
query[field.field] = ''
|
||||||
|
}
|
||||||
return { prop: field.prop, label: field.label }
|
return { prop: field.prop, label: field.label }
|
||||||
});
|
});
|
||||||
console.log("tableFields", tableFields.value)
|
console.log("tableFields", tableFields.value)
|
||||||
@ -203,10 +271,6 @@ const getData = async () => {
|
|||||||
// 新增/修改弹窗列
|
// 新增/修改弹窗列
|
||||||
dialogFields.value = data.columns
|
dialogFields.value = data.columns
|
||||||
.map((field: any) => {
|
.map((field: any) => {
|
||||||
// 拼装 新增/修改弹窗 字段
|
|
||||||
if (typeof (query[field.field]) === "undefined") {
|
|
||||||
query[field.field] = ''
|
|
||||||
}
|
|
||||||
let f: any = {
|
let f: any = {
|
||||||
label: field.label,
|
label: field.label,
|
||||||
field: field.field,
|
field: field.field,
|
||||||
@ -228,16 +292,17 @@ const getData = async () => {
|
|||||||
});
|
});
|
||||||
console.log("dialogFields", dialogFields.value);
|
console.log("dialogFields", dialogFields.value);
|
||||||
|
|
||||||
|
// 导出 excel 字段映射
|
||||||
|
exportFields = data.columns
|
||||||
|
.filter((field: any) => field.showInTable)
|
||||||
|
.map((field: any) => {
|
||||||
|
return { field: field.field, label: field.label }
|
||||||
|
});
|
||||||
|
console.log("exportFields", exportFields)
|
||||||
|
|
||||||
// 表单验证
|
// 表单验证
|
||||||
for (let field of data.columns) {
|
for (let field of data.columns) {
|
||||||
rules.value[field.field] = field.validateRules
|
rules.value[field.field] = field.validateRules
|
||||||
// .map((rule: any) => {
|
|
||||||
// if (rule.pattern) {
|
|
||||||
// rule.pattern = new RegExp(rule.pattern)
|
|
||||||
// console.log(rule.pattern)
|
|
||||||
// }
|
|
||||||
// return rule
|
|
||||||
// })
|
|
||||||
}
|
}
|
||||||
console.log("rules", rules.value)
|
console.log("rules", rules.value)
|
||||||
|
|
||||||
@ -382,6 +447,90 @@ const handleDelete = (index: number, row: any) => {
|
|||||||
.catch(() => { });
|
.catch(() => { });
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// 导出数据到文件
|
||||||
|
const handleExport = async () => {
|
||||||
|
// 去除分页参数
|
||||||
|
let params = JSON.parse(JSON.stringify(query))
|
||||||
|
delete params["pageIndex"]
|
||||||
|
delete params["pageSize"]
|
||||||
|
props.exportFunc(params).then((data: any) => {
|
||||||
|
console.log("exportData", data)
|
||||||
|
let sheetName = data.sheetName
|
||||||
|
let fileName = data.fileName
|
||||||
|
console.log("data.list", data.list)
|
||||||
|
|
||||||
|
// 字段翻译
|
||||||
|
let dataList = JSON.parse(JSON.stringify(data.list))
|
||||||
|
if (fieldsMapper) {
|
||||||
|
// 对于每一个需要映射的字段
|
||||||
|
for (let m of fieldsMapper) {
|
||||||
|
// console.log("mapper", m)
|
||||||
|
dataList = dataList.map((row: any) => {
|
||||||
|
let oldValue = row[m.key] // 取得旧值
|
||||||
|
let newValue = m.mapper[oldValue] // 翻译新值
|
||||||
|
row[m.key] = newValue // 直接在旧 key 塞回新值
|
||||||
|
// 因为后续是通过翻译前的 key 拿的数据,所以这里不翻译 key 只翻译 value
|
||||||
|
return row
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
console.log("dataList", dataList)
|
||||||
|
|
||||||
|
// 所有列的 field
|
||||||
|
let fieldNameList = exportFields.map((f: any) => f.field)
|
||||||
|
fieldNameList.unshift(idFieldName)
|
||||||
|
|
||||||
|
// 第一行表头
|
||||||
|
let firstRow = exportFields.map((f: any) => f.label)
|
||||||
|
firstRow.unshift("ID")
|
||||||
|
|
||||||
|
// 列宽
|
||||||
|
let rowWidth = exportFields.map(() => { return { wch: 13 } })
|
||||||
|
rowWidth.unshift({ wch: 5 })
|
||||||
|
|
||||||
|
// 数据部分
|
||||||
|
let excelList = dataList.map((row: any) => {
|
||||||
|
// 通过翻译前的 key 拿数据
|
||||||
|
return fieldNameList.map((field: any) => String(row[field]))
|
||||||
|
})
|
||||||
|
excelList.unshift(firstRow) // 插入表头
|
||||||
|
|
||||||
|
console.log("excelList", excelList)
|
||||||
|
|
||||||
|
function downloadFile(text: string, fileName: string, contentType: string) {
|
||||||
|
const blob = new Blob([text], { type: contentType });
|
||||||
|
const href = URL.createObjectURL(blob);
|
||||||
|
const alink = document.createElement("a");
|
||||||
|
alink.style.display = "none";
|
||||||
|
alink.download = fileName; // 下载后文件名
|
||||||
|
alink.href = href;
|
||||||
|
document.body.appendChild(alink);
|
||||||
|
alink.click();
|
||||||
|
document.body.removeChild(alink); // 下载完成移除元素
|
||||||
|
URL.revokeObjectURL(href); // 释放掉blob对象
|
||||||
|
}
|
||||||
|
|
||||||
|
// 生成文件
|
||||||
|
let _fileName: string = `${fileName || '数据导出'}.${exportConfig.value.ext || 'xlsx'}`
|
||||||
|
if (exportConfig.value.ext === "json") {
|
||||||
|
let text = JSON.stringify(excelList)
|
||||||
|
downloadFile(text, _fileName, "application/json;charset=utf-8")
|
||||||
|
} else if (exportConfig.value.ext === "txt") {
|
||||||
|
let text = excelList.map((row: Array<any>) => row.join('\t')).join('\n')
|
||||||
|
downloadFile(text, _fileName, "text/plain;charset=utf-8")
|
||||||
|
} else {
|
||||||
|
let worksheet = xlsx.utils.aoa_to_sheet(excelList)
|
||||||
|
let workbook = xlsx.utils.book_new()
|
||||||
|
worksheet["!cols"] = rowWidth; // 指定列宽
|
||||||
|
xlsx.utils.book_append_sheet(workbook, worksheet, sheetName || 'Sheet1')
|
||||||
|
xlsx.writeFile(workbook, _fileName)
|
||||||
|
}
|
||||||
|
|
||||||
|
ElMessage.success({ message: "导出成功" })
|
||||||
|
exportFormVisible.value = false
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
// 生成测试数据
|
// 生成测试数据
|
||||||
const doMockData = (isEdit: boolean) => {
|
const doMockData = (isEdit: boolean) => {
|
||||||
for (let mock of mockData) {
|
for (let mock of mockData) {
|
||||||
|
@ -52,19 +52,6 @@ const items = [
|
|||||||
title: '系统首页', // 站点基础信息
|
title: '系统首页', // 站点基础信息
|
||||||
permiss: 'dashboard',
|
permiss: 'dashboard',
|
||||||
},
|
},
|
||||||
{
|
|
||||||
icon: 'Monitor',
|
|
||||||
index: '/monitor-data',
|
|
||||||
title: '监测数据',
|
|
||||||
permiss: 'monitor-data',
|
|
||||||
subs: [
|
|
||||||
{
|
|
||||||
index: '/monitor-data-view',
|
|
||||||
title: '查看数据',
|
|
||||||
permiss: 'monitor-data-view',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
icon: 'BellFilled',
|
icon: 'BellFilled',
|
||||||
index: '/warning',
|
index: '/warning',
|
||||||
@ -85,123 +72,30 @@ const items = [
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
icon: 'OfficeBuilding',
|
icon: 'OfficeBuilding',
|
||||||
index: '/equipment',
|
index: '/shop',
|
||||||
title: '设备信息',
|
title: '商品管理',
|
||||||
permiss: 'equipment',
|
permiss: 'shop',
|
||||||
subs: [
|
subs: [
|
||||||
{
|
{
|
||||||
index: '/equipment-setting',
|
index: '/shop-good-setting',
|
||||||
title: '设备管理',
|
title: '商品管理',
|
||||||
permiss: 'equipment-setting',
|
permiss: 'shop-good-setting',
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
icon: 'Avatar',
|
icon: 'Avatar',
|
||||||
index: '/privilege',
|
index: '/privilege',
|
||||||
title: '用户角色',
|
title: '用户管理',
|
||||||
permiss: 'privilege',
|
permiss: 'privilege',
|
||||||
subs: [
|
subs: [
|
||||||
{
|
{
|
||||||
index: '/privilege-user-setting',
|
index: '/privilege-user-setting',
|
||||||
title: '用户管理', // 列表 增删改
|
title: '用户管理',
|
||||||
permiss: 'privilege-user-setting',
|
permiss: 'privilege-user-setting',
|
||||||
},
|
},
|
||||||
{
|
|
||||||
index: '/privilege-role-setting',
|
|
||||||
title: '角色权限', // 列表 增删改<角色名;角色对应权限>
|
|
||||||
permiss: 'privilege-role-setting',
|
|
||||||
},
|
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
... !settings.debugMode ? [] : [
|
|
||||||
{
|
|
||||||
icon: 'Odometer',
|
|
||||||
index: '/',
|
|
||||||
title: '——————————',
|
|
||||||
permiss: 'default',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
icon: 'Calendar',
|
|
||||||
index: '1',
|
|
||||||
title: '表格相关',
|
|
||||||
permiss: 'default',
|
|
||||||
subs: [
|
|
||||||
{
|
|
||||||
index: '/table',
|
|
||||||
title: '常用表格',
|
|
||||||
permiss: 'default',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
index: '/import',
|
|
||||||
title: '导入Excel',
|
|
||||||
permiss: 'default',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
index: '/export',
|
|
||||||
title: '导出Excel',
|
|
||||||
permiss: 'default',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
icon: 'DocumentCopy',
|
|
||||||
index: '/tabs',
|
|
||||||
title: 'tab选项卡',
|
|
||||||
permiss: 'default',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
icon: 'Edit',
|
|
||||||
index: '3',
|
|
||||||
title: '表单相关',
|
|
||||||
permiss: 'default',
|
|
||||||
subs: [
|
|
||||||
{
|
|
||||||
index: '/form',
|
|
||||||
title: '基本表单',
|
|
||||||
permiss: 'default',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
index: '/upload',
|
|
||||||
title: '文件上传',
|
|
||||||
permiss: 'default',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
index: '4',
|
|
||||||
title: '三级菜单',
|
|
||||||
permiss: 'default',
|
|
||||||
subs: [
|
|
||||||
{
|
|
||||||
index: '/editor',
|
|
||||||
title: '富文本编辑器',
|
|
||||||
permiss: 'default',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
index: '/markdown',
|
|
||||||
title: 'markdown编辑器',
|
|
||||||
permiss: '9default',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
icon: 'Setting',
|
|
||||||
index: '/icon',
|
|
||||||
title: '自定义图标',
|
|
||||||
permiss: 'default',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
icon: 'PieChart',
|
|
||||||
index: '/charts',
|
|
||||||
title: 'schart图表',
|
|
||||||
permiss: 'default',
|
|
||||||
},
|
|
||||||
]
|
|
||||||
];
|
];
|
||||||
|
|
||||||
const route = useRoute();
|
const route = useRoute();
|
||||||
|
@ -23,40 +23,13 @@ const routes: RouteRecordRaw[] = [
|
|||||||
component: () => import('../views/dashboard.vue'),
|
component: () => import('../views/dashboard.vue'),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: '/monitor-data-view',
|
path: '/shop-good-setting',
|
||||||
name: 'monitor-data-view',
|
name: 'shop-good-setting',
|
||||||
meta: {
|
meta: {
|
||||||
title: '查看数据',
|
title: '商品管理',
|
||||||
permiss: 'monitor-data-view',
|
permiss: 'shop-good-setting',
|
||||||
},
|
},
|
||||||
component: () => import('../views/monitor-data-view.vue'),
|
component: () => import('../views/shop-good-setting.vue'),
|
||||||
},
|
|
||||||
{
|
|
||||||
path: '/warning-view',
|
|
||||||
name: 'warning-view',
|
|
||||||
meta: {
|
|
||||||
title: '总览',
|
|
||||||
permiss: 'warning-view',
|
|
||||||
},
|
|
||||||
component: () => import('../views/warning-view.vue'),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: '/warning-setting',
|
|
||||||
name: 'warning-setting',
|
|
||||||
meta: {
|
|
||||||
title: '预警设置',
|
|
||||||
permiss: 'warning-setting',
|
|
||||||
},
|
|
||||||
component: () => import('../views/warning-setting.vue'),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: '/equipment-setting',
|
|
||||||
name: 'equipment-setting',
|
|
||||||
meta: {
|
|
||||||
title: '设备管理',
|
|
||||||
permiss: 'equipment-setting',
|
|
||||||
},
|
|
||||||
component: () => import('../views/equipment-setting.vue'),
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: '/privilege-user-setting',
|
path: '/privilege-user-setting',
|
||||||
@ -67,15 +40,6 @@ const routes: RouteRecordRaw[] = [
|
|||||||
},
|
},
|
||||||
component: () => import('../views/privilege-user-setting.vue'),
|
component: () => import('../views/privilege-user-setting.vue'),
|
||||||
},
|
},
|
||||||
{
|
|
||||||
path: '/privilege-role-setting',
|
|
||||||
name: 'privilege-role-setting',
|
|
||||||
meta: {
|
|
||||||
title: '角色权限',
|
|
||||||
permiss: 'privilege-role-setting',
|
|
||||||
},
|
|
||||||
component: () => import('../views/privilege-role-setting.vue'),
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
path: '/user',
|
path: '/user',
|
||||||
name: 'user',
|
name: 'user',
|
||||||
@ -84,93 +48,6 @@ const routes: RouteRecordRaw[] = [
|
|||||||
},
|
},
|
||||||
component: () => import('../views/user.vue'),
|
component: () => import('../views/user.vue'),
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
{
|
|
||||||
path: '/table',
|
|
||||||
name: 'basetable',
|
|
||||||
meta: {
|
|
||||||
title: '表格',
|
|
||||||
permiss: 'default',
|
|
||||||
},
|
|
||||||
component: () => import('../views/demo/table.vue'),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: '/charts',
|
|
||||||
name: 'basecharts',
|
|
||||||
meta: {
|
|
||||||
title: '图表',
|
|
||||||
permiss: 'default',
|
|
||||||
},
|
|
||||||
component: () => import('../views/demo/charts.vue'),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: '/form',
|
|
||||||
name: 'baseform',
|
|
||||||
meta: {
|
|
||||||
title: '表单',
|
|
||||||
permiss: 'default',
|
|
||||||
},
|
|
||||||
component: () => import('../views/demo/form.vue'),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: '/tabs',
|
|
||||||
name: 'tabs',
|
|
||||||
meta: {
|
|
||||||
title: 'tab标签',
|
|
||||||
permiss: 'default',
|
|
||||||
},
|
|
||||||
component: () => import('../views/demo/tabs.vue'),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: '/icon',
|
|
||||||
name: 'icon',
|
|
||||||
meta: {
|
|
||||||
title: '自定义图标',
|
|
||||||
permiss: 'default',
|
|
||||||
},
|
|
||||||
component: () => import('../views/demo/icon.vue'),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: '/editor',
|
|
||||||
name: 'editor',
|
|
||||||
meta: {
|
|
||||||
title: '富文本编辑器',
|
|
||||||
permiss: 'default',
|
|
||||||
},
|
|
||||||
component: () => import('../views/demo/editor.vue'),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: '/markdown',
|
|
||||||
name: 'markdown',
|
|
||||||
meta: {
|
|
||||||
title: 'markdown编辑器',
|
|
||||||
permiss: 'default',
|
|
||||||
},
|
|
||||||
component: () => import('../views/demo/markdown.vue'),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: '/export',
|
|
||||||
name: 'export',
|
|
||||||
meta: {
|
|
||||||
title: '导出Excel',
|
|
||||||
permiss: 'default',
|
|
||||||
},
|
|
||||||
component: () => import('../views/demo/export.vue'),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: '/import',
|
|
||||||
name: 'import',
|
|
||||||
meta: {
|
|
||||||
title: '导入Excel',
|
|
||||||
permiss: 'default',
|
|
||||||
},
|
|
||||||
component: () => import('../views/demo/import.vue'),
|
|
||||||
},
|
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -10,47 +10,26 @@ export const usePermissStore = defineStore('permiss', {
|
|||||||
state: () => {
|
state: () => {
|
||||||
return {
|
return {
|
||||||
"1": [
|
"1": [
|
||||||
"dashboard",
|
|
||||||
"data-integration",
|
|
||||||
"default",
|
"default",
|
||||||
"equipment",
|
|
||||||
"equipment-setting",
|
"dashboard",
|
||||||
"equipment-setting-manage",
|
|
||||||
"equipment-view",
|
"shop",
|
||||||
"monitor-data",
|
"shop-good-setting",
|
||||||
"monitor-data-statistics",
|
|
||||||
"monitor-data-view",
|
|
||||||
"privilege",
|
"privilege",
|
||||||
"privilege-role-setting",
|
|
||||||
"privilege-user-setting",
|
"privilege-user-setting",
|
||||||
"report",
|
|
||||||
"report-upload",
|
|
||||||
"resource",
|
|
||||||
"resource-staff-setting",
|
|
||||||
"resource-vehicle-setting",
|
|
||||||
"site-info",
|
|
||||||
"warning",
|
|
||||||
"warning-log",
|
|
||||||
"warning-setting",
|
|
||||||
"warning-view"
|
|
||||||
],
|
],
|
||||||
"2": [
|
"2": [
|
||||||
"dashboard",
|
|
||||||
"data-integration",
|
|
||||||
"default",
|
"default",
|
||||||
"equipment",
|
|
||||||
"equipment-setting",
|
"dashboard",
|
||||||
"equipment-view",
|
|
||||||
"monitor-data",
|
"shop",
|
||||||
"monitor-data-statistics",
|
"shop-good-setting",
|
||||||
"monitor-data-view",
|
|
||||||
"report",
|
"privilege",
|
||||||
"report-upload",
|
"privilege-user-setting",
|
||||||
"site-info",
|
|
||||||
"warning",
|
|
||||||
"warning-log",
|
|
||||||
"warning-setting",
|
|
||||||
"warning-view"
|
|
||||||
]
|
]
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
@ -1,127 +0,0 @@
|
|||||||
<template>
|
|
||||||
<div class="container">
|
|
||||||
<div class="plugins-tips">
|
|
||||||
vue-schart:vue.js封装sChart.js的图表组件。 访问地址:
|
|
||||||
<a href="https://github.com/lin-xin/vue-schart" target="_blank">vue-schart</a>
|
|
||||||
</div>
|
|
||||||
<div class="schart-box">
|
|
||||||
<div class="content-title">柱状图</div>
|
|
||||||
<schart class="schart" canvasId="bar" :options="options1"></schart>
|
|
||||||
</div>
|
|
||||||
<div class="schart-box">
|
|
||||||
<div class="content-title">折线图</div>
|
|
||||||
<schart class="schart" canvasId="line" :options="options2"></schart>
|
|
||||||
</div>
|
|
||||||
<div class="schart-box">
|
|
||||||
<div class="content-title">饼状图</div>
|
|
||||||
<schart class="schart" canvasId="pie" :options="options3"></schart>
|
|
||||||
</div>
|
|
||||||
<div class="schart-box">
|
|
||||||
<div class="content-title">环形图</div>
|
|
||||||
<schart class="schart" canvasId="ring" :options="options4"></schart>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script setup lang="ts" name="basecharts">
|
|
||||||
import Schart from 'vue-schart';
|
|
||||||
|
|
||||||
const options1 = {
|
|
||||||
type: 'bar',
|
|
||||||
title: {
|
|
||||||
text: '最近一周各品类销售图'
|
|
||||||
},
|
|
||||||
bgColor: '#fbfbfb',
|
|
||||||
labels: ['周一', '周二', '周三', '周四', '周五'],
|
|
||||||
datasets: [
|
|
||||||
{
|
|
||||||
label: '家电',
|
|
||||||
fillColor: 'rgba(241, 49, 74, 0.5)',
|
|
||||||
data: [234, 278, 270, 190, 230]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: '百货',
|
|
||||||
data: [164, 178, 190, 135, 160]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: '食品',
|
|
||||||
data: [144, 198, 150, 235, 120]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
};
|
|
||||||
const options2 = {
|
|
||||||
type: 'line',
|
|
||||||
title: {
|
|
||||||
text: '最近几个月各品类销售趋势图'
|
|
||||||
},
|
|
||||||
bgColor: '#fbfbfb',
|
|
||||||
labels: ['6月', '7月', '8月', '9月', '10月'],
|
|
||||||
datasets: [
|
|
||||||
{
|
|
||||||
label: '家电',
|
|
||||||
data: [234, 278, 270, 190, 230]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: '百货',
|
|
||||||
data: [164, 178, 150, 135, 160]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: '食品',
|
|
||||||
data: [114, 138, 200, 235, 190]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
};
|
|
||||||
const options3 = {
|
|
||||||
type: 'pie',
|
|
||||||
title: {
|
|
||||||
text: '服装品类销售饼状图'
|
|
||||||
},
|
|
||||||
legend: {
|
|
||||||
position: 'left'
|
|
||||||
},
|
|
||||||
bgColor: '#fbfbfb',
|
|
||||||
labels: ['T恤', '牛仔裤', '连衣裙', '毛衣', '七分裤', '短裙', '羽绒服'],
|
|
||||||
datasets: [
|
|
||||||
{
|
|
||||||
data: [334, 278, 190, 235, 260, 200, 141]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
};
|
|
||||||
const options4 = {
|
|
||||||
type: 'ring',
|
|
||||||
title: {
|
|
||||||
text: '环形三等分'
|
|
||||||
},
|
|
||||||
showValue: false,
|
|
||||||
legend: {
|
|
||||||
position: 'bottom',
|
|
||||||
bottom: 40
|
|
||||||
},
|
|
||||||
bgColor: '#fbfbfb',
|
|
||||||
labels: ['vue', 'react', 'angular'],
|
|
||||||
datasets: [
|
|
||||||
{
|
|
||||||
data: [500, 500, 500]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
};
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style scoped>
|
|
||||||
.schart-box {
|
|
||||||
display: inline-block;
|
|
||||||
margin: 20px;
|
|
||||||
}
|
|
||||||
.schart {
|
|
||||||
width: 600px;
|
|
||||||
height: 400px;
|
|
||||||
}
|
|
||||||
.content-title {
|
|
||||||
clear: both;
|
|
||||||
font-weight: 400;
|
|
||||||
line-height: 50px;
|
|
||||||
margin: 10px 0;
|
|
||||||
font-size: 22px;
|
|
||||||
color: #1f2f3d;
|
|
||||||
}
|
|
||||||
</style>
|
|
@ -1,37 +0,0 @@
|
|||||||
<template>
|
|
||||||
<div class="container">
|
|
||||||
<div class="plugins-tips">
|
|
||||||
wangEditor:轻量级 web 富文本编辑器,配置方便,使用简单。 访问地址:
|
|
||||||
<a href="https://www.wangeditor.com/doc/" target="_blank">wangEditor</a>
|
|
||||||
</div>
|
|
||||||
<div class="mgb20" ref="editor"></div>
|
|
||||||
<el-button type="primary" @click="syncHTML">提交</el-button>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script setup lang="ts" name="editor">
|
|
||||||
import WangEditor from 'wangeditor';
|
|
||||||
import { ref, reactive, onMounted, onBeforeUnmount } from 'vue';
|
|
||||||
|
|
||||||
const editor = ref(null);
|
|
||||||
const content = reactive({
|
|
||||||
html: '',
|
|
||||||
text: ''
|
|
||||||
});
|
|
||||||
let instance: any;
|
|
||||||
onMounted(() => {
|
|
||||||
instance = new WangEditor(editor.value);
|
|
||||||
instance.config.zIndex = 1;
|
|
||||||
instance.create();
|
|
||||||
});
|
|
||||||
onBeforeUnmount(() => {
|
|
||||||
instance.destroy();
|
|
||||||
instance = null;
|
|
||||||
});
|
|
||||||
const syncHTML = () => {
|
|
||||||
content.html = instance.txt.html();
|
|
||||||
console.log(content.html);
|
|
||||||
};
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style></style>
|
|
@ -1,98 +0,0 @@
|
|||||||
<template>
|
|
||||||
<div>
|
|
||||||
<div class="container">
|
|
||||||
<div class="handle-box">
|
|
||||||
<el-button type="primary" @click="exportXlsx">导出Excel</el-button>
|
|
||||||
</div>
|
|
||||||
<el-table :data="tableData" border class="table" header-cell-class-name="table-header">
|
|
||||||
<el-table-column prop="id" label="ID" width="55" align="center"></el-table-column>
|
|
||||||
<el-table-column prop="name" label="姓名"></el-table-column>
|
|
||||||
<el-table-column prop="sno" label="学号"></el-table-column>
|
|
||||||
<el-table-column prop="class" label="班级"></el-table-column>
|
|
||||||
<el-table-column prop="age" label="年龄"></el-table-column>
|
|
||||||
<el-table-column prop="sex" label="性别"></el-table-column>
|
|
||||||
</el-table>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script setup lang="ts" name="export">
|
|
||||||
import { ref } from 'vue';
|
|
||||||
import * as XLSX from 'xlsx';
|
|
||||||
|
|
||||||
interface TableItem {
|
|
||||||
id: number;
|
|
||||||
name: string;
|
|
||||||
sno: string;
|
|
||||||
class: string;
|
|
||||||
age: string;
|
|
||||||
sex: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
const tableData = ref<TableItem[]>([]);
|
|
||||||
// 获取表格数据
|
|
||||||
const getData = () => {
|
|
||||||
tableData.value = [
|
|
||||||
{
|
|
||||||
id: 1,
|
|
||||||
name: '小明',
|
|
||||||
sno: 'S001',
|
|
||||||
class: '一班',
|
|
||||||
age: '10',
|
|
||||||
sex: '男',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 2,
|
|
||||||
name: '小红',
|
|
||||||
sno: 'S002',
|
|
||||||
class: '一班',
|
|
||||||
age: '9',
|
|
||||||
sex: '女',
|
|
||||||
},
|
|
||||||
];
|
|
||||||
};
|
|
||||||
getData();
|
|
||||||
|
|
||||||
const list = [['序号', '姓名', '学号', '班级', '年龄', '性别']];
|
|
||||||
const exportXlsx = () => {
|
|
||||||
tableData.value.map((item: any, i: number) => {
|
|
||||||
const arr: any[] = [i + 1];
|
|
||||||
arr.push(...[item.name, item.sno, item.class, item.age, item.sex]);
|
|
||||||
list.push(arr);
|
|
||||||
});
|
|
||||||
let WorkSheet = XLSX.utils.aoa_to_sheet(list);
|
|
||||||
let new_workbook = XLSX.utils.book_new();
|
|
||||||
XLSX.utils.book_append_sheet(new_workbook, WorkSheet, '第一页');
|
|
||||||
XLSX.writeFile(new_workbook, `表格.xlsx`);
|
|
||||||
};
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style scoped>
|
|
||||||
.handle-box {
|
|
||||||
margin-bottom: 20px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.handle-select {
|
|
||||||
width: 120px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.handle-input {
|
|
||||||
width: 300px;
|
|
||||||
}
|
|
||||||
.table {
|
|
||||||
width: 100%;
|
|
||||||
font-size: 14px;
|
|
||||||
}
|
|
||||||
.red {
|
|
||||||
color: #f56c6c;
|
|
||||||
}
|
|
||||||
.mr10 {
|
|
||||||
margin-right: 10px;
|
|
||||||
}
|
|
||||||
.table-td-thumb {
|
|
||||||
display: block;
|
|
||||||
margin: auto;
|
|
||||||
width: 40px;
|
|
||||||
height: 40px;
|
|
||||||
}
|
|
||||||
</style>
|
|
@ -1,156 +0,0 @@
|
|||||||
<template>
|
|
||||||
<div class="container">
|
|
||||||
<div class="form-box">
|
|
||||||
<el-form ref="formRef" :rules="rules" :model="form" label-width="80px">
|
|
||||||
<el-form-item label="表单名称" prop="name">
|
|
||||||
<el-input v-model="form.name"></el-input>
|
|
||||||
</el-form-item>
|
|
||||||
<el-form-item label="选择器" prop="region">
|
|
||||||
<el-select v-model="form.region" placeholder="请选择">
|
|
||||||
<el-option key="小明" label="小明" value="小明"></el-option>
|
|
||||||
<el-option key="小红" label="小红" value="小红"></el-option>
|
|
||||||
<el-option key="小白" label="小白" value="小白"></el-option>
|
|
||||||
</el-select>
|
|
||||||
</el-form-item>
|
|
||||||
<el-form-item label="日期时间">
|
|
||||||
<el-col :span="11">
|
|
||||||
<el-form-item prop="date1">
|
|
||||||
<el-date-picker
|
|
||||||
type="date"
|
|
||||||
placeholder="选择日期"
|
|
||||||
v-model="form.date1"
|
|
||||||
style="width: 100%"
|
|
||||||
></el-date-picker>
|
|
||||||
</el-form-item>
|
|
||||||
</el-col>
|
|
||||||
<el-col class="line" :span="2">-</el-col>
|
|
||||||
<el-col :span="11">
|
|
||||||
<el-form-item prop="date2">
|
|
||||||
<el-time-picker placeholder="选择时间" v-model="form.date2" style="width: 100%">
|
|
||||||
</el-time-picker>
|
|
||||||
</el-form-item>
|
|
||||||
</el-col>
|
|
||||||
</el-form-item>
|
|
||||||
<el-form-item label="城市级联" prop="options">
|
|
||||||
<el-cascader :options="options" v-model="form.options"></el-cascader>
|
|
||||||
</el-form-item>
|
|
||||||
<el-form-item label="选择开关" prop="delivery">
|
|
||||||
<el-switch v-model="form.delivery"></el-switch>
|
|
||||||
</el-form-item>
|
|
||||||
<el-form-item label="多选框" prop="type">
|
|
||||||
<el-checkbox-group v-model="form.type">
|
|
||||||
<el-checkbox label="小明" name="type"></el-checkbox>
|
|
||||||
<el-checkbox label="小红" name="type"></el-checkbox>
|
|
||||||
<el-checkbox label="小白" name="type"></el-checkbox>
|
|
||||||
</el-checkbox-group>
|
|
||||||
</el-form-item>
|
|
||||||
<el-form-item label="单选框" prop="resource">
|
|
||||||
<el-radio-group v-model="form.resource">
|
|
||||||
<el-radio label="小明"></el-radio>
|
|
||||||
<el-radio label="小红"></el-radio>
|
|
||||||
<el-radio label="小白"></el-radio>
|
|
||||||
</el-radio-group>
|
|
||||||
</el-form-item>
|
|
||||||
<el-form-item label="文本框" prop="desc">
|
|
||||||
<el-input type="textarea" rows="5" v-model="form.desc"></el-input>
|
|
||||||
</el-form-item>
|
|
||||||
<el-form-item>
|
|
||||||
<el-button type="primary" @click="onSubmit(formRef)">表单提交</el-button>
|
|
||||||
<el-button @click="onReset(formRef)">重置表单</el-button>
|
|
||||||
</el-form-item>
|
|
||||||
</el-form>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script setup lang="ts" name="baseform">
|
|
||||||
import { reactive, ref } from 'vue';
|
|
||||||
import { ElMessage } from 'element-plus';
|
|
||||||
import type { FormInstance, FormRules } from 'element-plus';
|
|
||||||
|
|
||||||
const options = [
|
|
||||||
{
|
|
||||||
value: 'guangdong',
|
|
||||||
label: '广东省',
|
|
||||||
children: [
|
|
||||||
{
|
|
||||||
value: 'guangzhou',
|
|
||||||
label: '广州市',
|
|
||||||
children: [
|
|
||||||
{
|
|
||||||
value: 'tianhe',
|
|
||||||
label: '天河区',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'haizhu',
|
|
||||||
label: '海珠区',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'dongguan',
|
|
||||||
label: '东莞市',
|
|
||||||
children: [
|
|
||||||
{
|
|
||||||
value: 'changan',
|
|
||||||
label: '长安镇',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'humen',
|
|
||||||
label: '虎门镇',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'hunan',
|
|
||||||
label: '湖南省',
|
|
||||||
children: [
|
|
||||||
{
|
|
||||||
value: 'changsha',
|
|
||||||
label: '长沙市',
|
|
||||||
children: [
|
|
||||||
{
|
|
||||||
value: 'yuelu',
|
|
||||||
label: '岳麓区',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
];
|
|
||||||
const rules: FormRules = {
|
|
||||||
name: [{ required: true, message: '请输入表单名称', trigger: 'blur' }],
|
|
||||||
};
|
|
||||||
const formRef = ref<FormInstance>();
|
|
||||||
const form = reactive({
|
|
||||||
name: '',
|
|
||||||
region: '',
|
|
||||||
date1: '',
|
|
||||||
date2: '',
|
|
||||||
delivery: true,
|
|
||||||
type: ['小明'],
|
|
||||||
resource: '小红',
|
|
||||||
desc: '',
|
|
||||||
options: [],
|
|
||||||
});
|
|
||||||
// 提交
|
|
||||||
const onSubmit = (formEl: FormInstance | undefined) => {
|
|
||||||
// 表单校验
|
|
||||||
if (!formEl) return;
|
|
||||||
formEl.validate((valid) => {
|
|
||||||
if (valid) {
|
|
||||||
console.log(form);
|
|
||||||
ElMessage.success('提交成功!');
|
|
||||||
} else {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
|
||||||
// 重置
|
|
||||||
const onReset = (formEl: FormInstance | undefined) => {
|
|
||||||
if (!formEl) return;
|
|
||||||
formEl.resetFields();
|
|
||||||
};
|
|
||||||
</script>
|
|
@ -1,212 +0,0 @@
|
|||||||
<template>
|
|
||||||
<div class="container">
|
|
||||||
<h2>使用方法</h2>
|
|
||||||
<p style="line-height: 50px">
|
|
||||||
直接通过设置类名为 el-icon-lx-iconName 来使用即可。例如:(共{{ iconList.length }}个图标)
|
|
||||||
</p>
|
|
||||||
<p class="example-p">
|
|
||||||
<i class="el-icon-lx-redpacket_fill" style="font-size: 30px; color: #ff5900"></i>
|
|
||||||
<span><i class="el-icon-lx-redpacket_fill"></i></span>
|
|
||||||
</p>
|
|
||||||
<p class="example-p">
|
|
||||||
<i class="el-icon-lx-weibo" style="font-size: 30px; color: #fd5656"></i>
|
|
||||||
<span><i class="el-icon-lx-weibo"></i></span>
|
|
||||||
</p>
|
|
||||||
<p class="example-p">
|
|
||||||
<i class="el-icon-lx-emojifill" style="font-size: 30px; color: #ffc300"></i>
|
|
||||||
<span><i class="el-icon-lx-emojifill"></i></span>
|
|
||||||
</p>
|
|
||||||
<br />
|
|
||||||
<h2>图标</h2>
|
|
||||||
<div class="search-box">
|
|
||||||
<el-input class="search" size="large" v-model="keyword" clearable placeholder="请输入图标名称"></el-input>
|
|
||||||
</div>
|
|
||||||
<ul>
|
|
||||||
<li class="icon-li" v-for="(item, index) in list" :key="index">
|
|
||||||
<div class="icon-li-content">
|
|
||||||
<i :class="`el-icon-lx-${item}`"></i>
|
|
||||||
<span>{{ item }}</span>
|
|
||||||
</div>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script setup lang="ts" name="icon">
|
|
||||||
import { computed, ref } from 'vue';
|
|
||||||
|
|
||||||
const iconList: Array<string> = [
|
|
||||||
'attentionforbid',
|
|
||||||
'attentionforbidfill',
|
|
||||||
'attention',
|
|
||||||
'attentionfill',
|
|
||||||
'tag',
|
|
||||||
'tagfill',
|
|
||||||
'people',
|
|
||||||
'peoplefill',
|
|
||||||
'notice',
|
|
||||||
'noticefill',
|
|
||||||
'mobile',
|
|
||||||
'mobilefill',
|
|
||||||
'voice',
|
|
||||||
'voicefill',
|
|
||||||
'unlock',
|
|
||||||
'lock',
|
|
||||||
'home',
|
|
||||||
'homefill',
|
|
||||||
'delete',
|
|
||||||
'deletefill',
|
|
||||||
'notification',
|
|
||||||
'notificationfill',
|
|
||||||
'notificationforbidfill',
|
|
||||||
'like',
|
|
||||||
'likefill',
|
|
||||||
'comment',
|
|
||||||
'commentfill',
|
|
||||||
'camera',
|
|
||||||
'camerafill',
|
|
||||||
'warn',
|
|
||||||
'warnfill',
|
|
||||||
'time',
|
|
||||||
'timefill',
|
|
||||||
'location',
|
|
||||||
'locationfill',
|
|
||||||
'favor',
|
|
||||||
'favorfill',
|
|
||||||
'skin',
|
|
||||||
'skinfill',
|
|
||||||
'news',
|
|
||||||
'newsfill',
|
|
||||||
'record',
|
|
||||||
'recordfill',
|
|
||||||
'emoji',
|
|
||||||
'emojifill',
|
|
||||||
'message',
|
|
||||||
'messagefill',
|
|
||||||
'goods',
|
|
||||||
'goodsfill',
|
|
||||||
'crown',
|
|
||||||
'crownfill',
|
|
||||||
'move',
|
|
||||||
'add',
|
|
||||||
'hot',
|
|
||||||
'hotfill',
|
|
||||||
'service',
|
|
||||||
'servicefill',
|
|
||||||
'present',
|
|
||||||
'presentfill',
|
|
||||||
'pic',
|
|
||||||
'picfill',
|
|
||||||
'rank',
|
|
||||||
'rankfill',
|
|
||||||
'male',
|
|
||||||
'female',
|
|
||||||
'down',
|
|
||||||
'top',
|
|
||||||
'recharge',
|
|
||||||
'rechargefill',
|
|
||||||
'forward',
|
|
||||||
'forwardfill',
|
|
||||||
'info',
|
|
||||||
'infofill',
|
|
||||||
'redpacket',
|
|
||||||
'redpacket_fill',
|
|
||||||
'roundadd',
|
|
||||||
'roundaddfill',
|
|
||||||
'friendadd',
|
|
||||||
'friendaddfill',
|
|
||||||
'cart',
|
|
||||||
'cartfill',
|
|
||||||
'more',
|
|
||||||
'moreandroid',
|
|
||||||
'back',
|
|
||||||
'right',
|
|
||||||
'shop',
|
|
||||||
'shopfill',
|
|
||||||
'question',
|
|
||||||
'questionfill',
|
|
||||||
'roundclose',
|
|
||||||
'roundclosefill',
|
|
||||||
'roundcheck',
|
|
||||||
'roundcheckfill',
|
|
||||||
'global',
|
|
||||||
'mail',
|
|
||||||
'punch',
|
|
||||||
'exit',
|
|
||||||
'upload',
|
|
||||||
'read',
|
|
||||||
'file',
|
|
||||||
'link',
|
|
||||||
'full',
|
|
||||||
'group',
|
|
||||||
'friend',
|
|
||||||
'profile',
|
|
||||||
'addressbook',
|
|
||||||
'calendar',
|
|
||||||
'text',
|
|
||||||
'copy',
|
|
||||||
'share',
|
|
||||||
'wifi',
|
|
||||||
'vipcard',
|
|
||||||
'weibo',
|
|
||||||
'remind',
|
|
||||||
'refresh',
|
|
||||||
'filter',
|
|
||||||
'settings',
|
|
||||||
'scan',
|
|
||||||
'qrcode',
|
|
||||||
'cascades',
|
|
||||||
'apps',
|
|
||||||
'sort',
|
|
||||||
'searchlist',
|
|
||||||
'search',
|
|
||||||
'edit'
|
|
||||||
];
|
|
||||||
const keyword = ref('');
|
|
||||||
const list = computed(() => {
|
|
||||||
return iconList.filter(item => {
|
|
||||||
return item.indexOf(keyword.value) !== -1;
|
|
||||||
});
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style scoped>
|
|
||||||
.example-p {
|
|
||||||
height: 45px;
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
}
|
|
||||||
.search-box {
|
|
||||||
text-align: center;
|
|
||||||
margin-top: 10px;
|
|
||||||
}
|
|
||||||
.search {
|
|
||||||
width: 300px;
|
|
||||||
}
|
|
||||||
ul,
|
|
||||||
li {
|
|
||||||
list-style: none;
|
|
||||||
}
|
|
||||||
.icon-li {
|
|
||||||
display: inline-block;
|
|
||||||
padding: 10px;
|
|
||||||
width: 120px;
|
|
||||||
height: 120px;
|
|
||||||
}
|
|
||||||
.icon-li-content {
|
|
||||||
display: flex;
|
|
||||||
height: 100%;
|
|
||||||
flex-direction: column;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
.icon-li-content i {
|
|
||||||
font-size: 36px;
|
|
||||||
color: #606266;
|
|
||||||
}
|
|
||||||
.icon-li-content span {
|
|
||||||
margin-top: 10px;
|
|
||||||
color: #787878;
|
|
||||||
}
|
|
||||||
</style>
|
|
@ -1,118 +0,0 @@
|
|||||||
<template>
|
|
||||||
<div>
|
|
||||||
<div class="container">
|
|
||||||
<div class="handle-box">
|
|
||||||
<el-upload
|
|
||||||
action="#"
|
|
||||||
:limit="1"
|
|
||||||
accept=".xlsx, .xls"
|
|
||||||
:show-file-list="false"
|
|
||||||
:before-upload="beforeUpload"
|
|
||||||
:http-request="handleMany"
|
|
||||||
>
|
|
||||||
<el-button class="mr10" type="success">批量导入</el-button>
|
|
||||||
</el-upload>
|
|
||||||
<el-link href="/template.xlsx" target="_blank">下载模板</el-link>
|
|
||||||
</div>
|
|
||||||
<el-table :data="tableData" border class="table" header-cell-class-name="table-header">
|
|
||||||
<el-table-column prop="id" label="ID" width="55" align="center"></el-table-column>
|
|
||||||
<el-table-column prop="name" label="姓名"></el-table-column>
|
|
||||||
<el-table-column prop="sno" label="学号"></el-table-column>
|
|
||||||
<el-table-column prop="class" label="班级"></el-table-column>
|
|
||||||
<el-table-column prop="age" label="年龄"></el-table-column>
|
|
||||||
<el-table-column prop="sex" label="性别"></el-table-column>
|
|
||||||
</el-table>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script setup lang="ts" name="import">
|
|
||||||
import { UploadProps } from 'element-plus';
|
|
||||||
import { ref, reactive } from 'vue';
|
|
||||||
import * as XLSX from 'xlsx';
|
|
||||||
|
|
||||||
interface TableItem {
|
|
||||||
id: number;
|
|
||||||
name: string;
|
|
||||||
sno: string;
|
|
||||||
class: string;
|
|
||||||
age: string;
|
|
||||||
sex: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
const tableData = ref<TableItem[]>([]);
|
|
||||||
// 获取表格数据
|
|
||||||
const getData = () => {
|
|
||||||
tableData.value = [
|
|
||||||
{
|
|
||||||
id: 1,
|
|
||||||
name: '小明',
|
|
||||||
sno: 'S001',
|
|
||||||
class: '一班',
|
|
||||||
age: '10',
|
|
||||||
sex: '男',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 2,
|
|
||||||
name: '小红',
|
|
||||||
sno: 'S002',
|
|
||||||
class: '一班',
|
|
||||||
age: '9',
|
|
||||||
sex: '女',
|
|
||||||
},
|
|
||||||
];
|
|
||||||
};
|
|
||||||
getData();
|
|
||||||
|
|
||||||
const importList = ref<any>([]);
|
|
||||||
const beforeUpload: UploadProps['beforeUpload'] = async (rawFile) => {
|
|
||||||
importList.value = await analysisExcel(rawFile);
|
|
||||||
return true;
|
|
||||||
};
|
|
||||||
const analysisExcel = (file: any) => {
|
|
||||||
return new Promise(function (resolve, reject) {
|
|
||||||
const reader = new FileReader();
|
|
||||||
reader.onload = function (e: any) {
|
|
||||||
const data = e.target.result;
|
|
||||||
let datajson = XLSX.read(data, {
|
|
||||||
type: 'binary',
|
|
||||||
});
|
|
||||||
|
|
||||||
const sheetName = datajson.SheetNames[0];
|
|
||||||
const result = XLSX.utils.sheet_to_json(datajson.Sheets[sheetName]);
|
|
||||||
resolve(result);
|
|
||||||
};
|
|
||||||
reader.readAsBinaryString(file);
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleMany = async () => {
|
|
||||||
// 把数据传给服务器后获取最新列表,这里只是示例,不做请求
|
|
||||||
const list = importList.value.map((item: any, index: number) => {
|
|
||||||
return {
|
|
||||||
id: index,
|
|
||||||
name: item['姓名'],
|
|
||||||
sno: item['学号'],
|
|
||||||
class: item['班级'],
|
|
||||||
age: item['年龄'],
|
|
||||||
sex: item['性别'],
|
|
||||||
};
|
|
||||||
});
|
|
||||||
tableData.value.push(...list);
|
|
||||||
};
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style scoped>
|
|
||||||
.handle-box {
|
|
||||||
display: flex;
|
|
||||||
margin-bottom: 20px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.table {
|
|
||||||
width: 100%;
|
|
||||||
font-size: 14px;
|
|
||||||
}
|
|
||||||
.mr10 {
|
|
||||||
margin-right: 10px;
|
|
||||||
}
|
|
||||||
</style>
|
|
@ -1,21 +0,0 @@
|
|||||||
<template>
|
|
||||||
<div class="container">
|
|
||||||
<div class="plugins-tips">
|
|
||||||
md-editor-v3:vue3版本的 markdown 编辑器,配置丰富,请详看文档。 访问地址:
|
|
||||||
<a href="https://imzbf.github.io/md-editor-v3/index" target="_blank">md-editor-v3</a>
|
|
||||||
</div>
|
|
||||||
<md-editor class="mgb20" v-model="text" @on-upload-img="onUploadImg" />
|
|
||||||
<el-button type="primary">提交</el-button>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script setup lang="ts" name="md">
|
|
||||||
import { ref } from 'vue';
|
|
||||||
import MdEditor from 'md-editor-v3';
|
|
||||||
import 'md-editor-v3/lib/style.css';
|
|
||||||
|
|
||||||
const text = ref('Hello Editor!');
|
|
||||||
const onUploadImg = (files: any) => {
|
|
||||||
console.log(files);
|
|
||||||
};
|
|
||||||
</script>
|
|
@ -1,191 +0,0 @@
|
|||||||
<template>
|
|
||||||
<div>
|
|
||||||
<div class="container">
|
|
||||||
<div class="handle-box">
|
|
||||||
<el-select v-model="query.address" placeholder="地址" class="handle-select mr10">
|
|
||||||
<el-option key="1" label="广东省" value="广东省"></el-option>
|
|
||||||
<el-option key="2" label="湖南省" value="湖南省"></el-option>
|
|
||||||
</el-select>
|
|
||||||
<el-input v-model="query.name" placeholder="用户名" class="handle-input mr10"></el-input>
|
|
||||||
<el-button type="primary" :icon="Search" @click="handleSearch">搜索</el-button>
|
|
||||||
<el-button type="primary" :icon="Plus">新增</el-button>
|
|
||||||
</div>
|
|
||||||
<el-table :data="tableData" border class="table" ref="multipleTable" header-cell-class-name="table-header">
|
|
||||||
<el-table-column prop="id" label="ID" width="55" align="center"></el-table-column>
|
|
||||||
<el-table-column prop="name" label="用户名"></el-table-column>
|
|
||||||
<el-table-column label="账户余额">
|
|
||||||
<template #default="scope">¥{{ scope.row.money }}</template>
|
|
||||||
</el-table-column>
|
|
||||||
<el-table-column label="头像(查看大图)" align="center">
|
|
||||||
<template #default="scope">
|
|
||||||
<el-image
|
|
||||||
class="table-td-thumb"
|
|
||||||
:src="scope.row.thumb"
|
|
||||||
:z-index="10"
|
|
||||||
:preview-src-list="[scope.row.thumb]"
|
|
||||||
preview-teleported
|
|
||||||
>
|
|
||||||
</el-image>
|
|
||||||
</template>
|
|
||||||
</el-table-column>
|
|
||||||
<el-table-column prop="address" label="地址"></el-table-column>
|
|
||||||
<el-table-column label="状态" align="center">
|
|
||||||
<template #default="scope">
|
|
||||||
<el-tag
|
|
||||||
:type="scope.row.state === '成功' ? 'success' : scope.row.state === '失败' ? 'danger' : ''"
|
|
||||||
>
|
|
||||||
{{ scope.row.state }}
|
|
||||||
</el-tag>
|
|
||||||
</template>
|
|
||||||
</el-table-column>
|
|
||||||
|
|
||||||
<el-table-column prop="date" label="注册时间"></el-table-column>
|
|
||||||
<el-table-column label="操作" width="220" align="center">
|
|
||||||
<template #default="scope">
|
|
||||||
<el-button text :icon="Edit" @click="handleEdit(scope.$index, scope.row)" v-permiss="'default'">
|
|
||||||
编辑
|
|
||||||
</el-button>
|
|
||||||
<el-button text :icon="Delete" class="red" @click="handleDelete(scope.$index)" v-permiss="'default'">
|
|
||||||
删除
|
|
||||||
</el-button>
|
|
||||||
</template>
|
|
||||||
</el-table-column>
|
|
||||||
</el-table>
|
|
||||||
<div class="pagination">
|
|
||||||
<el-pagination
|
|
||||||
background
|
|
||||||
layout="total, prev, pager, next"
|
|
||||||
:current-page="query.pageIndex"
|
|
||||||
:page-size="query.pageSize"
|
|
||||||
:total="pageTotal"
|
|
||||||
@current-change="handlePageChange"
|
|
||||||
></el-pagination>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- 编辑弹出框 -->
|
|
||||||
<el-dialog title="编辑" v-model="editVisible" width="30%">
|
|
||||||
<el-form label-width="70px">
|
|
||||||
<el-form-item label="用户名">
|
|
||||||
<el-input v-model="form.name"></el-input>
|
|
||||||
</el-form-item>
|
|
||||||
<el-form-item label="地址">
|
|
||||||
<el-input v-model="form.address"></el-input>
|
|
||||||
</el-form-item>
|
|
||||||
</el-form>
|
|
||||||
<template #footer>
|
|
||||||
<span class="dialog-footer">
|
|
||||||
<el-button @click="editVisible = false">取 消</el-button>
|
|
||||||
<el-button type="primary" @click="saveEdit">确 定</el-button>
|
|
||||||
</span>
|
|
||||||
</template>
|
|
||||||
</el-dialog>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script setup lang="ts" name="basetable">
|
|
||||||
import { ref, reactive } from 'vue';
|
|
||||||
import { ElMessage, ElMessageBox } from 'element-plus';
|
|
||||||
import { Delete, Edit, Search, Plus } from '@element-plus/icons-vue';
|
|
||||||
import { fetchData } from '../../api/index';
|
|
||||||
|
|
||||||
interface TableItem {
|
|
||||||
id: number;
|
|
||||||
name: string;
|
|
||||||
money: string;
|
|
||||||
state: string;
|
|
||||||
date: string;
|
|
||||||
address: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
const query = reactive({
|
|
||||||
address: '',
|
|
||||||
name: '',
|
|
||||||
pageIndex: 1,
|
|
||||||
pageSize: 10
|
|
||||||
});
|
|
||||||
const tableData = ref<TableItem[]>([]);
|
|
||||||
const pageTotal = ref(0);
|
|
||||||
// 获取表格数据
|
|
||||||
const getData = () => {
|
|
||||||
fetchData().then(res => {
|
|
||||||
tableData.value = res.data.list;
|
|
||||||
pageTotal.value = res.data.pageTotal || 50;
|
|
||||||
});
|
|
||||||
};
|
|
||||||
getData();
|
|
||||||
|
|
||||||
// 查询操作
|
|
||||||
const handleSearch = () => {
|
|
||||||
query.pageIndex = 1;
|
|
||||||
getData();
|
|
||||||
};
|
|
||||||
// 分页导航
|
|
||||||
const handlePageChange = (val: number) => {
|
|
||||||
query.pageIndex = val;
|
|
||||||
getData();
|
|
||||||
};
|
|
||||||
|
|
||||||
// 删除操作
|
|
||||||
const handleDelete = (index: number) => {
|
|
||||||
// 二次确认删除
|
|
||||||
ElMessageBox.confirm('确定要删除吗?', '提示', {
|
|
||||||
type: 'warning'
|
|
||||||
})
|
|
||||||
.then(() => {
|
|
||||||
ElMessage.success('删除成功');
|
|
||||||
tableData.value.splice(index, 1);
|
|
||||||
})
|
|
||||||
.catch(() => {});
|
|
||||||
};
|
|
||||||
|
|
||||||
// 表格编辑时弹窗和保存
|
|
||||||
const editVisible = ref(false);
|
|
||||||
let form = reactive({
|
|
||||||
name: '',
|
|
||||||
address: ''
|
|
||||||
});
|
|
||||||
let idx: number = -1;
|
|
||||||
const handleEdit = (index: number, row: any) => {
|
|
||||||
idx = index;
|
|
||||||
form.name = row.name;
|
|
||||||
form.address = row.address;
|
|
||||||
editVisible.value = true;
|
|
||||||
};
|
|
||||||
const saveEdit = () => {
|
|
||||||
editVisible.value = false;
|
|
||||||
ElMessage.success(`修改第 ${idx + 1} 行成功`);
|
|
||||||
tableData.value[idx].name = form.name;
|
|
||||||
tableData.value[idx].address = form.address;
|
|
||||||
};
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style scoped>
|
|
||||||
.handle-box {
|
|
||||||
margin-bottom: 20px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.handle-select {
|
|
||||||
width: 120px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.handle-input {
|
|
||||||
width: 300px;
|
|
||||||
}
|
|
||||||
.table {
|
|
||||||
width: 100%;
|
|
||||||
font-size: 14px;
|
|
||||||
}
|
|
||||||
.red {
|
|
||||||
color: #F56C6C;
|
|
||||||
}
|
|
||||||
.mr10 {
|
|
||||||
margin-right: 10px;
|
|
||||||
}
|
|
||||||
.table-td-thumb {
|
|
||||||
display: block;
|
|
||||||
margin: auto;
|
|
||||||
width: 40px;
|
|
||||||
height: 40px;
|
|
||||||
}
|
|
||||||
</style>
|
|
@ -1,116 +0,0 @@
|
|||||||
<template>
|
|
||||||
<div class="container">
|
|
||||||
<el-tabs v-model="message">
|
|
||||||
<el-tab-pane :label="`未读消息(${state.unread.length})`" name="first">
|
|
||||||
<el-table :data="state.unread" :show-header="false" style="width: 100%">
|
|
||||||
<el-table-column>
|
|
||||||
<template #default="scope">
|
|
||||||
<span class="message-title">{{ scope.row.title }}</span>
|
|
||||||
</template>
|
|
||||||
</el-table-column>
|
|
||||||
<el-table-column prop="date" width="180"></el-table-column>
|
|
||||||
<el-table-column width="120">
|
|
||||||
<template #default="scope">
|
|
||||||
<el-button size="small" @click="handleRead(scope.$index)">标为已读</el-button>
|
|
||||||
</template>
|
|
||||||
</el-table-column>
|
|
||||||
</el-table>
|
|
||||||
<div class="handle-row">
|
|
||||||
<el-button type="primary">全部标为已读</el-button>
|
|
||||||
</div>
|
|
||||||
</el-tab-pane>
|
|
||||||
<el-tab-pane :label="`已读消息(${state.read.length})`" name="second">
|
|
||||||
<template v-if="message === 'second'">
|
|
||||||
<el-table :data="state.read" :show-header="false" style="width: 100%">
|
|
||||||
<el-table-column>
|
|
||||||
<template #default="scope">
|
|
||||||
<span class="message-title">{{ scope.row.title }}</span>
|
|
||||||
</template>
|
|
||||||
</el-table-column>
|
|
||||||
<el-table-column prop="date" width="150"></el-table-column>
|
|
||||||
<el-table-column width="120">
|
|
||||||
<template #default="scope">
|
|
||||||
<el-button type="danger" @click="handleDel(scope.$index)">删除</el-button>
|
|
||||||
</template>
|
|
||||||
</el-table-column>
|
|
||||||
</el-table>
|
|
||||||
<div class="handle-row">
|
|
||||||
<el-button type="danger">删除全部</el-button>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
</el-tab-pane>
|
|
||||||
<el-tab-pane :label="`回收站(${state.recycle.length})`" name="third">
|
|
||||||
<template v-if="message === 'third'">
|
|
||||||
<el-table :data="state.recycle" :show-header="false" style="width: 100%">
|
|
||||||
<el-table-column>
|
|
||||||
<template #default="scope">
|
|
||||||
<span class="message-title">{{ scope.row.title }}</span>
|
|
||||||
</template>
|
|
||||||
</el-table-column>
|
|
||||||
<el-table-column prop="date" width="150"></el-table-column>
|
|
||||||
<el-table-column width="120">
|
|
||||||
<template #default="scope">
|
|
||||||
<el-button @click="handleRestore(scope.$index)">还原</el-button>
|
|
||||||
</template>
|
|
||||||
</el-table-column>
|
|
||||||
</el-table>
|
|
||||||
<div class="handle-row">
|
|
||||||
<el-button type="danger">清空回收站</el-button>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
</el-tab-pane>
|
|
||||||
</el-tabs>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script setup lang="ts" name="tabs">
|
|
||||||
import { ref, reactive } from 'vue';
|
|
||||||
|
|
||||||
const message = ref('first');
|
|
||||||
const state = reactive({
|
|
||||||
unread: [
|
|
||||||
{
|
|
||||||
date: '2018-04-19 20:00:00',
|
|
||||||
title: '【系统通知】该系统将于今晚凌晨2点到5点进行升级维护'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
date: '2018-04-19 21:00:00',
|
|
||||||
title: '今晚12点整发大红包,先到先得'
|
|
||||||
}
|
|
||||||
],
|
|
||||||
read: [
|
|
||||||
{
|
|
||||||
date: '2018-04-19 20:00:00',
|
|
||||||
title: '【系统通知】该系统将于今晚凌晨2点到5点进行升级维护'
|
|
||||||
}
|
|
||||||
],
|
|
||||||
recycle: [
|
|
||||||
{
|
|
||||||
date: '2018-04-19 20:00:00',
|
|
||||||
title: '【系统通知】该系统将于今晚凌晨2点到5点进行升级维护'
|
|
||||||
}
|
|
||||||
]
|
|
||||||
});
|
|
||||||
|
|
||||||
const handleRead = (index: number) => {
|
|
||||||
const item = state.unread.splice(index, 1);
|
|
||||||
state.read = item.concat(state.read);
|
|
||||||
};
|
|
||||||
const handleDel = (index: number) => {
|
|
||||||
const item = state.read.splice(index, 1);
|
|
||||||
state.recycle = item.concat(state.recycle);
|
|
||||||
};
|
|
||||||
const handleRestore = (index: number) => {
|
|
||||||
const item = state.recycle.splice(index, 1);
|
|
||||||
state.read = item.concat(state.read);
|
|
||||||
};
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style>
|
|
||||||
.message-title {
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
.handle-row {
|
|
||||||
margin-top: 30px;
|
|
||||||
}
|
|
||||||
</style>
|
|
@ -1,174 +0,0 @@
|
|||||||
<template>
|
|
||||||
<div>
|
|
||||||
<el-row :gutter="20">
|
|
||||||
<el-col :span="12">
|
|
||||||
<el-card shadow="hover">
|
|
||||||
<template #header>
|
|
||||||
<div class="clearfix">
|
|
||||||
<span>基础信息</span>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
<div class="info">
|
|
||||||
<div class="info-image" @click="showDialog">
|
|
||||||
<el-avatar :size="100" :src="avatarImg" />
|
|
||||||
<span class="info-edit">
|
|
||||||
<i class="el-icon-lx-camerafill"></i>
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
<div class="info-name">{{ name }}</div>
|
|
||||||
<div class="info-desc">不可能!我的代码怎么可能会有bug!</div>
|
|
||||||
</div>
|
|
||||||
</el-card>
|
|
||||||
</el-col>
|
|
||||||
<el-col :span="12">
|
|
||||||
<el-card shadow="hover">
|
|
||||||
<template #header>
|
|
||||||
<div class="clearfix">
|
|
||||||
<span>账户编辑</span>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
<el-form label-width="90px">
|
|
||||||
<el-form-item label="用户名:"> {{ name }} </el-form-item>
|
|
||||||
<el-form-item label="旧密码:">
|
|
||||||
<el-input type="password" v-model="form.old"></el-input>
|
|
||||||
</el-form-item>
|
|
||||||
<el-form-item label="新密码:">
|
|
||||||
<el-input type="password" v-model="form.new"></el-input>
|
|
||||||
</el-form-item>
|
|
||||||
<el-form-item label="个人简介:">
|
|
||||||
<el-input v-model="form.desc"></el-input>
|
|
||||||
</el-form-item>
|
|
||||||
<el-form-item>
|
|
||||||
<el-button type="primary" @click="onSubmit">保存</el-button>
|
|
||||||
</el-form-item>
|
|
||||||
</el-form>
|
|
||||||
</el-card>
|
|
||||||
</el-col>
|
|
||||||
</el-row>
|
|
||||||
<el-dialog title="裁剪图片" v-model="dialogVisible" width="600px">
|
|
||||||
<vue-cropper
|
|
||||||
ref="cropper"
|
|
||||||
:src="imgSrc"
|
|
||||||
:ready="cropImage"
|
|
||||||
:zoom="cropImage"
|
|
||||||
:cropmove="cropImage"
|
|
||||||
style="width: 100%; height: 400px"
|
|
||||||
></vue-cropper>
|
|
||||||
|
|
||||||
<template #footer>
|
|
||||||
<span class="dialog-footer">
|
|
||||||
<el-button class="crop-demo-btn" type="primary"
|
|
||||||
>选择图片
|
|
||||||
<input class="crop-input" type="file" name="image" accept="image/*" @change="setImage" />
|
|
||||||
</el-button>
|
|
||||||
<el-button type="primary" @click="saveAvatar">上传并保存</el-button>
|
|
||||||
</span>
|
|
||||||
</template>
|
|
||||||
</el-dialog>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script setup lang="ts" name="user">
|
|
||||||
import { reactive, ref } from 'vue';
|
|
||||||
import VueCropper from 'vue-cropperjs';
|
|
||||||
import 'cropperjs/dist/cropper.css';
|
|
||||||
import avatar from '../../assets/img/img.jpg';
|
|
||||||
|
|
||||||
const name = localStorage.getItem('ms_username');
|
|
||||||
const form = reactive({
|
|
||||||
old: '',
|
|
||||||
new: '',
|
|
||||||
desc: '不可能!我的代码怎么可能会有bug!'
|
|
||||||
});
|
|
||||||
const onSubmit = () => {};
|
|
||||||
|
|
||||||
const avatarImg = ref(avatar);
|
|
||||||
const imgSrc = ref('');
|
|
||||||
const cropImg = ref('');
|
|
||||||
const dialogVisible = ref(false);
|
|
||||||
const cropper: any = ref();
|
|
||||||
|
|
||||||
const showDialog = () => {
|
|
||||||
dialogVisible.value = true;
|
|
||||||
imgSrc.value = avatarImg.value;
|
|
||||||
};
|
|
||||||
|
|
||||||
const setImage = (e: any) => {
|
|
||||||
const file = e.target.files[0];
|
|
||||||
if (!file.type.includes('image/')) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const reader = new FileReader();
|
|
||||||
reader.onload = (event: any) => {
|
|
||||||
dialogVisible.value = true;
|
|
||||||
imgSrc.value = event.target.result;
|
|
||||||
cropper.value && cropper.value.replace(event.target.result);
|
|
||||||
};
|
|
||||||
reader.readAsDataURL(file);
|
|
||||||
};
|
|
||||||
|
|
||||||
const cropImage = () => {
|
|
||||||
cropImg.value = cropper.value.getCroppedCanvas().toDataURL();
|
|
||||||
};
|
|
||||||
|
|
||||||
const saveAvatar = () => {
|
|
||||||
avatarImg.value = cropImg.value;
|
|
||||||
dialogVisible.value = false;
|
|
||||||
};
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style scoped>
|
|
||||||
.info {
|
|
||||||
text-align: center;
|
|
||||||
padding: 35px 0;
|
|
||||||
}
|
|
||||||
.info-image {
|
|
||||||
position: relative;
|
|
||||||
margin: auto;
|
|
||||||
width: 100px;
|
|
||||||
height: 100px;
|
|
||||||
background: #f8f8f8;
|
|
||||||
border: 1px solid #eee;
|
|
||||||
border-radius: 50px;
|
|
||||||
overflow: hidden;
|
|
||||||
}
|
|
||||||
|
|
||||||
.info-edit {
|
|
||||||
display: flex;
|
|
||||||
justify-content: center;
|
|
||||||
align-items: center;
|
|
||||||
position: absolute;
|
|
||||||
left: 0;
|
|
||||||
top: 0;
|
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
background: rgba(0, 0, 0, 0.5);
|
|
||||||
opacity: 0;
|
|
||||||
transition: opacity 0.3s ease;
|
|
||||||
}
|
|
||||||
.info-edit i {
|
|
||||||
color: #eee;
|
|
||||||
font-size: 25px;
|
|
||||||
}
|
|
||||||
.info-image:hover .info-edit {
|
|
||||||
opacity: 1;
|
|
||||||
}
|
|
||||||
.info-name {
|
|
||||||
margin: 15px 0 10px;
|
|
||||||
font-size: 24px;
|
|
||||||
font-weight: 500;
|
|
||||||
color: #262626;
|
|
||||||
}
|
|
||||||
.crop-demo-btn {
|
|
||||||
position: relative;
|
|
||||||
}
|
|
||||||
.crop-input {
|
|
||||||
position: absolute;
|
|
||||||
width: 100px;
|
|
||||||
height: 40px;
|
|
||||||
left: 0;
|
|
||||||
top: 0;
|
|
||||||
opacity: 0;
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
</style>
|
|
@ -1,389 +0,0 @@
|
|||||||
<template>
|
|
||||||
<div>
|
|
||||||
<div class="container">
|
|
||||||
<!-- 筛选 -->
|
|
||||||
<div class="handle-box">
|
|
||||||
<el-select v-model="query.params.deviceType" placeholder="设备类型" class="handle-select mr10"
|
|
||||||
style="width: 160px;">
|
|
||||||
<el-option :key="''" label="全部设备类型" :value="''"></el-option>
|
|
||||||
<el-option v-for="opt in deviceTypeOption" :key="opt.id" :label="opt.typeName"
|
|
||||||
:value="opt.id"></el-option>
|
|
||||||
</el-select>
|
|
||||||
<!-- <el-input v-model="query.params.name" placeholder="设备名" class="handle-input mr10"></el-input>
|
|
||||||
<el-button type="primary" :icon="Search" @click="handleSearch">搜索</el-button> -->
|
|
||||||
<el-button type="primary" :icon="Plus" @click="handleNew">新增设备</el-button>
|
|
||||||
<el-button type="primary" :icon="Plus" @click="exportExcel">导出设备列表</el-button>
|
|
||||||
</div>
|
|
||||||
<!-- 表格 -->
|
|
||||||
<el-table :data="tableData" border class="table" ref="multipleTable" header-cell-class-name="table-header">
|
|
||||||
<el-table-column prop="id" label="ID" width="55" align="center"></el-table-column>
|
|
||||||
<el-table-column prop="name" label="设备名称" align="center"></el-table-column>
|
|
||||||
<el-table-column prop="type" label="设备类型" align="center"></el-table-column>
|
|
||||||
<el-table-column prop="deviceName" label="设备ID" align="center"></el-table-column>
|
|
||||||
<el-table-column prop="location" label="设备位置" align="center"></el-table-column>
|
|
||||||
<el-table-column prop="contractor" label="承建商" align="center"></el-table-column>
|
|
||||||
<el-table-column prop="manufacturer" label="生产商" align="center"></el-table-column>
|
|
||||||
<el-table-column label="状态" align="center">
|
|
||||||
<template #default="scope">
|
|
||||||
<el-tag :type="scope.row.state === '在线' ? 'success' : (scope.row.state === '离线' ? 'danger' : '')">
|
|
||||||
{{ scope.row.state }}
|
|
||||||
</el-tag>
|
|
||||||
</template>
|
|
||||||
</el-table-column>
|
|
||||||
<el-table-column label="操作" width="220" align="center">
|
|
||||||
<template #default="scope">
|
|
||||||
<el-button text :icon="Edit" @click="handleEdit(scope.$index, scope.row)"
|
|
||||||
v-permiss="'equipment-setting-manage'">
|
|
||||||
编辑
|
|
||||||
</el-button>
|
|
||||||
<el-button text :icon="Delete" class="red" @click="handleDelete(scope.$index, scope.row)"
|
|
||||||
v-permiss="'equipment-setting-manage'">
|
|
||||||
删除
|
|
||||||
</el-button>
|
|
||||||
</template>
|
|
||||||
</el-table-column>
|
|
||||||
</el-table>
|
|
||||||
<!-- 分页 -->
|
|
||||||
<div class="pagination">
|
|
||||||
<el-pagination background layout="total, prev, pager, next" :current-page="query.pageIndex"
|
|
||||||
:page-size="query.pageSize" :total="pageTotal" @current-change="handlePageChange"></el-pagination>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- 编辑弹出框 -->
|
|
||||||
<el-dialog :title="formId > 0 ? '编辑' : '新增'" v-model="editVisible" style="width: 30%; min-width: 280px;">
|
|
||||||
<el-form ref="editForm" label-width="80px" :rules="rules" :model="form">
|
|
||||||
<el-form-item label="设备名称" prop="name">
|
|
||||||
<el-input class="popup-item" v-model="form.name"></el-input>
|
|
||||||
</el-form-item>
|
|
||||||
<el-form-item label="设备类型" prop="typeId">
|
|
||||||
<el-select class="popup-item" v-model="form.typeId" placeholder="设备类型">
|
|
||||||
<el-option :key="''" label="请选择设备类型" :value="''"></el-option>
|
|
||||||
<el-option v-for="opt in deviceTypeOption" :key="opt.id" :label="opt.typeName"
|
|
||||||
:value="opt.id"></el-option>
|
|
||||||
</el-select>
|
|
||||||
</el-form-item>
|
|
||||||
<el-form-item label="设备ID" prop="deviceName">
|
|
||||||
<el-input class="popup-item" v-model="form.deviceName"></el-input>
|
|
||||||
</el-form-item>
|
|
||||||
<el-form-item label="设备位置">
|
|
||||||
<el-input class="popup-item" v-model="form.location"></el-input>
|
|
||||||
</el-form-item>
|
|
||||||
<el-form-item label="承建商">
|
|
||||||
<el-input class="popup-item" v-model="form.contractor"></el-input>
|
|
||||||
</el-form-item>
|
|
||||||
<el-form-item label="生产商">
|
|
||||||
<el-input class="popup-item" v-model="form.manufacturer"></el-input>
|
|
||||||
</el-form-item>
|
|
||||||
</el-form>
|
|
||||||
<template #footer>
|
|
||||||
<span class="dialog-footer">
|
|
||||||
<el-button @click="editVisible = false">取 消</el-button>
|
|
||||||
<el-button type="primary" @click="saveEdit(editForm)">确 定</el-button>
|
|
||||||
</span>
|
|
||||||
</template>
|
|
||||||
</el-dialog>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script setup lang="ts">
|
|
||||||
import { ref, reactive, watch } from 'vue';
|
|
||||||
import { ElMessage, ElMessageBox } from 'element-plus';
|
|
||||||
import type { FormInstance, FormRules } from 'element-plus';
|
|
||||||
import { ElLoading } from 'element-plus';
|
|
||||||
import { Delete, Edit, Search, Plus } from '@element-plus/icons-vue';
|
|
||||||
import send_request from '../utils/send_request';
|
|
||||||
import * as XLSX from 'xlsx';
|
|
||||||
|
|
||||||
// 筛选条件
|
|
||||||
const query = reactive({
|
|
||||||
params: {
|
|
||||||
deviceType: '',
|
|
||||||
name: '',
|
|
||||||
},
|
|
||||||
pageIndex: 1,
|
|
||||||
pageSize: 10
|
|
||||||
});
|
|
||||||
|
|
||||||
// 下拉框数据
|
|
||||||
const deviceTypeOption = ref<[{ id: any, typeName: any }]>()
|
|
||||||
|
|
||||||
// 表格数据
|
|
||||||
const tableData: any = ref([]);
|
|
||||||
const pageTotal = ref(0);
|
|
||||||
const deviceTypeDict: any = ref({});
|
|
||||||
// 获取表格&下拉框数据
|
|
||||||
const getData = async () => {
|
|
||||||
const loading = ElLoading.service({
|
|
||||||
lock: true,
|
|
||||||
text: '请稍候',
|
|
||||||
background: 'rgba(0, 0, 0, 0.7)',
|
|
||||||
});
|
|
||||||
await send_request('v1/device/list', "GET", {
|
|
||||||
...query.params,
|
|
||||||
pageIndex: query.pageIndex,
|
|
||||||
pageSize: query.pageSize,
|
|
||||||
page: query.pageIndex,
|
|
||||||
}, (data: any) => {
|
|
||||||
|
|
||||||
let deviceList = data.list;
|
|
||||||
let deviceTypeList = data.optionDeviceType;
|
|
||||||
|
|
||||||
//生成"设备类型"数据字典
|
|
||||||
console.log("deviceList/deviceTypeList:", deviceList, deviceTypeList)
|
|
||||||
deviceTypeList.forEach((item: any) => deviceTypeDict.value[item.id] = item.typeName)
|
|
||||||
|
|
||||||
// 渲染表格
|
|
||||||
tableData.value = deviceList.list.map((i: any) => {
|
|
||||||
i.state = "在线"
|
|
||||||
i.type = deviceTypeDict.value[i.typeId]
|
|
||||||
return i
|
|
||||||
});
|
|
||||||
// console.log("tableData", tableData);
|
|
||||||
pageTotal.value = deviceList.total;
|
|
||||||
// 渲染下拉框
|
|
||||||
deviceTypeOption.value = deviceTypeList;
|
|
||||||
});
|
|
||||||
loading.close();
|
|
||||||
};
|
|
||||||
getData();
|
|
||||||
|
|
||||||
// 查询操作
|
|
||||||
const handleSearch = () => {
|
|
||||||
query.pageIndex = 1;
|
|
||||||
getData();
|
|
||||||
};
|
|
||||||
|
|
||||||
// 筛选条件变化自动搜索
|
|
||||||
watch(() => query.params, function (newVal, oldVal, ...args) {
|
|
||||||
console.log("watch query.params newVal", JSON.stringify(newVal))
|
|
||||||
console.log("watch query.params oldVal", JSON.stringify(oldVal))
|
|
||||||
console.log("watch query.params args", args)
|
|
||||||
handleSearch();
|
|
||||||
}, { deep: true });
|
|
||||||
|
|
||||||
// 分页导航
|
|
||||||
const handlePageChange = (val: number) => {
|
|
||||||
query.pageIndex = val;
|
|
||||||
getData();
|
|
||||||
};
|
|
||||||
|
|
||||||
// 删除操作
|
|
||||||
const handleDelete = (index: number, row: any) => {
|
|
||||||
// 二次确认删除
|
|
||||||
ElMessageBox.confirm('确定要删除吗?', '提示', {
|
|
||||||
type: 'warning'
|
|
||||||
})
|
|
||||||
.then(() => send_request('v1/device/delete', "POST", {
|
|
||||||
deviceId: row.id
|
|
||||||
}, (data: any) => {
|
|
||||||
// console.log(data);
|
|
||||||
ElMessage.success('删除成功');
|
|
||||||
tableData.value.splice(index, 1);
|
|
||||||
}))
|
|
||||||
.catch(() => {
|
|
||||||
ElMessage.success('删除失败');
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
// 添加/修改记录时表单验证
|
|
||||||
const editForm = ref<FormInstance>();
|
|
||||||
const rules: FormRules = {
|
|
||||||
name: [
|
|
||||||
{
|
|
||||||
required: true,
|
|
||||||
message: '请输入设备名称',
|
|
||||||
trigger: 'blur'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
min: 2,
|
|
||||||
message: '设备名称过短',
|
|
||||||
trigger: 'blur'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
max: 52,
|
|
||||||
message: '设备名称过长',
|
|
||||||
trigger: 'blur'
|
|
||||||
}
|
|
||||||
],
|
|
||||||
typeId: [
|
|
||||||
{
|
|
||||||
required: true,
|
|
||||||
message: '请选择设备类型',
|
|
||||||
trigger: 'blur'
|
|
||||||
}
|
|
||||||
],
|
|
||||||
deviceName: [
|
|
||||||
{
|
|
||||||
required: true,
|
|
||||||
message: '请输入设备ID',
|
|
||||||
trigger: 'blur'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
min: 2,
|
|
||||||
message: '设备ID过短',
|
|
||||||
trigger: 'blur'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
max: 52,
|
|
||||||
message: '设备ID过长',
|
|
||||||
trigger: 'blur'
|
|
||||||
}
|
|
||||||
],
|
|
||||||
};
|
|
||||||
// 表格编辑时弹窗和保存
|
|
||||||
const editVisible = ref(false);
|
|
||||||
let form = reactive({
|
|
||||||
name: '',
|
|
||||||
typeId: '',
|
|
||||||
deviceName: '',
|
|
||||||
location: '',
|
|
||||||
contractor: '',
|
|
||||||
manufacturer: '',
|
|
||||||
});
|
|
||||||
let idx: number = -1;
|
|
||||||
let formId: number = -1;
|
|
||||||
const handleEdit = (index: number, row: any) => {
|
|
||||||
idx = index;
|
|
||||||
formId = row.id;
|
|
||||||
form.name = row.name;
|
|
||||||
form.typeId = row.typeId;
|
|
||||||
form.deviceName = row.deviceName;
|
|
||||||
form.location = row.location;
|
|
||||||
form.contractor = row.contractor;
|
|
||||||
form.manufacturer = row.manufacturer;
|
|
||||||
editVisible.value = true;
|
|
||||||
};
|
|
||||||
// 新增弹窗
|
|
||||||
const handleNew = () => {
|
|
||||||
formId = -1;
|
|
||||||
for (let formKeys of Object.keys(form)) {
|
|
||||||
form[formKeys] = ''
|
|
||||||
}
|
|
||||||
editVisible.value = true;
|
|
||||||
};
|
|
||||||
|
|
||||||
const saveEdit = async (formEl: FormInstance | undefined) => {
|
|
||||||
if (!formEl) return;
|
|
||||||
// console.log("formEl", formEl);
|
|
||||||
formEl.validate(async (valid: boolean, invalidFields: any) => {
|
|
||||||
if (!valid) {
|
|
||||||
// console.log("invalidFields", invalidFields);
|
|
||||||
// 对表单中的每一个不合法输入框进行遍历
|
|
||||||
Object.values(invalidFields).forEach((input: any) => {
|
|
||||||
// 对该不合法输入框的提示信息进行遍历
|
|
||||||
input.forEach((element: any) => {
|
|
||||||
ElMessage.error({ message: element.message, grouping: true });
|
|
||||||
});
|
|
||||||
});
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (formId > 0) {
|
|
||||||
// 更新表格中数据
|
|
||||||
tableData.value[idx].name = form.name;
|
|
||||||
tableData.value[idx].typeId = form.typeId;
|
|
||||||
tableData.value[idx].deviceName = form.deviceName;
|
|
||||||
tableData.value[idx].location = form.location;
|
|
||||||
tableData.value[idx].contractor = form.contractor;
|
|
||||||
tableData.value[idx].manufacturer = form.manufacturer;
|
|
||||||
// 修改记录
|
|
||||||
await send_request('v1/device/edit', "POST", {
|
|
||||||
id: formId,
|
|
||||||
contractor: form.contractor,
|
|
||||||
deviceName: form.deviceName,
|
|
||||||
name: form.name,
|
|
||||||
location: form.location,
|
|
||||||
manufacturer: form.manufacturer,
|
|
||||||
typeId: form.typeId
|
|
||||||
}, (data: any) => {
|
|
||||||
// console.log(data)
|
|
||||||
// 关闭弹窗
|
|
||||||
editVisible.value = false;
|
|
||||||
ElMessage.success(`修改成功`);
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
// 新增记录
|
|
||||||
await send_request('v1/device/add', "POST", {
|
|
||||||
contractor: form.contractor,
|
|
||||||
deviceName: form.deviceName,
|
|
||||||
name: form.name,
|
|
||||||
location: form.location,
|
|
||||||
manufacturer: form.manufacturer,
|
|
||||||
typeId: form.typeId
|
|
||||||
}, (data: any) => {
|
|
||||||
// console.log(data)
|
|
||||||
// 关闭弹窗
|
|
||||||
editVisible.value = false;
|
|
||||||
ElMessage.success(`添加成功`);
|
|
||||||
query.pageIndex = Math.ceil((pageTotal.value + 1) / query.pageSize);
|
|
||||||
getData();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
// 导出设备到Excel列表
|
|
||||||
const exportExcel = async () => {
|
|
||||||
const loading = ElLoading.service({
|
|
||||||
lock: true,
|
|
||||||
text: '请稍候',
|
|
||||||
background: 'rgba(0, 0, 0, 0.7)',
|
|
||||||
});
|
|
||||||
|
|
||||||
let list = [['序号', '设备名称', '设备类型', '设备ID', '设备位置', '承建商', '生产商']];
|
|
||||||
await send_request('v1/device/listAll', "GET", {
|
|
||||||
}, (data: any) => {
|
|
||||||
data.list.map((item: any, i: number) => {
|
|
||||||
const arr: any[] = [i + 1];
|
|
||||||
// console.log("-----------------", arr);
|
|
||||||
arr.push(...[item.name, deviceTypeDict.value[item.typeId], item.deviceName, item.location, item.manufacturer, item.contractor]);
|
|
||||||
list.push(arr);
|
|
||||||
});
|
|
||||||
let WorkSheet = XLSX.utils.aoa_to_sheet(list);
|
|
||||||
let new_workbook = XLSX.utils.book_new();
|
|
||||||
XLSX.utils.book_append_sheet(new_workbook, WorkSheet, '第一页');
|
|
||||||
XLSX.writeFile(new_workbook, `表格.xlsx`);
|
|
||||||
});
|
|
||||||
loading.close();
|
|
||||||
}
|
|
||||||
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style scoped>
|
|
||||||
.handle-box {
|
|
||||||
margin-bottom: 20px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.handle-select {
|
|
||||||
width: 120px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.handle-input {
|
|
||||||
width: 300px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.table {
|
|
||||||
width: 100%;
|
|
||||||
font-size: 14px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.red {
|
|
||||||
color: #F56C6C;
|
|
||||||
}
|
|
||||||
|
|
||||||
.mr10 {
|
|
||||||
margin-right: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.table-td-thumb {
|
|
||||||
display: block;
|
|
||||||
margin: auto;
|
|
||||||
width: 40px;
|
|
||||||
height: 40px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.popup-item {
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
</style>
|
|
@ -1,182 +0,0 @@
|
|||||||
<template>
|
|
||||||
<div>
|
|
||||||
<div class="container">
|
|
||||||
<div class="handle-box">
|
|
||||||
<el-select v-model="query.address" placeholder="地址" class="handle-select mr10">
|
|
||||||
<el-option key="1" label="广东省" value="广东省"></el-option>
|
|
||||||
<el-option key="2" label="湖南省" value="湖南省"></el-option>
|
|
||||||
</el-select>
|
|
||||||
<el-input v-model="query.name" placeholder="用户名" class="handle-input mr10"></el-input>
|
|
||||||
<el-button type="primary" :icon="Search" @click="handleSearch">搜索</el-button>
|
|
||||||
<el-button type="primary" :icon="Plus">新增</el-button>
|
|
||||||
</div>
|
|
||||||
<el-table :data="tableData" border class="table" ref="multipleTable" header-cell-class-name="table-header">
|
|
||||||
<el-table-column prop="id" label="ID" width="55" align="center"></el-table-column>
|
|
||||||
<el-table-column prop="name" label="用户名"></el-table-column>
|
|
||||||
<el-table-column label="账户余额">
|
|
||||||
<template #default="scope">¥{{ scope.row.money }}</template>
|
|
||||||
</el-table-column>
|
|
||||||
<el-table-column label="头像(查看大图)" align="center">
|
|
||||||
<template #default="scope">
|
|
||||||
<el-image class="table-td-thumb" :src="scope.row.thumb" :z-index="10"
|
|
||||||
:preview-src-list="[scope.row.thumb]" preview-teleported>
|
|
||||||
</el-image>
|
|
||||||
</template>
|
|
||||||
</el-table-column>
|
|
||||||
<el-table-column prop="address" label="地址"></el-table-column>
|
|
||||||
<el-table-column label="状态" align="center">
|
|
||||||
<template #default="scope">
|
|
||||||
<el-tag :type="scope.row.state === '成功' ? 'success' : scope.row.state === '失败' ? 'danger' : ''">
|
|
||||||
{{ scope.row.state }}
|
|
||||||
</el-tag>
|
|
||||||
</template>
|
|
||||||
</el-table-column>
|
|
||||||
|
|
||||||
<el-table-column prop="date" label="注册时间"></el-table-column>
|
|
||||||
<el-table-column label="操作" width="220" align="center">
|
|
||||||
<template #default="scope">
|
|
||||||
<el-button text :icon="Edit" @click="handleEdit(scope.$index, scope.row)" v-permiss="15">
|
|
||||||
编辑
|
|
||||||
</el-button>
|
|
||||||
<el-button text :icon="Delete" class="red" @click="handleDelete(scope.$index)" v-permiss="16">
|
|
||||||
删除
|
|
||||||
</el-button>
|
|
||||||
</template>
|
|
||||||
</el-table-column>
|
|
||||||
</el-table>
|
|
||||||
<div class="pagination">
|
|
||||||
<el-pagination background layout="total, prev, pager, next" :current-page="query.pageIndex"
|
|
||||||
:page-size="query.pageSize" :total="pageTotal" @current-change="handlePageChange"></el-pagination>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- 编辑弹出框 -->
|
|
||||||
<el-dialog title="编辑" v-model="editVisible" width="30%">
|
|
||||||
<el-form label-width="70px">
|
|
||||||
<el-form-item label="用户名">
|
|
||||||
<el-input v-model="form.name"></el-input>
|
|
||||||
</el-form-item>
|
|
||||||
<el-form-item label="地址">
|
|
||||||
<el-input v-model="form.address"></el-input>
|
|
||||||
</el-form-item>
|
|
||||||
</el-form>
|
|
||||||
<template #footer>
|
|
||||||
<span class="dialog-footer">
|
|
||||||
<el-button @click="editVisible = false">取 消</el-button>
|
|
||||||
<el-button type="primary" @click="saveEdit">确 定</el-button>
|
|
||||||
</span>
|
|
||||||
</template>
|
|
||||||
</el-dialog>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script setup lang="ts">
|
|
||||||
import { ref, reactive } from 'vue';
|
|
||||||
import { ElMessage, ElMessageBox } from 'element-plus';
|
|
||||||
import { Delete, Edit, Search, Plus } from '@element-plus/icons-vue';
|
|
||||||
import { fetchData } from '../api/index';
|
|
||||||
|
|
||||||
interface TableItem {
|
|
||||||
id: number;
|
|
||||||
name: string;
|
|
||||||
money: string;
|
|
||||||
state: string;
|
|
||||||
date: string;
|
|
||||||
address: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
const query = reactive({
|
|
||||||
address: '',
|
|
||||||
name: '',
|
|
||||||
pageIndex: 1,
|
|
||||||
pageSize: 10
|
|
||||||
});
|
|
||||||
const tableData = ref<TableItem[]>([]);
|
|
||||||
const pageTotal = ref(0);
|
|
||||||
// 获取表格数据
|
|
||||||
const getData = () => {
|
|
||||||
fetchData().then(res => {
|
|
||||||
tableData.value = res.data.list;
|
|
||||||
pageTotal.value = res.data.pageTotal || 50;
|
|
||||||
});
|
|
||||||
};
|
|
||||||
getData();
|
|
||||||
|
|
||||||
// 查询操作
|
|
||||||
const handleSearch = () => {
|
|
||||||
query.pageIndex = 1;
|
|
||||||
getData();
|
|
||||||
};
|
|
||||||
// 分页导航
|
|
||||||
const handlePageChange = (val: number) => {
|
|
||||||
query.pageIndex = val;
|
|
||||||
getData();
|
|
||||||
};
|
|
||||||
|
|
||||||
// 删除操作
|
|
||||||
const handleDelete = (index: number) => {
|
|
||||||
// 二次确认删除
|
|
||||||
ElMessageBox.confirm('确定要删除吗?', '提示', {
|
|
||||||
type: 'warning'
|
|
||||||
})
|
|
||||||
.then(() => {
|
|
||||||
ElMessage.success('删除成功');
|
|
||||||
tableData.value.splice(index, 1);
|
|
||||||
})
|
|
||||||
.catch(() => { });
|
|
||||||
};
|
|
||||||
|
|
||||||
// 表格编辑时弹窗和保存
|
|
||||||
const editVisible = ref(false);
|
|
||||||
let form = reactive({
|
|
||||||
name: '',
|
|
||||||
address: ''
|
|
||||||
});
|
|
||||||
let idx: number = -1;
|
|
||||||
const handleEdit = (index: number, row: any) => {
|
|
||||||
idx = index;
|
|
||||||
form.name = row.name;
|
|
||||||
form.address = row.address;
|
|
||||||
editVisible.value = true;
|
|
||||||
};
|
|
||||||
const saveEdit = () => {
|
|
||||||
editVisible.value = false;
|
|
||||||
ElMessage.success(`修改第 ${idx + 1} 行成功`);
|
|
||||||
tableData.value[idx].name = form.name;
|
|
||||||
tableData.value[idx].address = form.address;
|
|
||||||
};
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style scoped>
|
|
||||||
.handle-box {
|
|
||||||
margin-bottom: 20px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.handle-select {
|
|
||||||
width: 120px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.handle-input {
|
|
||||||
width: 300px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.table {
|
|
||||||
width: 100%;
|
|
||||||
font-size: 14px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.red {
|
|
||||||
color: #F56C6C;
|
|
||||||
}
|
|
||||||
|
|
||||||
.mr10 {
|
|
||||||
margin-right: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.table-td-thumb {
|
|
||||||
display: block;
|
|
||||||
margin: auto;
|
|
||||||
width: 40px;
|
|
||||||
height: 40px;
|
|
||||||
}
|
|
||||||
</style>
|
|
@ -1,286 +0,0 @@
|
|||||||
<template>
|
|
||||||
<div class="container">
|
|
||||||
<div class="plugins-tips">角色及其对应的权限</div>
|
|
||||||
<!-- <div>
|
|
||||||
<span class="label">角色:</span>
|
|
||||||
<el-button type="primary" :icon="Search" @click="handleNew">增加</el-button>
|
|
||||||
<el-button type="primary" :icon="Search" @click="handleNew">修改</el-button>
|
|
||||||
<el-button type="primary" :icon="Search" @click="handleNew">删除</el-button>
|
|
||||||
</div> -->
|
|
||||||
|
|
||||||
<div style="display: grid; grid-template-columns: 1fr 3fr;">
|
|
||||||
<div style="margin-top: 40px;">
|
|
||||||
|
|
||||||
<div class="mgb20">
|
|
||||||
<span class="label">角色:</span>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div>
|
|
||||||
<el-radio-group v-model="selectRoleId" style="display: block;">
|
|
||||||
<el-radio :label="role.id" size="large" v-for="role in roleList" style="display: block;"
|
|
||||||
@click="() => { }">
|
|
||||||
{{ role.roleName }}
|
|
||||||
</el-radio>
|
|
||||||
</el-radio-group>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<div class="mgb20">
|
|
||||||
<span class="label">角色对应权限:</span>
|
|
||||||
<!-- <el-select v-model="role" @change="() => { }/*handleChange*/">
|
|
||||||
<el-option label="超级管理员" value="admin"></el-option>
|
|
||||||
<el-option label="普通用户" value="user"></el-option>
|
|
||||||
</el-select> -->
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="mgb20 tree-wrapper">
|
|
||||||
<el-tree ref="tree" :data="data" node-key="id" default-expand-all show-checkbox
|
|
||||||
:default-checked-keys="checkedKeys" />
|
|
||||||
</div>
|
|
||||||
<!-- <el-button type="primary" @click="onSubmit">保存权限</el-button> -->
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- 编辑弹出框 -->
|
|
||||||
<el-dialog :title="formId > 0 ? '编辑' : '新增'" v-model="editVisible" style="width: 30%; min-width: 280px;">
|
|
||||||
<el-form ref="editForm" label-width="80px" :rules="rules" :model="form">
|
|
||||||
<el-form-item label="角色名称" prop="roleName">
|
|
||||||
<el-input class="popup-item" v-model="form.roleName"></el-input>
|
|
||||||
</el-form-item>
|
|
||||||
<el-form-item label="备注">
|
|
||||||
<el-input class="popup-item" v-model="form.comment"></el-input>
|
|
||||||
</el-form-item>
|
|
||||||
</el-form>
|
|
||||||
<template #footer>
|
|
||||||
<span class="dialog-footer">
|
|
||||||
<el-button @click="editVisible = false">取 消</el-button>
|
|
||||||
<el-button type="primary" @click="addRole(editForm)">确 定</el-button>
|
|
||||||
</span>
|
|
||||||
</template>
|
|
||||||
</el-dialog>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script setup lang="ts">
|
|
||||||
import { ref, reactive, watch } from 'vue';
|
|
||||||
import { ElTree } from 'element-plus';
|
|
||||||
import { ElMessage, ElMessageBox } from 'element-plus';
|
|
||||||
import type { FormInstance, FormRules } from 'element-plus';
|
|
||||||
import { ElLoading } from 'element-plus';
|
|
||||||
import { Delete, Edit, Search, Plus } from '@element-plus/icons-vue';
|
|
||||||
import send_request from '../utils/send_request';
|
|
||||||
|
|
||||||
const editForm = ref<FormInstance>();
|
|
||||||
console.log("editForm:", editForm)
|
|
||||||
|
|
||||||
const rules: FormRules = {
|
|
||||||
deviceName: [
|
|
||||||
{
|
|
||||||
required: true,
|
|
||||||
message: '请输入设备名称',
|
|
||||||
trigger: 'blur'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
min: 2,
|
|
||||||
message: '设备名称过短',
|
|
||||||
trigger: 'blur'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
max: 52,
|
|
||||||
message: '设备名称过长',
|
|
||||||
trigger: 'blur'
|
|
||||||
}
|
|
||||||
],
|
|
||||||
type: [
|
|
||||||
{
|
|
||||||
required: true,
|
|
||||||
message: '请选择设备类型',
|
|
||||||
trigger: 'blur'
|
|
||||||
}
|
|
||||||
],
|
|
||||||
deviceId: [
|
|
||||||
{
|
|
||||||
required: true,
|
|
||||||
message: '请输入设备ID',
|
|
||||||
trigger: 'blur'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
min: 2,
|
|
||||||
message: '设备ID过短',
|
|
||||||
trigger: 'blur'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
max: 52,
|
|
||||||
message: '设备ID过长',
|
|
||||||
trigger: 'blur'
|
|
||||||
}
|
|
||||||
],
|
|
||||||
};
|
|
||||||
|
|
||||||
let formId: number = -1;
|
|
||||||
const editVisible = ref(false);
|
|
||||||
let form = reactive({
|
|
||||||
roleName: '',
|
|
||||||
comment: '',
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
const role = ref<string>('admin');
|
|
||||||
|
|
||||||
interface Tree {
|
|
||||||
id: string;
|
|
||||||
label: string;
|
|
||||||
children?: Tree[];
|
|
||||||
}
|
|
||||||
|
|
||||||
const data: Tree[] = [
|
|
||||||
{
|
|
||||||
id: 'dashboard',
|
|
||||||
label: '系统首页',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: '3dmodel',
|
|
||||||
label: '智慧矿山'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 'equipment',
|
|
||||||
label: '设备信息',
|
|
||||||
children: [
|
|
||||||
{
|
|
||||||
id: 'equipment-setting-manage',
|
|
||||||
label: '设备管理'
|
|
||||||
},
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 'monitor-data',
|
|
||||||
label: '监测数据',
|
|
||||||
children: [
|
|
||||||
{
|
|
||||||
id: 'monitor-data-view',
|
|
||||||
label: '查看数据'
|
|
||||||
},
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 'warning',
|
|
||||||
label: '预警信息',
|
|
||||||
children: [
|
|
||||||
{
|
|
||||||
id: 'warning-view',
|
|
||||||
label: '总览(预警信息)'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 'warning-setting',
|
|
||||||
label: '预警设置'
|
|
||||||
},
|
|
||||||
]
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
// 获取当前权限
|
|
||||||
const checkedKeys = ref<string[]>([]);
|
|
||||||
// const getPremission = () => {
|
|
||||||
// // 请求接口返回权限
|
|
||||||
// checkedKeys.value = permiss.defaultList[role.value];
|
|
||||||
// };
|
|
||||||
// getPremission();
|
|
||||||
|
|
||||||
// 保存权限
|
|
||||||
const tree = ref<InstanceType<typeof ElTree>>();
|
|
||||||
const onSubmit = () => {
|
|
||||||
// 获取选中的权限
|
|
||||||
console.log(tree.value!.getCheckedKeys(false));
|
|
||||||
};
|
|
||||||
|
|
||||||
const roleList = ref<any[]>();
|
|
||||||
const selectRoleId = ref(-1);
|
|
||||||
|
|
||||||
// 获取表格&下拉框数据
|
|
||||||
const getData = async () => {
|
|
||||||
// const loading = ElLoading.service({
|
|
||||||
// lock: true,
|
|
||||||
// text: '请稍候',
|
|
||||||
// background: 'rgba(0, 0, 0, 0.7)',
|
|
||||||
// });
|
|
||||||
await send_request('v1/role/list', "GET", {
|
|
||||||
// ...query.params,
|
|
||||||
// pageIndex: query.pageIndex,
|
|
||||||
// pageSize: query.pageSize,
|
|
||||||
// page: query.pageIndex,
|
|
||||||
}, (data: any) => {
|
|
||||||
// let deviceTypeOpt = data.optionDeviceType;
|
|
||||||
console.log("role/list", data)
|
|
||||||
roleList.value = data;
|
|
||||||
selectRoleId.value = data && data.length > 0 ? data[0].id : -1;
|
|
||||||
|
|
||||||
|
|
||||||
// 渲染表格
|
|
||||||
// tableData.value = deviceList.list.map((i: any) => {
|
|
||||||
// i.state = "在线"
|
|
||||||
// return i
|
|
||||||
// });
|
|
||||||
// pageTotal.value = deviceList.total;
|
|
||||||
// // 渲染下拉框
|
|
||||||
// deviceTypeOption.value = deviceTypeOpt;
|
|
||||||
});
|
|
||||||
// loading.close();
|
|
||||||
};
|
|
||||||
getData();
|
|
||||||
|
|
||||||
// const handleChange = (val: string[]) => {
|
|
||||||
// tree.value!.setCheckedKeys(permiss.defaultList[role.value]);
|
|
||||||
// };
|
|
||||||
|
|
||||||
// 新增弹窗
|
|
||||||
const handleNew = () => {
|
|
||||||
formId = -1;
|
|
||||||
for (let formKeys of Object.keys(form)) {
|
|
||||||
form[formKeys] = ''
|
|
||||||
}
|
|
||||||
editVisible.value = true;
|
|
||||||
};
|
|
||||||
|
|
||||||
// 添加角色
|
|
||||||
const addRole = async (formEl: FormInstance | undefined) => {
|
|
||||||
if (!formEl) return;
|
|
||||||
console.log("addRole:formEl", formEl);
|
|
||||||
|
|
||||||
// formEl.validate(async (valid: boolean, invalidFields: any) => {
|
|
||||||
// if (!valid) {
|
|
||||||
// console.log("invalidFields", invalidFields);
|
|
||||||
|
|
||||||
// // 对表单中的每一个不合法输入框进行遍历
|
|
||||||
// Object.values(invalidFields).forEach((input: any) => {
|
|
||||||
|
|
||||||
// // 对该不合法输入框的提示信息进行遍历
|
|
||||||
// input.forEach((element: any) => {
|
|
||||||
// ElMessage.error({
|
|
||||||
// message: element.message, grouping: true
|
|
||||||
// });
|
|
||||||
// });
|
|
||||||
// });
|
|
||||||
// return;
|
|
||||||
// }
|
|
||||||
// 新增记录
|
|
||||||
await send_request('v1/role/add', "POST", {
|
|
||||||
roleName: form.roleName,
|
|
||||||
comment: form.comment,
|
|
||||||
}, (data: any) => {
|
|
||||||
console.log(data);
|
|
||||||
// editVisible.value = false;
|
|
||||||
// ElMessage.success("添加成功");
|
|
||||||
});
|
|
||||||
// }
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style scoped>
|
|
||||||
.tree-wrapper {
|
|
||||||
max-width: 500px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.label {
|
|
||||||
font-size: 14px;
|
|
||||||
}
|
|
||||||
</style>
|
|
@ -1,12 +1,11 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<manageList :list-func="userApi.getUserList" :add-func="userApi.editUser" :edit-func="userApi.editUser"
|
<manageList :list-func="userApi.getUserList" :add-func="userApi.editUser" :edit-func="userApi.editUser"
|
||||||
:delete-func="userApi.deleteUser" edit-permiss="privilege-user-setting" />
|
:delete-func="userApi.deleteUser" :export-func="userApi.exportUserList" edit-permiss="privilege-user-setting" />
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { ref, reactive } from 'vue';
|
|
||||||
import manageList from '../components/manage-list.vue';
|
import manageList from '../components/manage-list.vue';
|
||||||
import * as userApi from '../api/user';
|
import * as userApi from '../api/user';
|
||||||
</script>
|
</script>
|
||||||
|
11
frontend/src/views/shop-good-setting.vue
Normal file
11
frontend/src/views/shop-good-setting.vue
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
<template>
|
||||||
|
<div class="container">
|
||||||
|
<manageList :list-func="userApi.getUserList" :add-func="userApi.editUser" :edit-func="userApi.editUser"
|
||||||
|
:delete-func="userApi.deleteUser" :export-func="userApi.exportUserList" edit-permiss="privilege-user-setting" />
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import manageList from '../components/manage-list.vue';
|
||||||
|
import * as userApi from '../api/user';
|
||||||
|
</script>
|
@ -1,302 +0,0 @@
|
|||||||
<template>
|
|
||||||
<div class="container">
|
|
||||||
|
|
||||||
<!-- 调试用 -->
|
|
||||||
<div v-if="false" style="background-color: lightgrey;">
|
|
||||||
<p>treeSelectItem: {{ treeSelectItem }}</p>
|
|
||||||
<p>monitorCodeList: {{ monitorCodeList }}</p>
|
|
||||||
<p>selectIndex: {{ selectIndex }}</p>
|
|
||||||
<p>form: {{ form }}</p>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div style="display: grid; grid-template-columns: 250px 2fr;">
|
|
||||||
<!-- 左侧 -->
|
|
||||||
<div>
|
|
||||||
<!-- 树状结构 -->
|
|
||||||
<el-input v-model="treeFilterText" placeholder="输入关键字以搜索..." style="margin-bottom: 10px;" />
|
|
||||||
<el-tree ref="treeRef" :data="treeData" :props="defaultProps" :filter-node-method="treeFilterNode"
|
|
||||||
@node-click="handleNodeClick" default-expand-all highlight-current :expand-on-click-node="false" />
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- 右侧 -->
|
|
||||||
<div v-if="treeSelectItem">
|
|
||||||
|
|
||||||
<div style="text-align: center;">
|
|
||||||
<el-radio-group v-model="selectIndex" size="large" style="margin: 10px 0;">
|
|
||||||
<el-radio-button v-for="monitorCode in monitorCodeList" :label="monitorCode" />
|
|
||||||
</el-radio-group>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<el-divider border-style="dotted">
|
|
||||||
<p>
|
|
||||||
<!-- <el-icon style="vertical-align: text-top;"><star-filled /></el-icon> -->
|
|
||||||
您正在配置{{ treeSelectItem.displayMsg }}
|
|
||||||
</p>
|
|
||||||
</el-divider>
|
|
||||||
|
|
||||||
<!-- form表单 -->
|
|
||||||
<el-form :model="form" label-width="120px">
|
|
||||||
|
|
||||||
<template v-for="i in form">
|
|
||||||
<el-form-item :label="i._title">
|
|
||||||
<el-switch v-model="i.Enable" />
|
|
||||||
</el-form-item>
|
|
||||||
|
|
||||||
<!-- v-if="i.Enable" -->
|
|
||||||
<el-form-item label="预警范围">
|
|
||||||
<el-col :span="10">
|
|
||||||
<el-input-number v-model="i.Lower" :disabled="!i.Enable" style="width: 100%" />
|
|
||||||
</el-col>
|
|
||||||
<el-col :span="2" style="text-align: center;">
|
|
||||||
<span class="text-gray-500">-</span>
|
|
||||||
</el-col>
|
|
||||||
<el-col :span="10">
|
|
||||||
<el-input-number v-model="i.Upper" :disabled="!i.Enable" style="width: 100%" />
|
|
||||||
</el-col>
|
|
||||||
<el-col :span="2" style="text-align: center;">
|
|
||||||
<el-button v-if="i.Lower || i.Upper" type="danger" :icon="Delete" circle
|
|
||||||
:disabled="!i.Enable" @click="i.Enable = false; i.Lower = null; i.Upper = null;" />
|
|
||||||
</el-col>
|
|
||||||
</el-form-item>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<el-form-item>
|
|
||||||
<el-button type="primary" @click="onSubmit">保存</el-button>
|
|
||||||
</el-form-item>
|
|
||||||
</el-form>
|
|
||||||
</div>
|
|
||||||
<div v-else style="padding-top: 11vh;">
|
|
||||||
<el-empty description="请在左侧选择设备" />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<script lang="ts" setup>
|
|
||||||
import { ref, watch, computed, reactive } from 'vue'
|
|
||||||
import { ElTree, ElLoading, ElMessage } from 'element-plus'
|
|
||||||
import send_request from '../utils/send_request';
|
|
||||||
import { Delete } from '@element-plus/icons-vue'
|
|
||||||
|
|
||||||
// 树状结构
|
|
||||||
interface Tree {
|
|
||||||
id: number
|
|
||||||
label: string
|
|
||||||
children?: Tree[]
|
|
||||||
detail?: any
|
|
||||||
}
|
|
||||||
|
|
||||||
// 树 上方搜索框中的字
|
|
||||||
const treeFilterText = ref('')
|
|
||||||
// 树 数据
|
|
||||||
const treeData: any = ref([]);
|
|
||||||
// 树 选择的结点
|
|
||||||
const treeSelectItem: any = ref(null);
|
|
||||||
// 树
|
|
||||||
const treeRef = ref<InstanceType<typeof ElTree>>()
|
|
||||||
|
|
||||||
// 单选 所有选项
|
|
||||||
const allMonitorCodeMap: any = ref({});
|
|
||||||
// 单选 当前显示的选项
|
|
||||||
const monitorCodeList: any = computed(() => {
|
|
||||||
if (treeSelectItem.value) {
|
|
||||||
console.log("monitorCodeList computed", allMonitorCodeMap.value, treeSelectItem.value.typeId)
|
|
||||||
let newRadioGroupList = allMonitorCodeMap.value[`${treeSelectItem.value.typeId}`]
|
|
||||||
if (newRadioGroupList.length > 0 && newRadioGroupList.indexOf(selectIndex.value) == -1) {
|
|
||||||
// 如果 newRadioGroupList 中不为空,且当前选择项的 monitorCode 不在 newRadioGroupList 中才更新
|
|
||||||
selectIndex.value = newRadioGroupList[0]
|
|
||||||
}
|
|
||||||
return newRadioGroupList
|
|
||||||
} else {
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
});
|
|
||||||
// 单选 选择项
|
|
||||||
const selectIndex: any = ref('');
|
|
||||||
|
|
||||||
// 树 搜索框文字改变事件
|
|
||||||
watch(treeFilterText, (val) => {
|
|
||||||
treeRef.value!.filter(val)
|
|
||||||
})
|
|
||||||
|
|
||||||
// 树 输入搜索文字过滤节点事件
|
|
||||||
const treeFilterNode = (value: string, data: Tree) => {
|
|
||||||
if (!value) return true
|
|
||||||
return data.label.includes(value) // || data.id === -1
|
|
||||||
}
|
|
||||||
|
|
||||||
const handleNodeClick = (data: Tree) => {
|
|
||||||
console.log("handleNodeClick", data)
|
|
||||||
treeSelectItem.value = data.detail ? data.detail : null;
|
|
||||||
}
|
|
||||||
|
|
||||||
const getTreeData = async () => {
|
|
||||||
const loading = ElLoading.service({
|
|
||||||
lock: true,
|
|
||||||
text: '请稍候',
|
|
||||||
background: 'rgba(0, 0, 0, 0.7)',
|
|
||||||
});
|
|
||||||
await send_request('v1/device/listAll', "GET", {
|
|
||||||
}, (data: any) => {
|
|
||||||
console.log("device/listAll", data)
|
|
||||||
let deviceTypeList = data.deviceType;
|
|
||||||
let deviceList = data.list;
|
|
||||||
|
|
||||||
let transData = []
|
|
||||||
for (let deviceType of deviceTypeList) {
|
|
||||||
transData.push({
|
|
||||||
id: deviceType.id,
|
|
||||||
label: deviceType.typeName,
|
|
||||||
children: [
|
|
||||||
{
|
|
||||||
id: `${deviceType.id}_0`,
|
|
||||||
label: "(默认)",
|
|
||||||
detail: {
|
|
||||||
deviceId: -1,
|
|
||||||
typeId: deviceType.id,
|
|
||||||
deviceName: `(默认)`,
|
|
||||||
displayMsg: ` ${deviceType.typeName}设备 默认设置`,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
...deviceList.filter((device: any) => device.typeId === deviceType.id)
|
|
||||||
.map((device: any) => {
|
|
||||||
return {
|
|
||||||
id: `${deviceType.id}_${device.id}`,
|
|
||||||
label: device.name,
|
|
||||||
detail: {
|
|
||||||
deviceId: device.id,
|
|
||||||
typeId: device.typeId,
|
|
||||||
deviceName: device.name,
|
|
||||||
displayMsg: ` ${deviceType.typeName}设备:${device.name}`,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
})
|
|
||||||
],
|
|
||||||
})
|
|
||||||
}
|
|
||||||
treeData.value = transData;
|
|
||||||
});
|
|
||||||
await send_request('v1/alert-model/getDeviceTypeToMonitorCodeMap', "GET", {
|
|
||||||
}, (data: any) => {
|
|
||||||
console.log("alert-model/getDeviceTypeToMonitorCodeMap", data)
|
|
||||||
allMonitorCodeMap.value = data;
|
|
||||||
});
|
|
||||||
loading.close();
|
|
||||||
};
|
|
||||||
getTreeData();
|
|
||||||
|
|
||||||
// Tree渲染所使用属性
|
|
||||||
const defaultProps = {
|
|
||||||
children: 'children',
|
|
||||||
label: 'label',
|
|
||||||
}
|
|
||||||
|
|
||||||
watch([treeSelectItem, selectIndex], ([foo, bar], [prevFoo, prevBar]) => {
|
|
||||||
if (!treeSelectItem.value) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
console.log("所选模型发生改变,需要重新获取AlertModel")
|
|
||||||
getAlertModel()
|
|
||||||
})
|
|
||||||
|
|
||||||
const getAlertModel = async () => {
|
|
||||||
const loading = ElLoading.service({
|
|
||||||
lock: true,
|
|
||||||
text: '请稍候',
|
|
||||||
background: 'rgba(0, 0, 0, 0.7)',
|
|
||||||
});
|
|
||||||
|
|
||||||
// isDefault -> true 默认模型; -> false 指定设备的模型
|
|
||||||
const isDefault = treeSelectItem.value.deviceId < 0;
|
|
||||||
const postParams = {
|
|
||||||
modelType: isDefault ? "default" : "specific",
|
|
||||||
deviceId: isDefault ? undefined : treeSelectItem.value.deviceId,
|
|
||||||
deviceTypeId: isDefault ? treeSelectItem.value.typeId : undefined,
|
|
||||||
monitorCode: selectIndex.value,
|
|
||||||
};
|
|
||||||
console.log("getAlertModel -> postParams", postParams);
|
|
||||||
await send_request('v1/alert-model/getAlertModel', "POST", postParams, (data: any) => {
|
|
||||||
console.log("alert-model/getAlertModel", data)
|
|
||||||
form.y.Enable = !!data.yellowIsAlert;
|
|
||||||
form.y.Lower = data.yellowLowerBound;
|
|
||||||
form.y.Upper = data.yellowUpperBound;
|
|
||||||
form.o.Enable = !!data.orangeIsAlert;
|
|
||||||
form.o.Lower = data.orangeLowerBound;
|
|
||||||
form.o.Upper = data.orangeUpperBound;
|
|
||||||
form.r.Enable = !!data.redIsAlert;
|
|
||||||
form.r.Lower = data.redLowerBound;
|
|
||||||
form.r.Upper = data.redUpperBound;
|
|
||||||
|
|
||||||
});
|
|
||||||
loading.close();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Form 表单
|
|
||||||
const form = reactive({
|
|
||||||
y: {
|
|
||||||
_title: "黄色预警",
|
|
||||||
Enable: false,
|
|
||||||
Lower: null,
|
|
||||||
Upper: null,
|
|
||||||
},
|
|
||||||
o: {
|
|
||||||
_title: "橙色预警",
|
|
||||||
Enable: false,
|
|
||||||
Lower: null,
|
|
||||||
Upper: null,
|
|
||||||
},
|
|
||||||
r: {
|
|
||||||
_title: "红色预警",
|
|
||||||
Enable: false,
|
|
||||||
Lower: null,
|
|
||||||
Upper: null,
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
const onSubmit = async () => {
|
|
||||||
console.log('submit!')
|
|
||||||
const loading = ElLoading.service({
|
|
||||||
lock: true,
|
|
||||||
text: '请稍候',
|
|
||||||
background: 'rgba(0, 0, 0, 0.7)',
|
|
||||||
});
|
|
||||||
|
|
||||||
// isDefault -> true 默认模型; -> false 指定设备的模型
|
|
||||||
const isDefault = treeSelectItem.value.deviceId < 0;
|
|
||||||
const postParams = {
|
|
||||||
modelType: isDefault ? "default" : "specific",
|
|
||||||
deviceId: isDefault ? undefined : treeSelectItem.value.deviceId,
|
|
||||||
deviceTypeId: isDefault ? treeSelectItem.value.typeId : undefined,
|
|
||||||
monitorCode: selectIndex.value,
|
|
||||||
yLower: form.y.Lower,
|
|
||||||
yUpper: form.y.Upper,
|
|
||||||
yEnable: form.y.Enable,
|
|
||||||
oLower: form.o.Lower,
|
|
||||||
oUpper: form.o.Upper,
|
|
||||||
oEnable: form.o.Enable,
|
|
||||||
rLower: form.r.Lower,
|
|
||||||
rUpper: form.r.Upper,
|
|
||||||
rEnable: form.r.Enable,
|
|
||||||
};
|
|
||||||
console.log("setAlertModel -> postParams", postParams);
|
|
||||||
await send_request('v1/alert-model/setAlertModel', "POST", postParams, (data: any) => {
|
|
||||||
console.log("v1/alert-model/setAlertModel", data)
|
|
||||||
if (data) {
|
|
||||||
ElMessage.success('保存成功');
|
|
||||||
} else {
|
|
||||||
ElMessage.error('保存失败');
|
|
||||||
}
|
|
||||||
});
|
|
||||||
loading.close();
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style>
|
|
||||||
.el-tree-node__content {
|
|
||||||
height: 36px !important;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|
||||||
<style scoped></style>
|
|
@ -1,396 +0,0 @@
|
|||||||
<template>
|
|
||||||
<div class="container">
|
|
||||||
<el-row :gutter="20">
|
|
||||||
<el-col :span="18">
|
|
||||||
<el-row :gutter="20" class="mgb20">
|
|
||||||
<el-col :span="6">
|
|
||||||
<el-card shadow="hover" :body-style="{ padding: '0px' }">
|
|
||||||
<div class="grid-content grid-con-0">
|
|
||||||
<el-icon class="grid-con-icon">
|
|
||||||
<Odometer />
|
|
||||||
</el-icon>
|
|
||||||
<div class="grid-cont-right">
|
|
||||||
<div class="grid-num">{{ levelCount?.today_total }}</div>
|
|
||||||
<div>今日累计预警</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</el-card>
|
|
||||||
</el-col>
|
|
||||||
<el-col :span="6">
|
|
||||||
<el-card shadow="hover" :body-style="{ padding: '0px' }">
|
|
||||||
<div class="grid-content grid-con-1">
|
|
||||||
<el-icon class="grid-con-icon">
|
|
||||||
<User />
|
|
||||||
</el-icon>
|
|
||||||
<div class="grid-cont-right">
|
|
||||||
<div class="grid-num">{{ levelCount?.today_y }}</div>
|
|
||||||
<div>黄色预警</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</el-card>
|
|
||||||
</el-col>
|
|
||||||
<el-col :span="6">
|
|
||||||
<el-card shadow="hover" :body-style="{ padding: '0px' }">
|
|
||||||
<div class="grid-content grid-con-2">
|
|
||||||
<el-icon class="grid-con-icon">
|
|
||||||
<ChatDotRound />
|
|
||||||
</el-icon>
|
|
||||||
<div class="grid-cont-right">
|
|
||||||
<div class="grid-num">{{ levelCount?.today_o }}</div>
|
|
||||||
<div>橙色预警</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</el-card>
|
|
||||||
</el-col>
|
|
||||||
<el-col :span="6">
|
|
||||||
<el-card shadow="hover" :body-style="{ padding: '0px' }">
|
|
||||||
<div class="grid-content grid-con-3">
|
|
||||||
<el-icon class="grid-con-icon">
|
|
||||||
<Goods />
|
|
||||||
</el-icon>
|
|
||||||
<div class="grid-cont-right">
|
|
||||||
<div class="grid-num">{{ levelCount?.today_r }}</div>
|
|
||||||
<div>红色预警</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</el-card>
|
|
||||||
</el-col>
|
|
||||||
</el-row>
|
|
||||||
<el-card shadow="hover" style="min-height: 403px">
|
|
||||||
<template #header>
|
|
||||||
<div class="clearfix">
|
|
||||||
<span>预警列表</span>
|
|
||||||
<el-button style="float: right; padding: 3px 0" text>查看全部</el-button>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
|
|
||||||
<!-- 表格 -->
|
|
||||||
<el-table :data="tableData" border class="table" ref="multipleTable"
|
|
||||||
header-cell-class-name="table-header">
|
|
||||||
<el-table-column prop="id" label="ID" width="55" align="center" v-if="false"></el-table-column>
|
|
||||||
<el-table-column prop="createTime" label="报警时间" align="center"></el-table-column>
|
|
||||||
<el-table-column prop="deviceName" label="报警设备" align="center"></el-table-column>
|
|
||||||
<el-table-column prop="alertLevel" label="报警等级" align="center"></el-table-column>
|
|
||||||
<el-table-column prop="monitorCode" label="监测项" align="center"></el-table-column>
|
|
||||||
<el-table-column prop="monitorValue" label="监测值" align="center"></el-table-column>
|
|
||||||
<el-table-column prop="threshold" label="阈值" align="center"></el-table-column>
|
|
||||||
<el-table-column prop="deviceId" label="" align="center" v-if="false"></el-table-column>
|
|
||||||
<!-- <el-table-column label="操作" width="220" align="center"> -->
|
|
||||||
<!-- <template #default="scope">
|
|
||||||
<el-button text :icon="Edit" @click="handleEdit(scope.$index, scope.row)"
|
|
||||||
v-permiss="'user-setting'">
|
|
||||||
编辑
|
|
||||||
</el-button>
|
|
||||||
<el-button text :icon="Delete" class="red" @click="handleDelete(scope.$index, scope.row)"
|
|
||||||
v-permiss="'user-setting'">
|
|
||||||
删除
|
|
||||||
</el-button>
|
|
||||||
</template> -->
|
|
||||||
<!-- </el-table-column> -->
|
|
||||||
</el-table>
|
|
||||||
<!-- 分页 -->
|
|
||||||
<div class="pagination">
|
|
||||||
<el-pagination background layout="total, prev, pager, next" :current-page="query.pageIndex"
|
|
||||||
:page-size="query.pageSize" :total="pageTotal"
|
|
||||||
@current-change="handlePageChange"></el-pagination>
|
|
||||||
</div>
|
|
||||||
<!-- <el-table :show-header="false" :data="todoList" style="width: 100%">
|
|
||||||
<el-table-column width="40">
|
|
||||||
<template #default="scope">
|
|
||||||
<el-checkbox v-model="scope.row.status"></el-checkbox>
|
|
||||||
</template>
|
|
||||||
</el-table-column>
|
|
||||||
<el-table-column>
|
|
||||||
<template #default="scope">
|
|
||||||
<div
|
|
||||||
class="todo-item"
|
|
||||||
:class="{
|
|
||||||
'todo-item-del': scope.row.status
|
|
||||||
}"
|
|
||||||
>
|
|
||||||
{{ scope.row.title }}
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
</el-table-column>
|
|
||||||
</el-table> -->
|
|
||||||
</el-card>
|
|
||||||
</el-col>
|
|
||||||
<el-col :span="6">
|
|
||||||
<el-card shadow="hover" class="mgb20">
|
|
||||||
<p>
|
|
||||||
监测预警总览
|
|
||||||
</p>
|
|
||||||
<div class="alert-image-container">
|
|
||||||
<img class="alert-image" :class="isAlerting ? 'alert-ing' : []"
|
|
||||||
:src="isAlerting ? '/assets/image/svg/alert_warning.svg' : '/assets/image/svg/alert_default.svg'"
|
|
||||||
@click="isAlerting = !isAlerting">
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- 表格 -->
|
|
||||||
<el-table :data="alertLogCountTableData" style="width: 100%">
|
|
||||||
<el-table-column prop="timeRange" label="" />
|
|
||||||
<el-table-column prop="yellow" label="黄色预警" />
|
|
||||||
<el-table-column prop="orange" label="橙色预警" />
|
|
||||||
<el-table-column prop="red" label="红色预警" />
|
|
||||||
<el-table-column prop="total" label="总计" />
|
|
||||||
</el-table>
|
|
||||||
</el-card>
|
|
||||||
</el-col>
|
|
||||||
</el-row>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script setup lang="ts" name="dashboard">
|
|
||||||
import { ref, reactive } from 'vue';
|
|
||||||
import send_request from '../utils/send_request';
|
|
||||||
|
|
||||||
const name = localStorage.getItem('ms_username');
|
|
||||||
const role: string = name === 'admin' ? '超级管理员' : '普通用户';
|
|
||||||
|
|
||||||
|
|
||||||
// 筛选条件
|
|
||||||
const query = reactive({
|
|
||||||
params: {
|
|
||||||
deviceType: '',
|
|
||||||
name: '',
|
|
||||||
},
|
|
||||||
pageIndex: 1,
|
|
||||||
pageSize: 10
|
|
||||||
});
|
|
||||||
|
|
||||||
// 展示的铃铛是否处于报警状态
|
|
||||||
const isAlerting = ref(false);
|
|
||||||
|
|
||||||
const alertLevel = {
|
|
||||||
"1": "黄色预警",
|
|
||||||
"2": "橙色预警",
|
|
||||||
"3": "红色预警",
|
|
||||||
}
|
|
||||||
const tableData: any = ref([]);
|
|
||||||
const pageTotal = ref(0);
|
|
||||||
const levelCount = ref({
|
|
||||||
'today_y': '',
|
|
||||||
'today_o': '',
|
|
||||||
'today_r': '',
|
|
||||||
'today_total': '',
|
|
||||||
});
|
|
||||||
|
|
||||||
// 统计表格的数据
|
|
||||||
const alertLogCountTableData = ref([]);
|
|
||||||
|
|
||||||
const getData = async () => {
|
|
||||||
// const loading = ElLoading.service({
|
|
||||||
// lock: true,
|
|
||||||
// text: '请稍候',
|
|
||||||
// background: 'rgba(0, 0, 0, 0.7)',
|
|
||||||
// });
|
|
||||||
await send_request('v1/alert/list', "GET", {
|
|
||||||
...query.params,
|
|
||||||
pageIndex: query.pageIndex,
|
|
||||||
pageSize: query.pageSize,
|
|
||||||
page: query.pageIndex,
|
|
||||||
}, (data: any) => {
|
|
||||||
let alertList = data;
|
|
||||||
|
|
||||||
//生成"设备类型"数据字典
|
|
||||||
//console.log("deviceList/deviceTypeList:", deviceList, deviceTypeList)
|
|
||||||
// deviceTypeList.forEach((item: any) => deviceTypeDict.value[item.id] = item.type)
|
|
||||||
|
|
||||||
// 渲染表格
|
|
||||||
tableData.value = alertList.list.map((i: any) => {
|
|
||||||
i.state = "在线"
|
|
||||||
i.alertLevel = alertLevel[i.alertLevel]
|
|
||||||
i.createTime = new Date(new Date(i.createTime).getTime() + 8 * 3600 * 1000).toISOString().substring(0, 19).replace('T', ' ')
|
|
||||||
return i
|
|
||||||
});
|
|
||||||
pageTotal.value = alertList.total;
|
|
||||||
// // 渲染下拉框
|
|
||||||
// deviceTypeOption.value = deviceTypeList;
|
|
||||||
});
|
|
||||||
|
|
||||||
// 各种预警的数量
|
|
||||||
await send_request('v1/chart-data/levelCount', "GET", {
|
|
||||||
}, (data: any) => {
|
|
||||||
console.log("v1/chart-data/levelCount:", data);
|
|
||||||
|
|
||||||
let timeRangeDict = {
|
|
||||||
"day": "今日",
|
|
||||||
"week": "本周",
|
|
||||||
"month": "本月",
|
|
||||||
"year": "今年",
|
|
||||||
"total": "累计",
|
|
||||||
}
|
|
||||||
alertLogCountTableData.value = data.map((row: any) => {
|
|
||||||
row.total = row.yellow + row.orange + row.red;
|
|
||||||
if (row.timeRange == "day") {
|
|
||||||
levelCount.value.today_y = row.yellow;
|
|
||||||
levelCount.value.today_o = row.orange;
|
|
||||||
levelCount.value.today_r = row.red;
|
|
||||||
levelCount.value.today_total = row.total;
|
|
||||||
console.log(levelCount.value)
|
|
||||||
}
|
|
||||||
row.timeRange = timeRangeDict[row.timeRange]
|
|
||||||
return row
|
|
||||||
})
|
|
||||||
console.log("alertLogCountTableData.value", alertLogCountTableData.value);
|
|
||||||
});
|
|
||||||
|
|
||||||
// loading.close();
|
|
||||||
};
|
|
||||||
getData();
|
|
||||||
// 分页导航
|
|
||||||
const handlePageChange = (val: number) => {
|
|
||||||
query.pageIndex = val;
|
|
||||||
getData();
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style scoped>
|
|
||||||
/* 警铃抖动样式 */
|
|
||||||
@keyframes shaking {
|
|
||||||
0% {
|
|
||||||
transform: rotate(0deg);
|
|
||||||
}
|
|
||||||
|
|
||||||
35% {
|
|
||||||
transform: rotate(20deg);
|
|
||||||
}
|
|
||||||
|
|
||||||
65% {
|
|
||||||
transform: rotate(-20deg);
|
|
||||||
}
|
|
||||||
|
|
||||||
100% {
|
|
||||||
transform: rotate(0deg);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.alert-image-container {
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.alert-image {
|
|
||||||
width: 60%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.alert-ing {
|
|
||||||
animation-duration: 1s;
|
|
||||||
animation-name: shaking;
|
|
||||||
animation-direction: normal;
|
|
||||||
animation-iteration-count: infinite;
|
|
||||||
animation-timing-function: cubic-bezier(0.76, 0.44, 0.33, 0.75);
|
|
||||||
animation-delay: 0.8s;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ############ */
|
|
||||||
|
|
||||||
.el-row {
|
|
||||||
margin-bottom: 20px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.grid-content {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
--grid-content-height: min(150px, 6vw);
|
|
||||||
height: var(--grid-content-height);
|
|
||||||
}
|
|
||||||
|
|
||||||
.grid-cont-right {
|
|
||||||
flex: 1;
|
|
||||||
text-align: center;
|
|
||||||
font-size: 14px;
|
|
||||||
color: #999;
|
|
||||||
}
|
|
||||||
|
|
||||||
.grid-num {
|
|
||||||
font-size: min(70px, 4vw);
|
|
||||||
font-weight: bold;
|
|
||||||
}
|
|
||||||
|
|
||||||
.grid-con-icon {
|
|
||||||
font-size: min(50px, 2.8vw);
|
|
||||||
width: min(150px, 5vw);
|
|
||||||
height: var(--grid-content-height);
|
|
||||||
text-align: center;
|
|
||||||
line-height: 100px;
|
|
||||||
color: #fff;
|
|
||||||
}
|
|
||||||
|
|
||||||
.grid-con-0 .grid-con-icon {
|
|
||||||
background: rgb(43 157 255);
|
|
||||||
}
|
|
||||||
|
|
||||||
.grid-con-0 .grid-num {
|
|
||||||
color: rgb(43 157 255);
|
|
||||||
}
|
|
||||||
|
|
||||||
.grid-con-1 .grid-con-icon {
|
|
||||||
background: rgb(255 223 43);
|
|
||||||
}
|
|
||||||
|
|
||||||
.grid-con-1 .grid-num {
|
|
||||||
color: rgb(255 223 43);
|
|
||||||
}
|
|
||||||
|
|
||||||
.grid-con-2 .grid-con-icon {
|
|
||||||
background: rgb(255, 135, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
.grid-con-2 .grid-num {
|
|
||||||
color: rgb(255, 135, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
.grid-con-3 .grid-con-icon {
|
|
||||||
background: rgb(242, 94, 67);
|
|
||||||
}
|
|
||||||
|
|
||||||
.grid-con-3 .grid-num {
|
|
||||||
color: rgb(242, 94, 67);
|
|
||||||
}
|
|
||||||
|
|
||||||
.user-info {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
padding-bottom: 20px;
|
|
||||||
border-bottom: 2px solid #ccc;
|
|
||||||
margin-bottom: 20px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.user-info-cont {
|
|
||||||
padding-left: 50px;
|
|
||||||
flex: 1;
|
|
||||||
font-size: 14px;
|
|
||||||
color: #999;
|
|
||||||
}
|
|
||||||
|
|
||||||
.user-info-cont div:first-child {
|
|
||||||
font-size: 30px;
|
|
||||||
color: #222;
|
|
||||||
}
|
|
||||||
|
|
||||||
.user-info-list {
|
|
||||||
font-size: 14px;
|
|
||||||
color: #999;
|
|
||||||
line-height: 25px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.user-info-list span {
|
|
||||||
margin-left: 70px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.mgb20 {
|
|
||||||
margin-bottom: 20px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.todo-item {
|
|
||||||
font-size: 14px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.todo-item-del {
|
|
||||||
text-decoration: line-through;
|
|
||||||
color: #999;
|
|
||||||
}
|
|
||||||
</style>
|
|
Loading…
Reference in New Issue
Block a user