This commit is contained in:
zhang zhuo 2026-05-27 15:51:24 +08:00
parent 4b3d518cc3
commit 9a57977aa9
17 changed files with 217 additions and 56 deletions

View File

@ -86,7 +86,7 @@ export default {
return await http.get("post/option", data);
},
import: async function (data = {}) {
return await http.get("post/import", data);
return await http.post("post/import", data);
},
},
upload: async function (data, config = {}) {

View File

@ -52,7 +52,7 @@ function genCacheKey() {
if (!props.cacheKey) {
return null;
}
return `${props.cacheKey || dictConfig.api.name}:` + tools.crypto.MD5(`${stableStringify({key: props.type})}`).slice(0, 8).toUpperCase()
return `${props.cacheKey || dictConfig.api.name}:` + tools.md5(`${stableStringify({key: props.type})}`).slice(0, 8).toUpperCase()
}
function stableStringify(obj) {

View File

@ -2,8 +2,7 @@
<div class="pi-editor" :style="{width: width}">
<Toolbar style="border: 1px solid #ccc" :editor="editorRef" :defaultConfig="toolbarConfig"/>
<Editor style="border: 1px solid #ccc; border-top: 0;" :style="{height: height}" v-model="html"
:defaultConfig="editorConfig"
@onCreated="handleCreated"/>
:defaultConfig="editorConfig" @onCreated="handleCreated"/>
<pi-asset-picker ref="pickerRef1" v-if="pickerVisible1" @success="saveSuccess1" @closed="pickerVisible1=false"
type="image" :max="10" :multiple="true"></pi-asset-picker>
<pi-asset-picker ref="pickerRef2" v-if="pickerVisible2" @success="saveSuccess2" @closed="pickerVisible2=false"
@ -18,7 +17,7 @@ import {Editor, Toolbar} from '@wangeditor/editor-for-vue'
import './ext/extImage'
import './ext/extVideo'
import config from "@/config"
import {ref, onUnmounted, watch, nextTick, onMounted, shallowRef} from "vue"
import {ref, onUnmounted, watch, nextTick, shallowRef, computed} from "vue"
const emit = defineEmits(['update:modelValue'])
const props = defineProps({
@ -62,14 +61,10 @@ const editorConfig = {
}
}
}
let html = ref("")
watch(() => props.modelValue, () => {
html.value = props.modelValue
}, {immediate: true})
watch(html, () => {
emit("update:modelValue", html.value)
const html = computed({
get: () => props.modelValue,
set: (val) => emit("update:modelValue", val)
})
onUnmounted(() => {
@ -80,6 +75,9 @@ onUnmounted(() => {
const handleCreated = (editor) => {
editorRef.value = editor
if (html.value) {
editor.setHtml(html.value)
}
}
function showPicker1() {

View File

@ -9,10 +9,7 @@ import tools from "@/utils/tools"
const {proxy} = getCurrentInstance()
const props = defineProps({
api: {
type: Object, default: () => {
}
},
api: {type: Object},
params: {
type: Object, default: () => {
}
@ -25,12 +22,12 @@ let loading = ref(false)
async function download() {
const data = {module: props.module, name: props.name, params: props.params}
let api = props.api
if (!api) {
api = api.tools.file.export
let apiUrl = props.api
if (!apiUrl) {
apiUrl = api.tools.file.export
}
loading.value = true
const [res, err] = await tools.go(api(data))
const [res, err] = await tools.go(apiUrl(data))
loading.value = false
if (err) {
proxy.$message.error(res.msg)

View File

@ -1,5 +1,5 @@
<template>
<el-image :src="prefix+src" :preview-src-list="previewList" v-bind="attrs"/>
<el-image v-if="src" :src="prefix+src" :preview-src-list="previewList" v-bind="attrs"/>
</template>
<script setup>

View File

@ -3,7 +3,8 @@
<slot :open="open">
<el-button type="info" plain icon="el-icon-upload" @click="open()"></el-button>
</slot>
<el-dialog v-model="dialog" title="导入" :width="550" :close-on-click-modal="false" append-to-body destroy-on-close>
<el-dialog v-model="dialog" title="导入" :width="550" :close-on-click-modal="false" append-to-body
destroy-on-close>
<el-progress v-if="loading" :text-inside="true" :stroke-width="20" :percentage="percentage"
style="margin-bottom: 15px;"/>
<div v-loading="loading">
@ -33,7 +34,7 @@
<template v-if="tip">{{ tip }}</template>
<template v-else>请上传小于或等于 {{ maxSize }}M {{ accept }} 格式文件</template>
<p v-if="templateUrl" style="margin-top: 7px;">
<el-link :href="templateUrl" target="_blank" type="primary" :underline="false">
<el-link :href="templateUrl" target="_blank" type="primary" underline="never">
下载导入模板
</el-link>
</p>
@ -98,7 +99,9 @@ function success(res, file) {
uploaderRef.value.clearFiles()
loading.value = false
percentage.value = 0
emit('success', res, close)
close()
emit('success', res)
proxy.$message.success(res.msg);
}
function error(err) {
@ -110,7 +113,6 @@ function error(err) {
})
}
function request(param) {
Object.assign(param.data, formData.value)
const data = new FormData();
@ -118,7 +120,7 @@ function request(param) {
for (const key in param.data) {
data.append(key, param.data[key]);
}
props.api.post(data, {
props.api(data, {
onUploadProgress: e => {
const complete = parseInt(((e.loaded / e.total) * 100) | 0, 10)
param.onProgress({percent: complete})

View File

@ -81,7 +81,7 @@ function genCacheKey() {
if (!props.cacheKey) {
return null;
}
return `${props.cacheKey || props.api.name}:` + tools.crypto.MD5(`${stableStringify(props.params)}`).slice(0, 8).toUpperCase()
return `${props.cacheKey || props.api.name}:` + tools.md5(`${stableStringify(props.params)}`).slice(0, 8).toUpperCase()
}
function stableStringify(obj) {

View File

@ -21,7 +21,7 @@
<div :style="{'height':_height}" v-loading="loading">
<div class="pi-table" :style="{'height':_table_height}">
<el-table v-bind="$attrs" :data="tableData" :row-key="rowKey" :key="toggleIndex" ref="piTableRef"
:height="height=='auto'?null:'100%'" :size="_config.size" :border="_config.border"
:height="height==='auto'?null:'100%'" :size="_config.size" :border="_config.border"
:stripe="_config.stripe" :summary-method="remoteSummary?remoteSummaryMethod:summaryMethod"
@sort-change="sortChange" @filter-change="filterChange">
<slot></slot>
@ -117,10 +117,7 @@ const hasDoSlot = computed(() => !!slots.do)
const props = defineProps({
tableName: {type: String, default: ""},
api: {
type: Function, default: () => {
}
},
api: {type: Function},
workbench: {type: Boolean, default: false},
params: {type: Object, default: () => ({})},
data: {
@ -134,7 +131,7 @@ const props = defineProps({
pageSize: {type: Number, default: config.pageSize},
pageSizes: {type: Array, default: config.pageSizes},
rowKey: {type: String, default: ""},
primaryKey: {type: String, default: "id"},
primaryKey: {type: String, default: "parent_id"},
summaryMethod: {type: Function, default: null},
column: {
type: Object, default: () => {
@ -274,7 +271,8 @@ async function getData() {
emptyText.value = "暂无数据";
tableData.value = response.data || [];
if (props.rowKey) {
tableData.value = tools.makeTreeData(tableData.value, 0, props.primaryKey, props.rowKey)
tableData.value = tools.makeTreeData(tableData.value, 0, props.rowKey, props.primaryKey)
console.log(tableData.value, 123)
//
if (response.data.length > 0 && tableData.value.length === 0) {
tableData.value = response.data

View File

@ -73,6 +73,7 @@ async function switchTab() {
page.value = 1
msgList.value = []
finish.value = false
isRead.value = false
await loadData()
}

138
src/utils/print.ts Normal file
View File

@ -0,0 +1,138 @@
// 打印类属性、方法定义
const Print = function(dom, options) {
// @ts-ignore
if (!(this instanceof Print)) return new Print(dom, options);
this.options = this.extend({
'noPrint': '.no-print'
}, options);
if ((typeof dom) === "string") {
try{
this.dom = document.querySelector(dom);
}catch{
var createDom = document.createElement("div")
createDom.innerHTML = dom
this.dom = createDom;
};
} else {
this.isDOM(dom)
this.dom = this.isDOM(dom) ? dom : dom.$el;
}
this.init();
};
Print.prototype = {
init: function() {
var content = this.getStyle() + this.getHtml();
this.writeIframe(content);
},
extend: function(obj, obj2) {
for (var k in obj2) {
obj[k] = obj2[k];
}
return obj;
},
getStyle: function() {
var str = "",
styles = document.querySelectorAll('style,link');
for (var i = 0; i < styles.length; i++) {
str += styles[i].outerHTML;
}
str += "<style>" + (this.options.noPrint ? this.options.noPrint : '.no-print') +
"{display:none;}</style>";
str += "<style>html,body{background-color:#fff;}</style>";
return str;
},
getHtml: function() {
var inputs = document.querySelectorAll('input');
var textareas = document.querySelectorAll('textarea');
var selects = document.querySelectorAll('select');
for (var k = 0; k < inputs.length; k++) {
if (inputs[k].type == "checkbox" || inputs[k].type == "radio") {
if (inputs[k].checked == true) {
inputs[k].setAttribute('checked', "checked")
} else {
inputs[k].removeAttribute('checked')
}
} else if (inputs[k].type == "text") {
inputs[k].setAttribute('value', inputs[k].value)
} else {
inputs[k].setAttribute('value', inputs[k].value)
}
}
for (var k2 = 0; k2 < textareas.length; k2++) {
if (textareas[k2].type == 'textarea') {
textareas[k2].innerHTML = textareas[k2].value
}
}
for (var k3 = 0; k3 < selects.length; k3++) {
if (selects[k3].type == 'select-one') {
var child = selects[k3].children;
for (var i in child) {
if (child[i].tagName == 'OPTION') {
// @ts-ignore
if (child[i].selected == true) {
child[i].setAttribute('selected', "selected")
} else {
child[i].removeAttribute('selected')
}
}
}
}
}
return this.dom.outerHTML;
},
writeIframe: function(content) {
var w, doc, iframe = document.createElement('iframe'),
f = document.body.appendChild(iframe);
iframe.id = "myIframe";
//iframe.style = "position:absolute;width:0;height:0;top:-10px;left:-10px;";
iframe.setAttribute('style', 'position:absolute;width:0;height:0;top:-10px;left:-10px;');
w = f.contentWindow || f.contentDocument;
doc = f.contentDocument || f.contentWindow.document;
doc.open();
doc.write(content);
doc.close();
var _this = this
iframe.onload = function() {
_this.toPrint(w);
setTimeout(function() {
document.body.removeChild(iframe)
}, 100)
}
},
toPrint: function(frameWindow) {
try {
setTimeout(function() {
frameWindow.focus();
try {
if (!frameWindow.document.execCommand('print', false, null)) {
frameWindow.print();
}
} catch (e) {
frameWindow.print();
}
frameWindow.close();
}, 10);
} catch (err) {
console.log('err', err);
}
},
isDOM: (typeof HTMLElement === 'object') ?
function(obj) {
return obj instanceof HTMLElement;
} : function(obj) {
return obj && typeof obj === 'object' && obj.nodeType === 1 && typeof obj.nodeName === 'string';
}
};
export default Print

View File

@ -30,14 +30,19 @@
</template>
</el-table-column>
<el-table-column label="账号" prop="username"></el-table-column>
<el-table-column label="昵称" prop="nickname"></el-table-column>
<el-table-column label="邮箱" prop="email"></el-table-column>
<el-table-column label="电话" prop="phone"></el-table-column>
<el-table-column label="名称" prop="nickname"></el-table-column>
<el-table-column label="岗位" prop="post_name">
<template #default="scope">
<el-tag v-for="item in scope.row.posts" :key="item.post_id" type="primary">{{ item.post_name }}</el-tag>
</template>
</el-table-column>
<el-table-column label="角色" prop="roles">
<template #default="scope">
{{ scope.row.roles.map(item => item.role_name).toString() }}
</template>
</el-table-column>
<el-table-column label="邮箱" prop="email"></el-table-column>
<el-table-column label="电话" prop="phone"></el-table-column>
<el-table-column label="创建时间" prop="create_time"></el-table-column>
<el-table-column label="操作" fixed="right" align="right" width="160">
<template #default="scope">

View File

@ -5,6 +5,9 @@
<el-form-item label="账号" prop="username">
<el-input v-model="form.username" placeholder="用于登录系统" clearable></el-input>
</el-form-item>
<el-form-item label="名称" prop="nickname">
<el-input v-model="form.nickname" placeholder="请输入名称" clearable></el-input>
</el-form-item>
<el-form-item label="邮箱" prop="email">
<el-input v-model="form.email" placeholder="请输入邮箱" clearable></el-input>
</el-form-item>
@ -128,7 +131,7 @@ async function submit() {
}
//
form.value.dept_id = deptRef.value.getCheckedNodes()[0].data.dept_id
if (form.value.password) form.value.password = tools.crypto.MD5(form.value.password)
if (form.value.password) form.value.password = tools.md5(form.value.password)
isSaveing.value = true;
const res = form.value.account_id ? await api.system.account.edit(form.value) : await api.system.account.add(form.value);
isSaveing.value = false;

View File

@ -16,7 +16,6 @@
<el-table-column label="ID" prop="config_id"></el-table-column>
<el-table-column label="参数名称" prop="config_name"></el-table-column>
<el-table-column label="参数键名" prop="config_key"></el-table-column>
<el-table-column label="参数键值" prop="config_value"></el-table-column>
<el-table-column label="备注" prop="remark"></el-table-column>
<el-table-column label="创建时间" prop="create_time"></el-table-column>
<el-table-column label="更新时间" prop="update_time"></el-table-column>

View File

@ -1,6 +1,6 @@
<template>
<pi-table ref="tableRef" :api="api.system.dept.list" row-key="dept_id" primary-key="parent_id" @selection-change="selectionChange"
hidePagination>
<pi-table ref="tableRef" :api="api.system.dept.list" row-key="dept_id" primary-key="parent_id"
@selection-change="selectionChange" hidePagination>
<template #do>
<el-button v-auth="'dept:add'" type="primary" icon="el-icon-plus" @click="add"></el-button>
<el-button v-auth="'dept:del'" type="danger" plain icon="el-icon-delete" :disabled="selection.length===0"
@ -21,11 +21,13 @@
</el-table-column>
<el-table-column label="创建时间" prop="create_time"></el-table-column>
<el-table-column label="备注" prop="remark"></el-table-column>
<el-table-column label="操作" fixed="right" align="right" width="170">
<el-table-column label="操作" fixed="right" align="right" width="120">
<template #default="scope">
<el-button-group>
<el-button text type="primary" size="small" @click="table_show(scope.row, scope.$index)">查看
</el-button>
<el-button text type="primary" size="small" @click="add(scope.row, scope.$index)">支部
</el-button>
<el-button v-auth="'dept:edit'" text type="success" size="small"
@click="table_edit(scope.row, scope.$index)">编辑
</el-button>
@ -63,10 +65,10 @@ let search = ref({
//
function add() {
function add(row) {
dialogShow.value = true
nextTick(() => {
saveRef.value.open()
saveRef.value.open().setParent(row.dept_id ?? 0)
})
}
@ -121,9 +123,7 @@ function upsearch() {
<script>
export default {
methods: {
}
methods: {}
}
</script>

View File

@ -78,18 +78,24 @@ function open(m = 'add', data = null) {
mode.value = m;
visible.value = true;
Object.assign(form.value, data)
return {setParent}
}
function setParent(parent_id=0) {
form.value.parent_id = parent_id
}
//
async function getGroup() {
const res = await api.system.dept.list();
groups.value = tools.makeTreeData(res.data, 0, "dept_id");
groups.value = tools.makeTreeData(res.data, 0, "dept_id", "parent_id");
}
//
async function submit() {
//
const validate = await formRef.value.validate().catch(() => {});
const validate = await formRef.value.validate().catch(() => {
});
if (!validate) {
return false
}

View File

@ -14,6 +14,11 @@
<el-table-column type="selection" width="50"></el-table-column>
<el-table-column label="#" type="index" width="50"></el-table-column>
<el-table-column label="岗位名称" prop="post_name"></el-table-column>
<el-table-column label="岗位编码" prop="post_code">
<template #default="scope">
<pi-dict-text :value="scope.row.post_code" type="post_category" cache-key="POST_CATEGORY"/>
</template>
</el-table-column>
<el-table-column label="状态" prop="status">
<template #default="scope">
<el-tag v-if="scope.row.status===1" type="success">启用</el-tag>
@ -49,6 +54,7 @@ import api from "@/api/index";
import {getCurrentInstance, nextTick, ref} from "vue"
import piImport from "@/components/piImport"
import piExport from "@/components/piExport"
import piDictText from "@/components/piDictText"
defineOptions({
name: "systemPost"

View File

@ -4,8 +4,13 @@
<el-form-item label="岗位名称" prop="post_name">
<el-input type="text" v-model="form.post_name" placeholder="请输入岗位名称" clearable></el-input>
</el-form-item>
<el-form-item label="岗位编码" prop="post_code">
<pi-select v-model="form.post_code" :api="api.system.dict_data.option" :params="{key:'post_category'}"
:props="{label: 'dict_label', value: 'dict_value'}"></pi-select>
</el-form-item>
<el-form-item label="排序权重" prop="rank">
<el-input-number v-model="form.rank" controls-position="right" :min="1" :max="9999" style="width: 100%;"></el-input-number>
<el-input-number v-model="form.rank" controls-position="right" :min="1" :max="9999"
style="width: 100%;"></el-input-number>
</el-form-item>
<el-form-item label="是否启用" prop="status">
<el-switch v-model="form.status" :active-value="1" :inactive-value="0"></el-switch>
@ -57,8 +62,11 @@ function open(m = 'add', data = null) {
async function submit() {
//
const validate = await formRef.value.validate().catch(() => {});
if(!validate){ return false }
const validate = await formRef.value.validate().catch(() => {
});
if (!validate) {
return false
}
isSaveing.value = true;
const res = form.value.post_id ? await api.system.post.edit(form.value) : await api.system.post.add(form.value);
isSaveing.value = false;