master
xy 2 years ago
parent a3112b7553
commit 036bb29a29

@ -1,13 +1,13 @@
const Mock = require('mockjs')
const data = Mock.mock({
'items|30': [{
'data|30': [{
id: '@id',
title: '@sentence(10, 20)',
'status|1': ['published', 'draft', 'deleted'],
author: 'name',
display_time: '@datetime',
pageviews: '@integer(300, 5000)'
money: '@integer(300, 5000)'
}]
})
@ -19,10 +19,8 @@ module.exports = [
const items = data.items
return {
code: 20000,
data: {
total: items.length,
items: items
}
data: items.data,
total:items.data.length
}
}
}

@ -0,0 +1,35 @@
import request from "@/utils/request";
import qs from "qs";
export function index(params,isLoading = false) {
return request({
method: "get",
url: "/api/admin/base-form/index",
params,
isLoading
})
}
export function show(params) {
return request({
method: "get",
url: "/api/admin/base-form/show",
params
})
}
export function save(data) {
return request({
method: "post",
url: "/api/admin/base-form/save",
data
})
}
export function destroy(params) {
return request({
method: "get",
url: "/api/admin/base-form/destroy",
params
})
}

@ -0,0 +1,51 @@
import request from "@/utils/request";
export function index(params,isLoading = false) {
return request({
method: "get",
url: "/api/admin/custom-form/index",
params,
isLoading
})
}
export function show(params) {
return request({
method: "get",
url: "/api/admin/custom-form/show",
params
})
}
export function save(data) {
return request({
method: "post",
url: "/api/admin/custom-form/save",
data
})
}
export function destroy(params) {
return request({
method: "get",
url: "/api/admin/custom-form/destroy",
params
})
}
export function config(params) {
return request({
method: "get",
url: "/api/admin/custom-form/config",
params
})
}
export function update(params) {
return request({
method: "get",
url: "/api/admin/custom-form/update-table",
params,
isLoading:false
})
}

@ -0,0 +1,35 @@
import request from "@/utils/request";
export function index(params,isLoading = false) {
return request({
method: "get",
url: "/api/admin/custom-form-field/index",
params,
isLoading
})
}
export function show(params) {
return request({
method: "get",
url: "/api/admin/custom-form-field/show",
params
})
}
export function save(data) {
return request({
method: "post",
url: "/api/admin/custom-form-field/save",
data
})
}
export function destroy(params) {
return request({
method: "get",
url: "/api/admin/custom-form-field/destroy",
params
})
}

@ -0,0 +1,63 @@
<script>
export default {
props:{
auths:{
type:Array,
default:()=>[]
}
},
data() {
return {}
},
methods: {
},
render(){
let _this = this
//()
let temp = JSON.parse(JSON.stringify(this.auths))
if(temp.indexOf('search') !== -1){
console.log(temp.indexOf('search'))
temp.splice(temp.indexOf('search'),1)
temp.unshift('search')
}
console.log(temp)
return (
<div style={
{
'display':'flex',
'flex-warp':'wrap'
}
}>
<div style={
{
'margin-right':'10px'
}
}>
{ _this.$scopedSlots.default ? _this.$scopedSlots.default() : '' }
</div>
{
temp.map((item,index) => {
if(_this.$scopedSlots[item]){
return (
<div style={
{
'margin-right':'10px'
}
}>
{ _this.$scopedSlots[item](item,index) }
</div>
)
}
})
}
</div>
)
}
}
</script>
<style scoped lang="scss">
</style>

@ -1,6 +1,7 @@
<script>
export default {
props:{
zIndex:Number,
type:{
type:String,
default:"normal"
@ -60,6 +61,7 @@ export default {
},
showChange(e){
this.$emit('update:isShow',e)
this.$emit('on-visible-change',e)
},
validate(){
return new Promise((resolve,reject)=>{
@ -91,15 +93,19 @@ export default {
}
this.$refs['elForm'].validate().then(res=>{
if(res)this.$emit('submit')
}).catch(err=>{
}).catch(err => {
this.$Message.warning({
content:'请填写完整信息',
duration:1
content: "请填写完整信息",
background: true,
duration: 1
})
})
},
okClick(){
this.$emit('on-ok')
},
clearValidate() {
this.$refs['elForm'].clearValidate();
}
},
watch:{
@ -123,6 +129,7 @@ export default {
const {okText,okClick,footerRender,width,type,$scopedSlots,rules,form,showChange,isShow,title} = this
return (
<Modal
z-index={this.zIndex}
ok-text={okText}
class-name={'vertical-center-modal'}
width={width}
@ -288,5 +295,8 @@ export default {
left: calc(100% - 80px) !important;
transform: translateX(-100%);
}
.ivu-message{
z-index: 5000 !important;
}
</style>

@ -97,6 +97,24 @@ export default {
}
</script>
<style lang="scss">
.xy-selectors{
&__item{
display: flex;
align-items: center;
padding: 8px 20px;
&--name{
width: 100px;
margin-right: 20px;
}
}
}
</style>
<style scoped lang="scss">
@import "../../styles/variables";
.xy-selectors{
@ -108,7 +126,7 @@ export default {
//align-items: center;
&__item{
margin-right: 10px;
//margin-right: 10px;
}
&__select{
@ -136,8 +154,7 @@ export default {
&-card{
//width: 100%;
background: rgba(239,242,250,0.95);
border-radius: 4px;
border-top-left-radius: 0;
border-radius: 0 4px 4px 4px;
border: $primaryColor solid 1px;
box-shadow: 0 4px 10px 1px $primaryColor;
@ -164,6 +181,7 @@ export default {
width: 100%;
display: flex;
justify-content: space-evenly;
background: rgba(239,242,250,0.95);
position: absolute;
bottom: 0;

@ -1,15 +1,21 @@
<script>
import axios from 'axios';
import {getToken} from "@/utils/auth";
import axios from "axios";
import { getToken } from "@/utils/auth";
export default {
props: {
//
action:[String,Function], //String Functionpromise
reqOpt:Object, //
resProp:{
type:String,
default:'data'
},//
action: [String, Function], //String Functionpromise
destroyAction: [Function], //promise
delayReq: {
type: Boolean,
default: false
},//
reqOpt: Object, //
destroyReqOpt:Object,
resProp: {
type: String,
default: "data",
}, //
//
auths: {
@ -171,19 +177,20 @@ export default {
return {
isBtns: false,
tableHeight: null,
//document.documentElement.clientHeight -50 -37 - 20- 25 - 76,
//document.documentElement.clientHeight -50 -37 - 20- 25 - 76,
isShowPage: true,
checkTable: this.tableItem.map((item) => item?.prop),
loading: false,
visibleBtn: true, //
sortFlag:0,
totalData:0,
listData:[],
selectOpt:{
page:1,
page_size:10,
sort_name:'',
sort_type:''
totalData: 0,
listData: [],
selectOpt: {
page: 1,
page_size: 10,
sort_name: "",
sort_type: "",
},
};
},
@ -191,7 +198,9 @@ export default {
//
initLoad() {
let clientHeight = document.documentElement.clientHeight;
let lxheader = document.querySelector('.v-header').getBoundingClientRect()
let lxheader = document
.querySelector(".v-header")
.getBoundingClientRect();
let lxHeader_height = lxheader.height + 25; //
let paginationHeight = 37; //
let topHeight = 50; //
@ -199,61 +208,78 @@ export default {
clientHeight - lxHeader_height - topHeight - paginationHeight - 20 - 25;
//console.log(this.tableHeight)
},
getTableData(isRefresh = false){
if(isRefresh){
this.selectOpt.page = 1
}
switch (typeof this.action){
case "string":
this.loading = true
axios({
baseURL:process.env.VUE_APP_BASE_API,
url:this.action,
headers:{
Authorization:"Bearer " + getToken()
},
params:(this.reqOpt.method && this.reqOpt.method === 'get') ? this.selectOpt : '',
data:(this.reqOpt.method && this.reqOpt.method === 'post') ? this.selectOpt : '',
...this.reqOpt
}).then(res => {
this.listData = this.getByStrkey(res.data,this.resProp)
this.totalData = res.data.total
setTimeout(() => {
this.loading = false
},300)
}).catch(err => {
console.error(err)
this.loading = false
})
break;
case "function":
this.loading = true
this.action(false,{
...this.selectOpt,
...this.reqOpt
}).then(res => {
this.listData = this.getByStrkey(res,this.resProp)
this.totalData = res.total
setTimeout(() => {
this.loading = false
},300)
}).catch(err => {
console.error(err)
this.loading = false
})
break;
async getTableData(isRefresh = false) {
if (isRefresh) {
this.selectOpt.page = 1;
}
setTimeout(() => {
switch (typeof this.action) {
case "string":
this.loading = true;
axios({
baseURL: process.env.VUE_APP_BASE_API,
url: this.action,
headers: {
Authorization: "Bearer " + getToken(),
},
params:
this.reqOpt.method && this.reqOpt.method === "get"
? this.selectOpt
: "",
data:
this.reqOpt.method && this.reqOpt.method === "post"
? this.selectOpt
: "",
...this.reqOpt,
})
.then((res) => {
this.listData = this.getByStrkey(res.data, this.resProp);
this.totalData = res.data.total;
setTimeout(() => {
this.loading = false;
}, 300);
})
.catch((err) => {
console.error(err);
this.loading = false;
});
break;
case "function":
this.loading = true;
this.action({
...this.selectOpt,
...this.reqOpt,
},false)
.then((res) => {
this.listData = this.getByStrkey(res, this.resProp);
this.totalData = res.total;
setTimeout(() => {
this.loading = false;
}, 300);
})
.catch((err) => {
console.error(err);
this.loading = false;
});
break;
case "undefined":
break
default:
console.error("ACTION TYPE ERROR")
return;
}
})
},
getByStrkey(obj,str){
if(!str) return obj
getByStrkey(obj, str) {
if (!str) return obj;
let res = this.deepCopy(obj);
let keys = str.split('.')
keys.forEach(key => {
res = res[key]
})
let keys = str.split(".");
keys.forEach((key) => {
res = res[key];
});
return res;
},
deepCopy(data){
deepCopy(data) {
//string,number,bool,null,undefined,symbol
//object,array,date
if (data && typeof data === "object") {
@ -294,19 +320,27 @@ export default {
return data;
}
},
sortListener({column, prop, order}){
this.selectOpt.sort_name = prop
switch (order){
case "ascending":
this.selectOpt.sort_type = 'ASC'
break;
case "descending":
this.selectOpt.sort_type = 'DESC'
break;
default:
this.selectOpt.sort_type = ''
sortListener({ column, prop, order }) {
if(prop === this.selectOpt.sort_name){
this.sortFlag ++
}else{
this.sortFlag = 0
}
this.getTableData()
this.selectOpt.page = 1;
this.selectOpt.sort_name = prop;
this.selectOpt.sort_type = ['ASC','DESC',null][this.sortFlag % 3]
// TODO:
// switch (order) {
// case "ascending":
// this.selectOpt.sort_type = "ASC";
// break;
// case "descending":
// this.selectOpt.sort_type = "DESC";
// break;
// default:
// this.selectOpt.sort_type = "";
// }
this.getTableData();
},
//element table
@ -339,6 +373,9 @@ export default {
sort() {
this.$refs.table.sort();
},
getSelection(){
return this.$refs.table?.store?.states?.selection ?? []
},
//table
delete(row, type) {
@ -399,10 +436,23 @@ export default {
this.$emit("expand-change", row, expanded);
},
deleteClick(row) {
this.$emit('delete', row)
this.$emit("delete", row);
if (this.destroyAction) {
this.destroyAction({
id: row.id,
...this.destroyReqOpt
},false).then((res) => {
this.$message({
type: "success",
message: "删除成功",
});
if(this.action)this.getTableData();
this.$emit('destroyed',row)
});
}
},
editorClick(row) {
this.$emit('editor', row)
this.$emit("editor", row);
},
createPage() {
@ -418,27 +468,31 @@ export default {
show-total={true}
page-size={this.pageSize}
v-show={this.isShowPage}
total={this.action ? (this.totalData || this.listData.length) : this.total}
total={
this.action
? this.totalData || this.listData.length
: this.total
}
size="small"
show-elevator={true}
show-sizer={this.showSizer}
class="xy-table__page"
on={{
["on-page-size-change"]: (e) => {
if(this.action){
this.selectOpt.page_size = e
this.selectOpt.page = 1
this.getTableData()
if (this.action) {
this.selectOpt.page_size = e;
this.selectOpt.page = 1;
this.getTableData();
}
this.$emit("pageSizeChange", e)
this.$emit("pageSizeChange", e);
},
["on-change"]: (e) => {
if(this.action){
this.selectOpt.page = e
this.getTableData()
if (this.action) {
this.selectOpt.page = e;
this.getTableData();
}
this.$emit("pageIndexChange", e)
}
this.$emit("pageIndexChange", e);
},
}}
></Page>
</transition>
@ -452,11 +506,13 @@ export default {
return (
<el-checkbox-group v-model={this.checkTable}>
{this.$props?.tableItem?.map((item, index) => {
return item.type !== 'expand' ? (
return item.type !== "expand" ? (
<el-checkbox label={item.prop} key={item.prop}>
{item.label}
</el-checkbox>
) : ''
) : (
""
);
})}
</el-checkbox-group>
);
@ -521,22 +577,68 @@ export default {
);
btns.set(
"delete",
<Poptip
transfer={true}
confirm
title="确认要删除吗"
on={{ ["on-ok"]: () => _this.deleteClick(scope.row, "delete") }}
>
<i-button
style={{
"margin-right": "6px",
}}
type="error"
size="small"
>
删除
</i-button>
</Poptip>
<el-popover width="180"
trigger="hover"
ref={`${scope.column.id}-${scope.$index}`}
scopedSlots={{
"default": () => {
return (
<div>
<p style={{'padding-bottom':'10px'}}>确定要删除吗</p>
<div style={{"text-align":"right","margin":"0"}}>
<el-button size="mini"
type="text"
on={{
['click']:e => {
this.$refs[`${scope.column.id}-${scope.$index}`].doClose()
}
}}>取消</el-button>
<el-button type="primary"
size="mini"
on={{
['click']:() => _this.deleteClick(scope.row, "delete")
}}>确定</el-button>
</div>
</div>
)
},
"reference":() => {
return (
<div style={{ "margin-right": "6px","height":"100%","width":"100%"}}>
<i-button
type="error"
size="small"
on={{
['click']:e => {
this.$refs[`${scope.column.id}-${scope.$index}`].doShow()
}
}}
>
删除
</i-button>
</div>
)
}
}}>
</el-popover>
// <Poptip
// transfer={true}
// confirm
// title=""
// on={{ ["on-ok"]: () => _this.deleteClick(scope.row, "delete") }}
// >
// <i-button
// style={{
// "margin-right": "6px",
// }}
// type="error"
// size="small"
// >
//
// </i-button>
// </Poptip>
);
let flag = 0;
let dom = (
@ -572,8 +674,25 @@ export default {
});
},
},
watch:{
tableItem(newVal){
this.checkTable = newVal.map((item) => item?.prop)
},
},
created() {
this.getTableData()
if(this.delayReq) {
let watch = this.$watch(()=>this.reqOpt,async (newVal,oldVal)=>{
if(this.action) {
await this.getTableData();
watch();
}
},{
deep: true,
immediate: true
})
} else {
if(this.action) this.getTableData();
}
},
mounted() {
this.initLoad();
@ -581,7 +700,7 @@ export default {
updated() {
this.$nextTick(() => {
this.doLayout();
})
});
},
render(h) {
let { $scopedSlots } = this;
@ -638,7 +757,9 @@ export default {
["row-dblclick"]: this.rowDblclick,
["header-click"]: this.headerClick,
["header-contextmenu"]: this.headerContextmenu,
["sort-change"]: this.action ? this.sortListener : this.sortChange,
["sort-change"]: this.action
? this.sortListener
: this.sortChange,
["filter-change"]: this.filterChange,
["current-change"]: this.currentChange,
["header-dragend"]: this.headerDragend,
@ -651,9 +772,12 @@ export default {
}
return (
<el-table-column
key={String(Math.random())+index}
// TODO: keysort
//key={`xy-table-col-${item.prop}`}
key={String(Math.random()) + index}
type={item.type}
index={item.index}
//column-key={`xy-table-column-${item.prop}`}
column-key={String(Math.random())}
label={item.label}
prop={item.prop}
@ -694,17 +818,18 @@ export default {
: ""
}
>
{ item.multiHd
{item.multiHd
? item.multiHd.map((item1, index1) => {
return (
<el-table-column
key={`xy-table-col-multi-${item1.prop}`}
//key={`xy-table-col-multi-${item1.prop}`}
key={String(Math.random()) + index1}
prop={`${item.pProp ? item.pProp + "." : ""}${
item1.prop
}`}
type={item1.type}
index={item1.index}
column-key={String(Math.random())}
column-key={String(Math.random() + index1)}
label={item1.label}
prop={item1.prop}
width={item1.width ?? "auto"}
@ -717,7 +842,9 @@ export default {
sort-orders={item1.sortOrders}
resizale={item1.resizale ?? false}
formatter={item1.formatter}
show-overflow-tooltip={item1.showOverflowTooltip ?? true}
show-overflow-tooltip={
item1.showOverflowTooltip ?? true
}
align={item1.align ?? "center"}
header-align={item1.headerAlign ?? "center"}
class-name={`xy-table__row-fade ${item1.className}`}
@ -745,10 +872,10 @@ export default {
</el-table-column>
);
})}
{ $scopedSlots.btns ? $scopedSlots.btns() : this.isCreateAuthBtns() }
{$scopedSlots.btns ? $scopedSlots.btns() : this.isCreateAuthBtns()}
</el-table>
) : (
<el-table height={this.height ?? this.tableHeight} />
<el-table ref="table" v-loading={this.loading} height={this.height ?? this.tableHeight} />
)}
<el-backtop
@ -757,7 +884,7 @@ export default {
bottom={100}
right={36}
></el-backtop>
{ this.createPage() }
{this.createPage()}
</div>
);
},

@ -0,0 +1,108 @@
export default [
{
label: "element-ui",
options: [
{
value: "el-radio",
label: "单选框",
},
{
value: "el-checkbox",
label: "多选框",
},
{
value: "text",
label: "输入框",
},
{
value: "el-input-number",
label: "计数器",
},
{
value: "el-select",
label: "选择器"
},
{
value: "el-switch",
label: "开关",
},
{
value: "el-slider",
label: "滑块",
},
{
value: "el-time-select",
label: "时间选择器",
},
{
value: "el-date-picker",
label: "日期选择器",
},
{
value: "el-upload",
label: "上传",
},
{
value: "el-rate",
label: "评分",
},
{
value: "el-color-picker",
label: "颜色选择器",
},
],
},
{
label: "iview",
options: [
{
value: "Input",
label: "输入框",
},
{
value: "Radio",
label: "单选框",
},
{
value: "Checkbox",
label: "多选框",
},
{
value: "Switch",
label: "开关",
},
{
value: "select",
label: "选择器",
},
{
value: "Slider",
label: "滑块",
},
{
value: "DatePicker",
label: "日期选择器",
},
{
value: "TimeSelect",
label: "时间选择器",
},
{
value: "InputNumber",
label: "计数器",
},
{
value: "Upload",
label: "上传",
},
{
value: "Rate",
label: "评分",
},
{
value: "ColorPicker",
label: "颜色选择器",
},
],
},
];

@ -0,0 +1,22 @@
export const op = [
{
value: "like",
label: "包含"
},
{
value: "notlike",
label: "不包含"
},
{
value: "eq",
label: "等于"
},
{
value: "neq",
label: "不等于"
},
{
value: "range",
label: "范围"
}
]

@ -40,7 +40,9 @@ Vue.use(VueParticles)
// set ElementUI lang to EN
//Vue.use(ElementUI, { locale })
// 如果想要中文版 element-ui按如下方式声明
Vue.use(ElementUI)
Vue.use(ElementUI)
import Message from 'element-ui/lib/message';
Vue.config.productionTip = false
@ -76,26 +78,6 @@ Vue.prototype.$integrateData = (target,value) => {
}
}
}
Vue.prototype.$successMessage = (type,name) => {
let word;
switch (type){
case 'add':
word = '新增'
break;
case 'editor':
word = '编辑'
break;
case 'destroy':
word = '删除'
break;
default:
word = type
}
Vue.prototype.$message({
type:'success',
message:`${word}${name}成功`
})
}
new Vue({
el: '#app',
router,

@ -0,0 +1,13 @@
export const authMixin = {
data(){
return {
auths_auth_mixin:[],
}
},
created() {
if(this.$route.meta?.auths?.length > 0 && this.$route.meta.auths[0]){
this.auths_auth_mixin = this.$route.meta.auths
}
console.log(this.auths_auth_mixin)
}
}

@ -60,11 +60,27 @@ const state = {
* 后台查询的菜单数据拼装成路由格式的数据
* @param routes
*/
const pathHandler = (path,id) => {
if(path.includes('#') || path == ''){
return id + '_key'
const pathHandler = (item) => {
if(!item.path || item.path?.includes('#') || item.path == ''){
return item.id + '_key'
}
return path
if(/^\^/.test(item.path)){
return item.path.replace(/^\^+/g,"")
}
if(/^\$/.test(item.path)){
return item.path.replace(/^\$+/g,"")
}
return item.path
// if(path.includes('$')){
// return path.replace(/^\$+/g,"")
// }
// if(path.includes('^')){
// return path.replace(/^\^+/g,"")
// }
// if(path.includes('#') || path == ''){
// return id + '_key'
// }
// return path
}
const componentHandler = (path) => {
//return path === '#'|| path == '' ? Layout : loadView(path)
@ -76,70 +92,85 @@ const componentHandler = (path) => {
}
return loadView(path)
}
/**
* 后台查询的菜单数据拼装成路由格式的数据
* @param routes
*/
export function generaMenu(routes, data) {
data.forEach(item => {
if (item.url === "/") {
routes.push({
path: '/',
component: Layout,
redirect: '/dashboard',
children: [{
path: 'dashboard',
name: '系统首页',
component: () => import('@/views/dashboard/index'),
meta: {
title: '系统首页',
icon: 'dashboard'
}
}]
})
} else if (item.url === "##") {
routes.push({
path: item.path,
component: Layout,
children: [{
path: item.path,
name: item.name,
component: item.url === '#' ? Layout : loadView(item.path),
meta: {
title: item.name,
id: item.id,
roles: ['admin'],
icon: item.icon
}
}]
})
} else {
var path = item.url;
if (item.path != "null" && item.path != null && item.path != "") {
path = item.path
}
const menu = {
path: (path === '#' ? item.id + '_key' : path),
redirect: (item.children.length > 0 ? "noRedirect" : ""),
component: item.url === '#' ? Layout : loadView(item.url),
// hidden: true,
children: [],
name: 'menu_' + item.id,
meta: {
title: item.name,
id: item.id,
roles: ['admin'],
icon: item.icon
}
}
if (item.children) {
generaMenu(menu.children, item.children)
}
routes.push(menu)
}
})
// path为#,左边栏根目录无视图,##下级根目录无视图,$不显示在左边栏视图,^左边栏根目录有视图
export function generaMenu(routes, data) {
data.forEach(item => {
let params = {};
if(item.path?.includes('?')){
let flag = item.path.split('?')
item.path = flag[0]
if(flag[1]){
let list = flag[1].split('&')
list.forEach(item => {
let kv = item.split('=')
Object.defineProperty(params,kv[0],{
value:kv[1],
writable:true,
enumerable:true,
configurable:false
})
})
}
}
if (item.url === "/") {
} else if(/^\^/.test(item.path)){
const menu = {
path: pathHandler(item),
component: Layout,
children: [{
path: "",
name: 'menu_' + item.id,
component: (item.url.includes('#')||item.path == '') ? Layout : loadView(item.url),
meta: {
title: item.name,
id: item.id,
roles: ['admin'],
auths:item.has_auth_node_tags,
params,
icon: item.icon
}
}, ]
}
if (item.children) {
generaMenu(menu.children, item.children)
}
routes.push(menu)
} else {
const menu = {
path: pathHandler(item),
//(item.path === '#'||item.path == '' ? item.id + '_key' : item.path),
component: componentHandler(item.url),
//(item.path === '#'||item.path == '' ? Layout : loadView(item.path)),
// hidden: true,
children: [],
name: 'menu_' + item.id,
meta: {
title: item.name,
id: item.id,
roles: ['admin'],
auths:item.has_auth_node_tags,
params,
icon: item.icon
}
}
if(item.path?.includes("$")){
menu.hidden = true
}
if (item.children) {
generaMenu(menu.children, item.children)
}
routes.push(menu)
}
})
// routes.push({
// path: '*',
// redirect: '/404',
// hidden: true
// })
}
const mutations = {
@ -175,8 +206,8 @@ const mutations = {
const actions = {
generateRoutes({
commit
}, roles) {
commit
}, roles) {
return new Promise(resolve => {
const loadMenuData = []
// 先查询后台并返回左侧菜单数据并把数据添加到路由

@ -115,3 +115,46 @@ export function param2Obj(url) {
})
return obj
}
//深拷贝数据
export function deepCopy(data) {
//string,number,bool,null,undefined,symbol
//object,array,date
if (data && typeof data === "object") {
//针对函数的拷贝
if (typeof data === "function") {
let tempFunc = data.bind(null);
tempFunc.prototype = deepCopy(data.prototype);
return tempFunc;
}
switch (Object.prototype.toString.call(data)) {
case "[object String]":
return data.toString();
case "[object Number]":
return Number(data.toString());
case "[object Boolean]":
return Boolean(data.toString());
case "[object Date]":
return new Date(data.getTime());
case "[object Array]":
let arr = [];
for (let i = 0; i < data.length; i++) {
arr[i] = deepCopy(data[i]);
}
return arr;
//js自带对象或用户自定义类实例
case "[object Object]":
let obj = {};
for (let key in data) {
//会遍历原型链上的属性方法可以用hasOwnProperty来控制 obj.hasOwnProperty(prop)
obj[key] = deepCopy(data[key]);
}
return obj;
}
} else {
//string,number,bool,null,undefined,symbol
return data;
}
}

@ -0,0 +1,245 @@
<script>
import { save, show } from "@/api/system/baseForm";
import { getparameter } from "@/api/system/dictionary";
export default {
props: {
formInfo: {
type: Array,
default: () => [],
},
tableName: String
},
render(h) {
let domMap = new Map([
['text', 'el-input'],
['textarea', 'el-input'],
['checkbox', 'el-select'],
['date', 'el-date-picker'],
['datetime', 'el-time-select']
])
let typeMap = new Map([
['text', ''],
['textarea', 'textarea'],
['checkbox', ''],
['date', 'date'],
['datetime', '']
])
return h(
"el-dialog",
{
props: {
title: "新增",
visible: this.dialogVisible,
width: "30%",
},
on: {
"update:visible": (val) => {
this.dialogVisible = val;
},
},
},
[
h(
"el-form",
{
ref: "elForm",
props: {
model: this.form,
labelWidth: "80px",
rules: this.rules,
labelPosition: "right",
size: "small"
},
},
this.formInfo.map((i,index) => {
return h("el-form-item",{
ref: `elFormItem${i.field}`,
props: {
label: i.name,
prop: i.field
}
},[
h(domMap.get(i.edit_input),{
props: {
value: this.form[i.field],
type: typeMap.get(i.edit_input),
placeholder: `请填写${i.name}`,
valueFormat: (() => {
if(i.edit_input === 'date') {
return 'yyyy-MM-dd'
}
})(),
},
attrs: {
placeholder: `请填写${i.name}`
},
on: {
['input']:e => {
if(i.field) {
this.form[i.field] = e
this.form = Object.assign({}, this.form)
}
}
}
},(i.edit_input === 'checkbox' && i.paramters) ? i.paramters.map(param => {
return h('el-option',{
props: {
label: param.value,
value: param.id,
key: param.id
}
})
}) : '')
])
})
),
h("template", { slot: "footer" }, [
h(
"el-button",
{
on: {
click: () => (this.dialogVisible = false),
},
},
"取消"
),
h(
"el-button",
{
props: {
type: 'warning',
plain: true
},
on: {
click: () => (this.init()),
},
},
"重置"
),
h(
"el-button",
{
props: {
type: "primary",
},
on: {
click: this.submit
},
},
"确定"
),
]),
]
);
},
data() {
return {
id: "",
type: "add",
dialogVisible: false,
form: {},
rules: {},
};
},
methods: {
init() {
for(let key in this.form) {
this.form[key] = ""
}
this.$refs["elForm"].clearValidate()
},
show() {
this.dialogVisible = true;
},
hidden() {
this.dialogVisible = false;
},
setType(type = "add") {
let types = ["add", "editor"];
if (types.includes(type)) {
this.type = type;
} else {
console.warn("Unknown type: " + type);
}
},
setId(id) {
if (typeof id == "number") {
this.id = id;
} else {
console.error("error typeof id: " + typeof id);
}
},
async getDetail() {
const res = await show({ id: this.id,table_name: this.tableName });
this.$integrateData(this.form, res);
this.form = Object.assign({}, this.form);
},
submit() {
if (this.type === "add") {
if (this.form.hasOwnProperty("id")) {
delete this.form.id;
}
}
if (this.type === "editor") {
Object.defineProperty(this.form, "id", {
value: this.id,
enumerable: true,
configurable: true,
writable: true,
});
}
this.$refs['elForm'].validate(validate => {
if(validate) {
console.log(this.form)
save(Object.assign(this.form, { table_name: this.tableName })).then(res => {
this.$Message.success({
content: `${this.type === 'add' ? '新增' : '编辑'}成功`
})
this.$emit("refresh")
this.hidden();
})
}
});
}
},
computed: {},
watch: {
formInfo: {
handler: function (newVal) {
this.form = {};
this.rules = {}
newVal.forEach(i => {
if(i.field) {
this.form[i.field] = "";
this.rules[i.field] = [{ required:true,message: `请填写${i.name}` }]
if(i.edit_input === 'checkbox' && i.parameter_id) {
getparameter({ id: i.parameter_id }).then(res => {
i.paramters = res.detail ?? []
})
}
}
})
},
//immediate: true,
},
dialogVisible(val) {
if (val) {
if (this.type === "editor") {
this.$nextTick(() => this.getDetail())
}
} else {
this.id = "";
this.type = "";
this.init();
this.$refs["elForm"].clearValidate();
delete this.form.id;
}
}
}
};
</script>
<style scoped lang="scss"></style>

@ -0,0 +1,190 @@
<template>
<div>
<!-- 查询配置 -->
<div>
<div ref="lxHeader">
<LxHeader icon="md-apps" :text="customForm.tableName" style="margin-bottom: 10px; border: 0px; margin-top: 15px">
<div slot="content"></div>
<slot>
<header-content :auths="auths_auth_mixin">
<template #search>
<div style="display: flex">
<Select v-model="select.filter[0].key" style="width: 100px;" placeholder="搜索条目">
<Option v-for="item in form" :key="item.id" :value="item.field">{{ item.name }}</Option>
</Select>
<Select v-model="select.filter[0].op" style="width: 100px;margin-left: 10px;" placeholder="搜索条件">
<Option v-for="item in op" :key="item.value" :value="item.value">{{ item.label }}</Option>
</Select>
<Input v-model="select.filter[0].value" style="width: 150px;margin-left: 10px;" placeholder="请填写关键词"/>
<Button
style="margin-left: 10px"
type="primary"
@click="$refs['xyTable'].getTableData(true)"
>查询</Button
>
<xy-selectors
style="margin-left: 10px"
@reset="reset"
@search="$refs['xyTable'].getTableData(true)"
>
<template>
<div class="select">
<div class="select__item" v-for="(item,index) in select.filter">
<p>条件{{index+1}}</p>
<Select v-model="item.key" style="width: 100px;" placeholder="搜索条目">
<Option v-for="item in form" :key="item.id" :value="item.field">{{ item.name }}</Option>
</Select>
<Select v-model="item.op" style="width: 100px;margin-left: 10px;" placeholder="搜索条件">
<Option v-for="item in op" :key="item.value" :value="item.value">{{ item.label }}</Option>
</Select>
<Input v-model="item.value" style="width: 150px;margin-left: 10px;" placeholder="请填写关键词"/>
<el-button v-if="index !== 0" size="small" type="danger" icon="el-icon-delete" circle style="margin-left: 10px;" @click="select.filter.splice(index,1)"></el-button>
</div>
</div>
<div class="add-btn">
<el-button size="small" type="primary" icon="el-icon-plus" circle @click="select.filter.push({key: '',op: '',value: ''})"></el-button>
<span>新增一条</span>
</div>
</template>
</xy-selectors>
</div>
</template>
<template #create>
<Button
type="primary"
@click="$refs['dialog'].setType('add'),$refs['dialog'].show()"
>新增</Button
>
</template>
</header-content>
</slot>
</LxHeader>
</div>
</div>
<xy-table
:auths="auths_auth_mixin"
:delay-req="true"
:destroy-action="destroy"
ref="xyTable"
:border="true"
:action="index"
:req-opt="Object.assign(select,selectForm)"
:destroy-req-opt="select"
:table-item="table"
@editor="row => {
$refs['dialog'].setId(row.id);
$refs['dialog'].setType('editor');
$refs['dialog'].show();
}"></xy-table>
<dialoger :table-name="customForm.tableName" :form-info="form" ref="dialog" @refresh="$refs['xyTable'].getTableData()"></dialoger>
</div>
</template>
<script>
import { index as fieldIndex } from "@/api/system/customFormField"
import { authMixin } from "@/mixin/authMixin";
import { index,destroy } from "@/api/system/baseForm"
import { op } from "@/const/op"
import dialoger from './dialog.vue'
import LxHeader from "@/components/LxHeader/index.vue";
import headerContent from "@/components/LxHeader/XyContent.vue";
export default {
components:{
LxHeader,
dialoger,
headerContent,
},
mixins: [authMixin],
data() {
return {
op,
select: {
table_name: "",
filter: [
{
key: "",
op: "",
value: ""
}
]
},
selectForm: [],
form: [],
table: [],
customForm: {
customFormId: "",
tableName: ""
}
}
},
methods: {
index,destroy,
reset() {
},
async getField() {
if(this.$route.meta.params?.custom_form) {
let decode = decodeURIComponent(this.$route.meta.params?.custom_form)
try {
let custom_form = JSON.parse(decode)
this.customForm.customFormId = custom_form.custom_form_id
this.customForm.tableName = custom_form.table_name
this.select.table_name = custom_form.table_name
}catch (err) {
console.warn(err)
}
}
const res = await fieldIndex({
page: 1,
page_size: 999,
custom_form_id: this.customForm.customFormId
})
this.form = res.data
this.selectForm = ''
this.table = res.data.map(i => {
return {
prop: i.field,
label: i.name
}
})
}
},
computed: {},
created() {
this.getField()
}
}
</script>
<style scoped lang="scss">
.select {
&__item {
& > p {
display: inline-block;
width: 80px;
text-align: center;
}
& + div {
margin-top: 6px;
}
}
}
.add-btn {
display: flex;
justify-content: center;
align-items: center;
& > span {
padding: 0 10px;
}
}
</style>

@ -0,0 +1,305 @@
<template>
<div>
<xy-dialog
ref="dialog"
:z-index="zIndex"
:is-show.sync="isShow"
type="form"
:title="type === 'add' ? '新增字段' : '编辑字段'"
:form="form"
:rules="rules"
@submit="submit"
>
<template v-slot:field>
<div class="xy-table-item">
<div class="xy-table-item-label">
<span style="color: red; font-weight: 600; padding-right: 4px"
>*</span
>
字段名
</div>
<div class="xy-table-item-content">
<el-input
v-model="form.field"
clearable
placeholder="请输入字段名"
style="width: 300px"
></el-input>
</div>
</div>
</template>
<template v-slot:name>
<div class="xy-table-item">
<div class="xy-table-item-label">
<span style="color: red; font-weight: 600; padding-right: 4px"
>*</span
>
名字
</div>
<div class="xy-table-item-content">
<el-input
v-model="form.name"
clearable
placeholder="请输入名字"
style="width: 300px"
></el-input>
</div>
</div>
</template>
<template v-slot:parameter_id>
<div class="xy-table-item">
<div class="xy-table-item-label">数据字典 </div>
<div class="xy-table-item-content">
<el-select
v-model="form.parameter_id"
clearable
:popper-append-to-body="false"
placeholder="请选择数据字典"
style="width: 300px"
>
<el-option
v-for="item in parameters"
:key="item.id"
:label="item.name"
:value="item.id"
></el-option>
</el-select>
</div>
</div>
</template>
<template v-slot:search_input>
<div class="xy-table-item">
<div class="xy-table-item-label">查询输入类型 </div>
<div class="xy-table-item-content">
<el-select
filterable
:popper-append-to-body="false"
v-model="form.search_input"
clearable
placeholder="请选择查询输入类型"
style="width: 300px"
>
<el-option v-for="item in config" :key="item.id" :value="item.edit_input" :label="item.name">
</el-option>
<!-- <el-option-group-->
<!-- v-for="group in inputTypes"-->
<!-- :key="group.label"-->
<!-- :label="group.label">-->
<!-- <el-option-->
<!-- v-for="item in group.options"-->
<!-- :key="item.value"-->
<!-- :label="item.label"-->
<!-- :value="item.value">-->
<!-- </el-option>-->
<!-- </el-option-group>-->
</el-select>
</div>
</div>
</template>
<template v-slot:edit_input>
<div class="xy-table-item">
<div class="xy-table-item-label">
<span style="color: red; font-weight: 600; padding-right: 4px"
>*</span
>
编辑输入类型
</div>
<div class="xy-table-item-content">
<el-select
filterable
:popper-append-to-body="false"
v-model="form.edit_input"
clearable
placeholder="请选择编辑输入类型"
style="width: 300px"
>
<el-option v-for="item in config" :key="item.id" :value="item.edit_input" :label="item.name">
</el-option>
<!-- <el-option-group-->
<!-- v-for="group in inputTypes"-->
<!-- :key="group.label"-->
<!-- :label="group.label">-->
<!-- <el-option-->
<!-- v-for="item in group.options"-->
<!-- :key="item.value"-->
<!-- :label="item.label"-->
<!-- :value="item.value">-->
<!-- </el-option>-->
<!-- </el-option-group>-->
</el-select>
</div>
</div>
</template>
</xy-dialog>
</div>
</template>
<script>
import { config } from "@/api/system/customForm";
import { listparameter } from "@/api/system/dictionary";
import { show, save } from "@/api/system/customFormField";
import inputTypes from "@/const/inputType"
export default {
props: {
zIndex:Number,
},
data() {
return {
parameters: [],
config: [],
//inputTypes,
isShow: false,
id: "",
type: "",
form: {
custom_form_id: "",
field: "",
name: "",
parameter_id: "",
search_input: "",
edit_input: "",
},
rules: {
field: [
{
required: true,
message: "请填写字段名",
},
{
pattern: /^[a-z_]+$/,
message: '字段名只能包含小写英文字母和下划线'
},
],
name: [
{
required: true,
message: "请填写名字",
},
],
edit_input: [
{
required: true,
message: "请填写编辑输入类型",
},
],
},
};
},
methods: {
show() {
this.isShow = true;
},
hidden() {
this.isShow = false;
},
init() {
this.form = {
field: "",
name: "",
parameter_id: "",
search_input: "",
edit_input: "",
};
},
setId(id) {
if (typeof id == "number") {
this.id = id;
} else {
console.error("error typeof id: " + typeof id);
}
},
getId() {
return this.id;
},
setType(type = "add") {
let types = ["add", "editor"];
if (types.includes(type)) {
this.type = type;
} else {
console.warn("Unknown type: " + type);
}
},
setForm(key = [], value = []) {
if (key instanceof Array) {
key.forEach((key, index) => {
this.form[key] = value[index] ?? "";
});
}
if (typeof key === "string") {
this.form[key] = value;
}
if (!key) {
this.init();
}
},
async getParameters() {
const res = await listparameter({ page: 1,page_size :999} )
this.parameters = res.data
},
async getConfig() {
let res = await config()
this.config = res.edit_to_migration
console.log(this.config)
},
async getDetail() {
const res = await show({ id: this.id });
this.$integrateData(this.form, res);
},
submit() {
if (this.type === "add") {
if (this.form.hasOwnProperty("id")) {
delete this.form.id;
}
}
if (this.type === "editor") {
Object.defineProperty(this.form, "id", {
value: this.id,
enumerable: true,
configurable: true,
writable: true,
});
}
save(this.form).then((res) => {
this.$message({
type: "success",
message: this.type === "add" ? "新增字段" : "编辑字段" + "成功",
});
this.isShow = false;
this.$emit("refresh");
});
},
},
watch: {
isShow(val) {
if (val) {
if (this.type === "editor") {
this.getDetail();
}
} else {
this.id = "";
this.type = "";
this.init();
this.$refs["dialog"].clearValidate();
delete this.form.id;
}
},
},
created() {
this.getConfig();
this.getParameters();
}
};
</script>
<style scoped lang="scss">
::v-deep .el-input__inner {
text-align: left;
}
.xy-table-item-label {
width: 180px;
}
</style>

@ -0,0 +1,211 @@
<template>
<div>
<xy-dialog
ref="dialog"
:is-show.sync="isShow"
type="form"
:title="type === 'add' ? '新增表单' : '编辑表单'"
:form="form"
:rules="rules"
@submit="submit"
>
<template v-slot:table_name>
<div class="xy-table-item">
<div class="xy-table-item-label">
<span style="color: red; font-weight: 600; padding-right: 4px"
>*</span
>
表名
</div>
<div class="xy-table-item-content">
<el-input
v-model="form.table_name"
clearable
placeholder="请输入表名"
style="width: 300px"
></el-input>
</div>
</div>
</template>
<template v-slot:name>
<div class="xy-table-item">
<div class="xy-table-item-label">
<span style="color: red; font-weight: 600; padding-right: 4px"
>*</span
>
名字
</div>
<div class="xy-table-item-content">
<el-input
v-model="form.name"
clearable
placeholder="请输入名字"
style="width: 300px"
></el-input>
</div>
</div>
</template>
</xy-dialog>
</div>
</template>
<script>
import { show, save } from "@/api/system/customForm";
export default {
props: {},
data() {
return {
isShow: false,
id: "",
type: "",
form: {
table_name: "",
name: "",
},
rules: {
table_name: [
{
required: true,
message: "请填写表名",
},
{
pattern: /^[a-z_]+$/,
message: '表名只能包含小写英文字母和下划线'
},
{
validator: (rule, value, callback) => {
function isPlural(word) {
if (word.endsWith("s")) {
return true;
} else if (word.endsWith("y")) {
const lastButOneChar = word.charAt(word.length - 2);
return !isVowel(lastButOneChar) && !lastButOneChar.includes("'");
} else if (word.endsWith("fe") || word.endsWith("f")) {
const wordWithoutEnding = word.endsWith("fe") ? word.slice(0, -2) : word.slice(0, -1);
return !isVowel(wordWithoutEnding.charAt(wordWithoutEnding.length - 1));
} else {
// irregular plurals
const irregulars = ["child", "children", "mouse", "mice"];
return irregulars.includes(word);
}
}
function isVowel(char) {
return ["a", "e", "i", "o", "u"].includes(char.toLowerCase());
}
if(isPlural(value)) {
callback()
}else {
callback(new Error("请输入复数单词"))
}
},
trigger: 'blur'
}
],
name: [
{
required: true,
message: "请填写名字",
},
],
},
};
},
methods: {
show() {
this.isShow = true;
},
hidden() {
this.isShow = false;
},
setId(id) {
if(typeof id == "number") {
this.id = id;
}else {
console.error("error typeof id: " + typeof id)
}
},
getId() {
return this.id;
},
setType(type = 'add') {
let types = ['add','editor']
if(types.includes(type)) {
this.type = type;
}else{
console.warn("Unknown type: " + type)
}
},
init() {
this.form = {
table_name: "",
name: "",
};
},
setForm(key = [], value = []) {
if (key instanceof Array) {
key.forEach((key, index) => {
this.form[key] = value[index] ?? "";
});
}
if (typeof key === "string") {
this.form[key] = value;
}
if (!key) {
this.init();
}
},
async getDetail() {
const res = await show({ id: this.id });
this.$integrateData(this.form, res);
},
submit() {
if (this.type === "add") {
if (this.form.hasOwnProperty("id")) {
delete this.form.id;
}
}
if (this.type === "editor") {
Object.defineProperty(this.form, "id", {
value: this.id,
enumerable: true,
configurable: true,
writable: true,
});
}
save(this.form).then((res) => {
this.$message({
type: "success",
message: this.type === "add" ? "新增表单" : "编辑表单" + "成功",
});
this.isShow = false;
this.$emit("refresh");
});
},
},
watch: {
isShow(val) {
if (val) {
if (this.type === "editor") {
this.getDetail();
}
} else {
this.id = "";
this.type = "";
this.init();
this.$refs["dialog"].clearValidate();
delete this.form.id;
}
},
},
};
</script>
<style scoped lang="scss">
::v-deep .el-input__inner {
text-align: left;
}
</style>

@ -0,0 +1,159 @@
<template>
<div>
<el-drawer
ref="elDrawer"
title="自定义字段"
:visible.sync="isShow"
size="49%"
direction="rtl"
>
<template>
<div class="btns">
<el-button
size="small"
type="primary"
icon="el-icon-refresh"
circle
@click="$refs['xyTable'].getTableData(true)"
></el-button>
<el-button
size="small"
type="primary"
icon="el-icon-plus"
circle
@click="$refs['addField'].setForm(['custom_form_id'],[id]),$refs['addField'].setType('add'), $refs['addField'].show()"
></el-button>
<el-button
size="small"
type="primary"
icon="el-icon-search"
circle
></el-button>
</div>
<xy-table
:delay-req="true"
:auths="['delete','edit']"
:action="index"
:destroy-action="destroy"
:req-opt="{
custom_form_id: id
}"
ref="xyTable"
:height="400"
style="margin: 0 10px"
:table-item="table"
@editor="row => {
$refs['addField'].setType('editor');
$refs['addField'].setId(row.id);
$refs['addField'].show();
}"
@destroyed="row => {
update({ id })
}"
>
</xy-table>
</template>
</el-drawer>
<addField
:z-index="zIndex"
ref="addField"
@refresh="refreshCallback"
></addField>
</div>
</template>
<script>
import { update } from "@/api/system/customForm"
import { index,destroy } from "@/api/system/customFormField";
import addField from "./addField.vue";
export default {
components: {
addField,
},
data() {
return {
zIndex: 2001,
select: {
custom_form_id: this.id
},
id: null,
isShow: false,
table: [
{
type: "index",
width: 70,
label: "编号",
},
{
prop: "field",
label: "字段标识",
width: 120,
},
{
prop: "name",
label: "名字",
width: 160,
},
],
};
},
methods: {
index,destroy,update,
show() {
this.isShow = true;
},
hidden() {
this.isShow = false;
},
setId(id) {
if (typeof id == "number") {
this.id = id;
} else {
console.error("error typeof id: " + typeof id);
}
},
getId() {
return this.id;
},
refreshCallback() {
this.$refs['xyTable'].getTableData()
update({ id:this.id })
}
},
computed: {},
watch: {
isShow: {
handler: function (newVal) {
if(newVal) {
this.zIndex = Number(
window
.getComputedStyle(this.$refs["elDrawer"].$el)
.getPropertyValue("z-index")
)
? Number(
window
.getComputedStyle(this.$refs["elDrawer"].$el)
.getPropertyValue("z-index")
) + 1
: 2100;
this.$nextTick(() => {
this.$refs['xyTable'].getTableData(true);
})
}
}
}
},
mounted() {
},
};
</script>
<style scoped lang="scss">
.btns {
margin: 0 10px 12px 10px;
}
</style>

@ -0,0 +1,96 @@
<template>
<div class="container">
<!-- 查询配置 -->
<div>
<div ref="lxHeader">
<LxHeader icon="md-apps" text="自定义表单" style="margin-bottom: 10px; border: 0px; margin-top: 15px">
<div slot="content"></div>
<slot>
<div>
<Button type="primary" style="margin-left: 10px" @click="$refs['xyTable'].getTableData()"></Button>
<Button type="primary" style="margin-left: 10px" @click="$refs['addForm'].type = 'add',$refs['addForm'].show()">新增</Button>
</div>
</slot>
</LxHeader>
</div>
</div>
<xy-table
ref="xyTable"
:auths="auths_auth_mixin"
:action="index"
:destroy-action="destroy"
:border="true"
:table-item="table"
@editor="row => {
$refs['addForm'].setType('editor');
$refs['addForm'].setId(row.id);
$refs['addForm'].show();
}">
<template #setting="scope">
<Button type="primary"
size="small"
@click="$refs['formFields'].setId(scope.row.id),$refs['formFields'].show()">字段</Button>
</template>
</xy-table>
<addForm ref="addForm" @refresh="$refs['xyTable'].getTableData()"></addForm>
<formFields ref="formFields"></formFields>
</div>
</template>
<script>
import { index,destroy } from '@/api/system/customForm'
import { authMixin } from "@/mixin/authMixin";
import LxHeader from "@/components/LxHeader/index.vue";
import addForm from "./components/addForm.vue";
import formFields from "./components/formFields.vue";
export default {
components:{
LxHeader,addForm,formFields
},
mixins: [authMixin],
data() {
return {
select:{
page:1,
page_size:10
},
list:[],
table:[
{
type: 'index',
label:'编号',
width:100
},
{
prop:'table_name',
label:'表名',
width:180,
sortable:'custom',
},
{
prop:'name',
label:'名称',
width:200,
sortable:'custom',
},
]
}
},
methods: {
index,destroy,
},
computed: {},
mounted() {
}
}
</script>
<style scoped lang="scss">
</style>

@ -1,359 +1,515 @@
<template>
<div class="container">
<!-- 查询配置 -->
<div>
<div ref="lxHeader">
<LxHeader icon="md-apps" text="菜单管理" style="margin-bottom: 10px; border: 0px; margin-top: 15px">
<div slot="content"></div>
<slot>
<div>
<Input style="width: 200px; margin-right: 10px" v-model.number="searchFields.Name" placeholder="关键字搜索" />
<Button type="primary" @click="load" style="margin-left: 10px">查询</Button>
<Button type="primary" @click="edit()" style="margin-left: 10px">新增菜单</Button>
</div>
</slot>
</LxHeader>
</div>
<div class="table-tree">
<el-table :data="tableData" :height="tableHeight" class="v-table" style="width: 100%;margin-bottom: 20px;"
row-key="id" border default-expand-all :tree-props="{children: 'children', hasChildren: 'hasChildren'}">
<el-table-column type="index" align="center">
</el-table-column>
<el-table-column prop="name" label="菜单" sortable width="180">
</el-table-column>
<el-table-column prop="url" label="菜单路径" sortable>
</el-table-column>
<el-table-column prop="path" label="路由" sortable>
</el-table-column>
<el-table-column prop="icon" label="图标" sortable>
</el-table-column>
<el-table-column prop="api_prefix" label="API前缀" sortable>
</el-table-column>
<el-table-column prop="sortnumber" label="排序" sortable>
</el-table-column>
<el-table-column fixed="right" label="操作" width="300">
<template slot-scope="scope">
<Button type="primary" @click="addchildren(scope.row)" size="small" style="margin-left: 10px;"
ghost>子菜单</Button>
<Button type="error" @click="del(scope.row)" size="small" style="margin-left: 10px;" ghost>删除</Button>
<Button type="primary" @click="edit(scope.row)" size="small" style="margin-left: 10px;" ghost>编辑</Button>
</template>
</el-table-column>
</el-table>
</div>
</div>
<el-dialog title="菜单编辑" :visible.sync="dialogFormVisible" width="60%">
<el-form :model="form" :rules="rules" ref="form" label-position="right" :label-width="formLabelWidth">
<el-row>
<el-col :span="12">
<el-form-item label="父菜单">
<el-input v-model="form.pname" disabled autocomplete="off"></el-input>
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="18">
<el-form-item label="名称" prop="name">
<el-input v-model="form.name" autocomplete="off"></el-input>
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="18">
<el-form-item label="菜单路径" prop="url">
<el-input v-model="form.url" autocomplete="off"></el-input>
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="18">
<el-form-item label="路由" prop="path">
<el-input v-model="form.path" autocomplete="off"></el-input>
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="12">
<el-form-item label="API前缀" prop="api_prefix">
<el-input v-model="form.api_prefix" autocomplete="off"></el-input>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="排序">
<el-input v-model="form.sortnumber" autocomplete="off"></el-input>
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="12">
<el-form-item label="是否显示" prop="visible">
<el-select v-model="form.visible">
<el-option label="显示" value="1"></el-option>
<el-option label="不显示" value="0"></el-option>
</el-select>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="图标" prop="icon">
<el-input v-model="form.icon" autocomplete="off"></el-input>
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="24">
<div style="display: flex;align-items: center;justify-content: space-between;">
<el-form-item label="操作权限" prop="auth_node_tags">
<el-checkbox-group v-model="form.auth_node_tagsArr">
<el-checkbox :label="item.tag" v-for="(item,index) of list" :key="item.id">
{{item.name}}
</el-checkbox>
</el-checkbox-group>
</el-form-item>
<el-button size="small" @click="dialogOptFormVisible=true" round>新增</el-button>
</div>
</el-col>
</el-row>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button @click="resetForm('form')"> </el-button>
<el-button type="primary" @click="submitForm('form')"> </el-button>
</div>
</el-dialog>
<el-dialog title="操作新增" :visible.sync="dialogOptFormVisible" width="30%">
<el-form :model="actionForm" :rules="actionRules" ref="actionForm" label-position="right"
:label-width="formLabelWidth">
<el-form-item label="标识" prop="tag">
<el-input v-model="actionForm.tag" autocomplete="off"></el-input>
</el-form-item>
<el-form-item label="名称" prop="name">
<el-input v-model="actionForm.name" autocomplete="off">
</el-input>
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button @click="resetForm('actionForm')"> </el-button>
<el-button type="primary" @click="saveAuthForm('actionForm')"> </el-button>
</div>
</el-dialog>
</div>
</template>
<script>
import LxHeader from "@/components/LxHeader/index.vue";
import {
save,
listmenu,
del
} from "../../api/system/menu.js";
import {
store as storeAuth,
list,
del as delAuth
} from "../../api/system/auth.js";
export default {
components: {
LxHeader
},
created() {
this.initLoad();
this.load();
},
mounted() {},
data() {
return {
dialogOptFormVisible: false,
dialogFormVisible: false,
formLabelWidth: "120px",
form: {
name: "",
id: "",
pid: "0",
url: "",
visible: "1",
sortnumber: 0,
icon: "",
pname: "根菜单",
api_prefix: "",
auth_node_tagsArr: [],
auth_node_tags: "",
path: ""
},
actionRules: {
tag: [{
required: true,
message: '请输入标识',
trigger: 'blur'
}],
name: [{
required: true,
message: '请输入名称',
trigger: 'blur'
}],
},
rules: {
name: [{
required: true,
message: '请输入菜单名称',
trigger: 'blur'
}],
url: [{
required: true,
message: '请输入菜单路径',
trigger: 'blur'
}],
icon: [{
required: true,
message: '请输入图标',
trigger: 'blur'
}],
visible: [{
required: true,
message: '请选择是否显示',
trigger: 'blur'
}],
},
tableHeight: 0,
//
searchFields: {
KeyWord: ""
},
tableData: [],
list: [],
actionForm: {
name: "",
tag: ""
}
}
},
methods: {
saveAuthForm(formName) {
var that = this;
this.$refs[formName].validate((valid) => {
if (valid) {
storeAuth(that.actionForm).then(response => {
console.log(response)
this.$Message.success('操作成功');
that.dialogOptFormVisible = false;
that.loadAuth();
}).catch(error => {
reject(error)
})
} else {
this.$Message.error('数据校验失败');
return false;
}
});
},
loadAuth() {
var that = this;
list({
page: 1
}).then(res => {
that.list = res.data;
}).catch(error => {
})
},
initLoad() {
var that = this;
var clientHeight = document.documentElement.clientHeight
var lxHeader_height = 96.5; //
var paginationHeight = 37; //
var topHeight = 50; //
let tableHeight = clientHeight - lxHeader_height - topHeight - paginationHeight - 20;
that.tableHeight = tableHeight;
},
load() {
var that = this;
listmenu().then(response => {
that.tableData = response;
}).catch(error => {
//reject(error)
})
},
edit(obj) {
this.form = this.$options.data().form;
this.loadAuth();
if (obj) {
obj.visible = obj.visible.toString();
if (obj.auth_node_tags)
this.form.auth_node_tagsArr = obj.auth_node_tags.split(",");
var result = Object.assign(this.form, obj)
this.form = result;
}
this.dialogFormVisible = true;
},
addchildren(obj) {
this.form = this.$options.data().form
if (obj) {
this.form.pname = obj.name;
this.form.pid = obj.id;
this.dialogFormVisible = true;
}
},
submitForm(formName) {
var that = this;
this.$refs[formName].validate((valid) => {
if (valid) {
this.form.auth_node_tags = this.form.auth_node_tagsArr.join(",");
save(that.form).then(response => {
console.log(response)
this.$Message.success('操作成功');
that.dialogFormVisible = false;
that.load();
}).catch(error => {
reject(error)
})
} else {
this.$Message.error('数据校验失败');
return false;
}
});
},
resetForm(formName) {
var that = this;
this.$refs[formName].resetFields();
if (formName == "form")
that.dialogFormVisible = false;
else
that.dialogOptFormVisible = false
},
del(obj) {
var that = this;
if (obj) {
this.$Modal.confirm({
title: '确认要删除数据?',
onOk: () => {
del({
id: obj.id
}).then(response => {
this.$Message.success('操作成功');
that.load();
}).catch(error => {
console.log(error)
reject(error)
})
},
onCancel: () => {
//this.$Message.info('Clicked cancel');
}
});
}
},
}
};
<template>
<div class="container">
<!-- 查询配置 -->
<div>
<div ref="lxHeader">
<LxHeader
icon="md-apps"
text="菜单管理"
style="margin-bottom: 10px; border: 0px; margin-top: 15px"
>
<div slot="content"></div>
<slot>
<div>
<Input
style="width: 200px; margin-right: 10px"
v-model.number="searchFields.Name"
placeholder="关键字搜索"
/>
<Button type="primary" @click="load" style="margin-left: 10px"
>查询</Button
>
<Button type="primary" @click="edit()" style="margin-left: 10px"
>新增菜单</Button
>
</div>
</slot>
</LxHeader>
</div>
<div class="table-tree">
<el-table
:data="tableData"
:height="tableHeight"
class="v-table"
style="width: 100%; margin-bottom: 20px"
row-key="id"
border
default-expand-all
:tree-props="{ children: 'children', hasChildren: 'hasChildren' }"
>
<el-table-column type="index" align="center"> </el-table-column>
<el-table-column prop="name" label="菜单" sortable width="180">
</el-table-column>
<el-table-column prop="url" label="菜单路径" sortable>
</el-table-column>
<el-table-column prop="path" label="路由" sortable> </el-table-column>
<el-table-column prop="icon" label="图标" sortable> </el-table-column>
<el-table-column prop="api_prefix" label="API前缀" sortable>
</el-table-column>
<el-table-column prop="sortnumber" label="排序" sortable>
</el-table-column>
<el-table-column fixed="right" label="操作" width="300">
<template slot-scope="scope">
<Button
type="primary"
@click="addchildren(scope.row)"
size="small"
style="margin-left: 10px"
ghost
>子菜单</Button
>
<Button
type="error"
@click="del(scope.row)"
size="small"
style="margin-left: 10px"
ghost
>删除</Button
>
<Button
type="primary"
@click="edit(scope.row)"
size="small"
style="margin-left: 10px"
ghost
>编辑</Button
>
</template>
</el-table-column>
</el-table>
</div>
</div>
<el-dialog title="菜单编辑" :visible.sync="dialogFormVisible" width="60%">
<el-form
:model="form"
:rules="rules"
ref="form"
label-position="right"
:label-width="formLabelWidth"
>
<el-row>
<el-col :span="12">
<el-form-item label="父菜单">
<el-input
v-model="form.pname"
disabled
autocomplete="off"
></el-input>
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="18">
<el-form-item label="名称" prop="name">
<el-input v-model="form.name" autocomplete="off"></el-input>
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="18">
<el-form-item label="菜单路径" prop="url">
<el-input v-model="form.url" autocomplete="off"></el-input>
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="18">
<el-form-item label="路由" prop="path">
<el-input v-model="form.path" autocomplete="off"></el-input>
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="18">
<el-form-item label="表单">
<el-select value-key="id" v-model="selectCustomForm">
<el-option
v-for="item in customForms"
:key="item.id"
:value="item"
:label="item.name"
></el-option>
</el-select>
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="12">
<el-form-item label="API前缀" prop="api_prefix">
<el-input v-model="form.api_prefix" autocomplete="off"></el-input>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="排序">
<el-input v-model="form.sortnumber" autocomplete="off"></el-input>
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="12">
<el-form-item label="是否显示" prop="visible">
<el-select v-model="form.visible">
<el-option label="显示" value="1"></el-option>
<el-option label="不显示" value="0"></el-option>
</el-select>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="图标" prop="icon">
<el-input v-model="form.icon" autocomplete="off"></el-input>
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="24">
<div
style="
display: flex;
align-items: center;
justify-content: space-between;
"
>
<el-form-item label="操作权限" prop="auth_node_tags">
<el-checkbox-group v-model="form.auth_node_tagsArr">
<el-checkbox
:label="item.tag"
v-for="(item, index) of list"
:key="item.id"
>
{{ item.name }}
</el-checkbox>
</el-checkbox-group>
</el-form-item>
<el-button size="small" @click="dialogOptFormVisible = true" round
>新增</el-button
>
</div>
</el-col>
</el-row>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button @click="resetForm('form')"> </el-button>
<el-button type="primary" @click="submitForm('form')"> </el-button>
</div>
</el-dialog>
<el-dialog
title="操作新增"
:visible.sync="dialogOptFormVisible"
width="30%"
>
<el-form
:model="actionForm"
:rules="actionRules"
ref="actionForm"
label-position="right"
:label-width="formLabelWidth"
>
<el-form-item label="标识" prop="tag">
<el-input v-model="actionForm.tag" autocomplete="off"></el-input>
</el-form-item>
<el-form-item label="名称" prop="name">
<el-input v-model="actionForm.name" autocomplete="off"> </el-input>
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button @click="resetForm('actionForm')"> </el-button>
<el-button type="primary" @click="saveAuthForm('actionForm')"
> </el-button
>
</div>
</el-dialog>
</div>
</template>
<script>
import LxHeader from "@/components/LxHeader/index.vue";
import { save, listmenu, del } from "@/api/system/menu";
import { index } from "@/api/system/customForm";
import { store as storeAuth, list, del as delAuth } from "@/api/system/auth.js";
export default {
components: {
LxHeader,
},
created() {
this.getCustomForms();
this.initLoad();
this.load();
},
mounted() {},
data() {
return {
selectCustomForm: "",
customForms: [],
dialogOptFormVisible: false,
dialogFormVisible: false,
formLabelWidth: "120px",
form: {
name: "",
id: "",
pid: "0",
url: "",
visible: "1",
sortnumber: 0,
icon: "",
pname: "根菜单",
api_prefix: "",
auth_node_tagsArr: [],
auth_node_tags: "",
path: "",
},
actionRules: {
tag: [
{
required: true,
message: "请输入标识",
trigger: "blur",
},
],
name: [
{
required: true,
message: "请输入名称",
trigger: "blur",
},
],
},
rules: {
name: [
{
required: true,
message: "请输入菜单名称",
trigger: "blur",
},
],
url: [
{
required: true,
message: "请输入菜单路径",
trigger: "blur",
},
],
path: [
{
required: true,
message: "请输入路由",
trigger: "blur",
},
],
icon: [
{
required: true,
message: "请输入图标",
trigger: "blur",
},
],
visible: [
{
required: true,
message: "请选择是否显示",
trigger: "blur",
},
],
},
tableHeight: 0,
//
searchFields: {
KeyWord: "",
},
tableData: [],
list: [],
actionForm: {
name: "",
tag: "",
},
};
},
methods: {
async getCustomForms() {
const res = await index({ page: 1, page_size: 999 });
this.customForms = res.data;
},
saveAuthForm(formName) {
var that = this;
this.$refs[formName].validate((valid) => {
if (valid) {
storeAuth(that.actionForm)
.then((response) => {
console.log(response);
this.$Message.success("操作成功");
that.dialogOptFormVisible = false;
that.loadAuth();
})
.catch((error) => {
reject(error);
});
} else {
this.$Message.error("数据校验失败");
return false;
}
});
},
loadAuth() {
var that = this;
list({
page: 1,
})
.then((res) => {
that.list = res.data;
})
.catch((error) => {});
},
initLoad() {
var that = this;
var clientHeight = document.documentElement.clientHeight;
var lxHeader_height = 96.5; //
var paginationHeight = 37; //
var topHeight = 50; //
let tableHeight =
clientHeight - lxHeader_height - topHeight - paginationHeight - 20;
that.tableHeight = tableHeight;
},
load() {
var that = this;
listmenu()
.then((response) => {
that.tableData = response;
})
.catch((error) => {
//reject(error)
});
},
edit(obj) {
this.form = this.$options.data().form;
this.loadAuth();
if (obj) {
obj.visible = obj.visible.toString();
if (obj.auth_node_tags)
this.form.auth_node_tagsArr = obj.auth_node_tags.split(",");
var result = Object.assign(this.form, obj);
this.form = result;
let queryString = this.form.path.split("?")[1];
// &
let paramsArray = queryString.split("&");
//
let params = {};
// params
for (let i = 0; i < paramsArray.length; i++) {
let param = paramsArray[i].split("=");
let paramName = param[0];
let paramValue = param[1];
params[paramName] = paramValue;
}
// custom_form_id
let customForm = params["custom_form"] ? JSON.parse(decodeURIComponent(params["custom_form"])) : {}
this.selectCustomForm = this.customForms.find(i => i.id === customForm?.custom_form_id)
}
this.dialogFormVisible = true;
},
addchildren(obj) {
this.form = this.$options.data().form;
if (obj) {
this.form.pname = obj.name;
this.form.pid = obj.id;
this.dialogFormVisible = true;
}
},
replaceCustomFormParam(str, newValue) {
// custom_form
const regex = /([&?])custom_form=([^&]*)(&|$)/;
const match = str.match(regex);
if (match) {
const before = match[1]; // "&" "?"
const after = match[3]; // "&" "" custom_form
const oldValue = match[2]; //
//
const newStr = str.replace(
`custom_form=${oldValue}`,
`custom_form=${newValue}`
);
// "&" "&"
return before ? newStr : `${newStr}&`;
} else {
// custom_form
return str + `&custom_form=${newValue}`;
}
},
submitForm(formName) {
var that = this;
this.$refs[formName].validate((valid) => {
if (valid) {
if (that.selectCustomForm) {
let temp = encodeURIComponent(
`{"custom_form_id":${that.selectCustomForm?.id},"table_name":"${that.selectCustomForm?.table_name}"}`
);
if (that.form?.path?.includes("?")) {
if (that.form.path.indexOf("custom_form") === -1) {
that.form.path += `&custom_form=${temp}`;
} else {
that.form.path = that.replaceCustomFormParam(that.form.path,temp);
}
} else {
that.form.path += `?custom_form=${temp}`;
}
}
this.form.auth_node_tags = this.form.auth_node_tagsArr.join(",");
save(that.form)
.then((response) => {
console.log(response);
this.$Message.success("操作成功");
that.dialogFormVisible = false;
that.load();
})
.catch((error) => {
reject(error);
});
} else {
this.$Message.error("数据校验失败");
return false;
}
});
},
resetForm(formName) {
var that = this;
this.$refs[formName].resetFields();
if (formName == "form") that.dialogFormVisible = false;
else that.dialogOptFormVisible = false;
},
del(obj) {
var that = this;
if (obj) {
this.$Modal.confirm({
title: "确认要删除数据?",
onOk: () => {
del({
id: obj.id,
})
.then((response) => {
this.$Message.success("操作成功");
that.load();
})
.catch((error) => {
console.log(error);
reject(error);
});
},
onCancel: () => {
//this.$Message.info('Clicked cancel');
},
});
}
},
},
};
</script>

@ -61,6 +61,11 @@
<el-form-item label="密码" prop="password">
<el-input v-model="form.password" type="password" autocomplete="off"></el-input>
</el-form-item>
<el-form-item label="部门" prop="department_id">
<el-select v-model="form.department_id">
<el-option v-for="item in departmentList" :key="item.id" :label="item.name" :value="item.id"></el-option>
</el-select>
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button @click="resetForm('form')"> </el-button>
@ -82,6 +87,7 @@
import {
list
} from "../../api/system/role.js";
import {listdept} from "@/api/system/department"
export default {
components: {
LxHeader
@ -89,6 +95,7 @@
created() {
this.initLoad();
var that = this;
this.getDepartmentList();
this.loadRole(function() {
that.load();
});
@ -98,6 +105,7 @@
return {
roleList: [],
departmentList: [],
checkAll: false,
isIndeterminate: true,
dialogFormVisible: false,
@ -106,7 +114,8 @@
form: {
name: "",
username: "",
password: ""
password: "",
department_id: "",
},
rules: {
name: [{
@ -182,6 +191,10 @@
//reject(error)
})
},
async getDepartmentList() {
const res = await listdept();
this.departmentList = res;
},
hasRoles(roles, id) {
return roles.filter((p, i) => {
return p.id == id

@ -31,6 +31,9 @@ module.exports = {
loaderOptions: { // 向 CSS 相关的 loader 传递选项
less: {
javascriptEnabled: true
},
sass:{
prependData: '@import "@/styles/index.scss";'
}
}
},

Loading…
Cancel
Save