master
xy 2 years ago
parent fb8d99d444
commit db57d414af

@ -4,3 +4,4 @@ ENV='development'
# base api
VUE_APP_BASE_API=http://starter.ali251.langye.net
VUE_APP_UPLOAD_API=http://starter.ali251.langye.net/api/admin/upload-file
VUE_APP_PREVIEW_API=http://view.ali251.langye.net:8012/onlinePreview

@ -3,4 +3,5 @@ ENV = 'production'
# base api
VUE_APP_BASE_API = http://starter.ali251.langye.net
VUE_APP_UPLOAD_API =http://starter.ali251.langye.net/api/admin/upload-file
VUE_APP_UPLOAD_API =http://starter.ali251.langye.net/api/admin/upload-file
VUE_APP_PREVIEW_API=http://view.ali251.langye.net:8012/onlinePreview

@ -4,5 +4,6 @@ NODE_ENV = production
ENV = 'staging'
# base api
VUE_APP_BASE_API = '/stage-api'
VUE_APP_BASE_API=http://starter.ali251.langye.net
VUE_APP_UPLOAD_API=http://starter.ali251.langye.net/api/admin/upload-file

@ -36,6 +36,7 @@
"vue-router": "3.0.6",
"vuedraggable": "^2.24.3",
"vuex": "3.1.0",
"webpack-md5-hash": "^0.0.6",
"xlsx": "^0.18.5"
},
"devDependencies": {

@ -1,31 +1,33 @@
import request from '@/utils/request'
import request from '@/utils/request'
export function listCommondepartment(params) {
return request({
url: '/api/admin/other/admin-department-list',
method: 'get',
params:params
})
export function listCommondepartment(params) {
return request({
url: '/api/admin/other/admin-department-list',
method: 'get',
params:params,
isLoading: false
})
}
export function listCommonuser(params) {
return request({
url: '/api/admin/other/admin-user-list',
method: 'get',
params:params
})
export function listCommonuser(params) {
return request({
url: '/api/admin/other/admin-user-list',
method: 'get',
params:params,
isLoading: false
})
}
export function remoteStatistic(params) {
return request({
url: '/api/admin/other/remot-statistic',
method: 'get',
params:params
})
export function remoteStatistic(params) {
return request({
url: '/api/admin/other/remot-statistic',
method: 'get',
params:params
})
}

@ -4,7 +4,8 @@ export function login(data) {
return request({
url: '/api/admin/auth/login',
method: 'post',
data
data,
isLoading: false
})
}
@ -12,7 +13,8 @@ export function getInfo(token) {
return request({
url: '/api/admin/auth/me',
method: 'post',
params: { token }
params: { token },
isLoading: false
})
}
@ -27,6 +29,7 @@ export function getAuthMenu(token) {
return request({
url: '/api/admin/auth/permissions',
method: 'get',
params: { token }
params: { token },
isLoading: false
})
}
}

@ -20,7 +20,7 @@ export const addPropsMap = new Map([
["datetime", {
type: 'datetime',
clearable: true,
valueFormat: 'yyyy-MM-dd mm:hh:ss',
valueFormat: 'yyyy-MM-dd hh:mm:ss',
pickerOptions: {
shortcuts: [{
text: '今天',

@ -0,0 +1,10 @@
const validation = new Map([
['integer',/^-?\d+$/],//整数
['date',/(^\d{10})|(^\d{13})|(^((\d\d\d\d(.+)|\d\d(.+))?(0?[1-9](.+)|1[012](.+))?((0?[1-9]|[12]\d|3[01])(.+))?\s?)((0?[0-9]|1[0-9]|2[0-3])(.+))?((0?[0-9]|[1-5][0-9])(.+))?((0?[0-9]|[1-5][0-9])(.+))?)$/],
['email',/^[^\s@]+@[^\s@]+\.[^\s@]+$/],
['idcard',/(^([1-6][1-9]|50)\d{4}\d{2}((0[1-9])|10|11|12)(([0-2][1-9])|10|20|30|31)\d{3})|(^([1-6][1-9]|50)\d{4}(18|19|20)\d{2}((0[1-9])|10|11|12)(([0-2][1-9])|10|20|30|31)\d{3}[0-9Xx])$/],
['mobile',/(^1[3456789]\d{9})|(^(0\d{2,3}(-)*)?\d{7})$/],
['numeric',/^-?\d+(.\d+)?$/],
])
export default validation

@ -5,11 +5,9 @@ import NProgress from 'nprogress' // progress bar
import 'nprogress/nprogress.css' // progress bar style
import { getToken } from '@/utils/auth' // get token from cookie
import getPageTitle from '@/utils/get-page-title'
NProgress.configure({ showSpinner: false }) // NProgress Configuration
const whiteList = ['/login'] // no redirect whitelist
router.beforeEach(async(to, from, next) => {
// start progress bar
NProgress.start()

@ -1,7 +1,7 @@
module.exports = {
title: '朗业基础平台',
TOKEN_KEY: 'starter_token',
/**
* @type {boolean} true | false
* @description Whether fix the header

@ -1,7 +1,93 @@
import {index} from "@/api/system/customFormField";
import {index,destroy} from "@/api/system/customFormField";
import {show,save} from "@/api/system/customForm";
import {Message} from "element-ui";
const uploadField = [
{
"field": "original_name",
"name": "源名称",
"search_input": "text",
"edit_input": "text",
"admin_id": null,
"department_id": null,
"sort": 1,
"help": null,
"validation": [],
"select_item": [],
"list_show": 1,
"form_show": 1,
},
{
"field": "name",
"name": "名称",
"search_input": "text",
"edit_input": "text",
"admin_id": null,
"department_id": null,
"sort": 2,
"help": null,
"validation": [],
"select_item": [],
"list_show": 1,
"form_show": 1,
},
{
"field": "extension",
"name": "后缀名",
"search_input": "text",
"edit_input": "text",
"admin_id": null,
"department_id": null,
"sort": 3,
"help": null,
"validation": [],
"select_item": [],
"list_show": 1,
"form_show": 1,
},
{
"field": "size",
"name": "大小",
"search_input": "text",
"edit_input": "text",
"admin_id": null,
"department_id": null,
"sort": 4,
"help": null,
"validation": [],
"select_item": [],
"list_show": 1,
"form_show": 1,
},
{
"field": "url",
"name": "地址",
"search_input": "text",
"edit_input": "text",
"admin_id": null,
"department_id": null,
"sort": 5,
"help": null,
"validation": [],
"select_item": [],
"list_show": 1,
"form_show": 1,
},
{
"field": "folder",
"name": "类型",
"search_input": "text",
"edit_input": "text",
"admin_id": null,
"department_id": null,
"sort": 6,
"help": null,
"validation": [],
"select_item": [],
"list_show": 1,
"form_show": 1,
}
]
const state = {
formList: [], //更个表单配置信息
copyFormListId: [], //备份原始的字段id数组,以做删除
@ -39,6 +125,25 @@ const mutations = {
};
const actions = {
submitUpload: ({ state, commit }, tableId) => {
return new Promise((resolve, reject) => {
show({ id: tableId }).then(res => {
res.fields = uploadField
save(res).then(res1 => {
Message({
type: 'success',
message: res1.msg
})
resolve(res1)
}).catch(err1 => {
reject(err1)
})
}).catch(err => {
reject(err)
})
})
},
submit: ({ state, commit }, tableId) => {
return new Promise((resolve, reject) => {
show({ id: tableId }).then(res => {
@ -113,6 +218,24 @@ const actions = {
});
});
},
deleteField: ({ state, commit, dispatch }) => {
if (state.selectedForm?.id) {
return new Promise((resolve, reject) => {
destroy({ id: state.selectedForm.id }).then(res => {
resolve(res)
commit('CLEAR_SELECTED')
commit('CLEAR_SELECTED_INDEX')
}).catch(err => {
reject(err)
})
})
} else {
return new Promise((resolve, reject) => {
state.formList.splice(state.selectedIndex, 1);
resolve(false)
})
}
}
};
export default {

@ -47,3 +47,22 @@
.el-range-separator {
box-sizing: content-box;
}
.el-dialog {
background-color: #fff;
border: 0;
border-radius: 6px;
background-clip: padding-box;
box-shadow: 0 4px 12px rgba(0, 0, 0, .15);
&__header {
border-bottom: 1px solid #e8eaec;
padding: 14px 16px;
line-height: 1;
}
&__footer {
border-top: 1px solid #e8eaec;
padding: 12px 18px;
text-align: right;
}
}

@ -229,7 +229,7 @@
>.el-menu--popup {
max-height: 100vh;
overflow-y: auto;
background: #0077CC !important;
background: $primaryColor !important;
&::-webkit-scrollbar-track-piece {
background: #d3dce6;

@ -1,15 +1,14 @@
import Cookies from 'js-cookie'
const TokenKey = 'starter_token'
import { TOKEN_KEY } from '@/settings'
export function getToken() {
return Cookies.get(TokenKey)
return Cookies.get(TOKEN_KEY)
}
export function setToken(token) {
return Cookies.set(TokenKey, token)
return Cookies.set(TOKEN_KEY, token)
}
export function removeToken() {
return Cookies.remove(TokenKey)
return Cookies.remove(TOKEN_KEY)
}

@ -0,0 +1,242 @@
import { show } from "@/api/system/customForm";
import { listCommondepartment, listCommonuser } from "@/api/common";
import { primaryColor } from "@/styles/variables.scss"
import { download } from "@/utils/downloadRequest";
function down (url) {
download(url)
}
function preview (url) {
let codeUri = `${process.env.VUE_APP_PREVIEW_API}?url=${encodeURIComponent(
new Buffer(url).toString("base64")
)}`
window.open(codeUri,'_blank')
}
const baseTable = new Map([
['departments', async () => {
return (await listCommondepartment())
}],
['admins',async () => {
return (await listCommonuser())
}]
])
export async function getForm (customFormId) {
let selectItemMap = new Map();
if (!customFormId) {
console.warn("customFormId is required!")
return
}
const res = await show({ id: customFormId }, false);
const { fields, relation } = res;
let fieldRes = fields.sort((a,b) => a.sort - b.sort);
if (
!fields ||
!relation ||
!fields instanceof Array ||
!relation instanceof Array
) {
throw new Error("fields或relation参数错误");
}
fieldRes?.forEach((i, index) => {
i._relations = relation.find((j) => j.custom_form_field === i.field);
if (i.select_item && typeof i.select_item === 'object') {
let keys = Object.keys(i.select_item)
if (keys.length > 0) {
i._params = keys.map((key) => {
return {
key,
value: /^\d*$/.test(i.select_item[key])
? Number(i.select_item[key])
: i.select_item[key],
};
});
selectItemMap.set(i.field, i._params);
//有select,radio
i.edit_input = 'radio'
}
}
})
return { fieldRes, selectItemMap };
}
export function getRenderTable (ctx, fields, replaces) {
const h = ctx.$createElement;
if (replaces && !(replaces instanceof Map)) {
throw new Error("replaces参数错误,需要Map类型");
}
return fields.map((field, index) => {
//自定义替换
if (replaces instanceof Map && replaces.get(field.field)) {
return replaces.get(field.field)
}
//文件
if (field.edit_input === 'file' || field.edit_input === 'files') {
let renderFn = () => {}
const { link_relation, foreign_key, link_with_name } = field._relations;
if (link_relation === 'hasOne' || link_relation === 'newHasOne') {
renderFn = row => {
if (!row[link_with_name]?.url) {
return ''
}
return (
<div style="display: flex;align-items: center;">
{
['jpg','jpeg','png','gif','svg','webp','bmp'].indexOf(row[link_with_name]?.extension) === -1 ?
(<el-link
type="primary"
download={row[link_with_name]?.original_name}
>
{row[link_with_name]?.original_name}
</el-link>) : (<el-image fit="contain" style="max-width: 80px;max-height: 60px;" src={row[link_with_name]?.url} alt={row[link_with_name]?.original_name} preview-src-list={[row[link_with_name]?.url]}></el-image>)
}
<Icon type="md-cloud-download"
style="margin-left: 10px;cursor: pointer;font-size: 17px;"
color={primaryColor}
on={{
['click']: _ => down(row[link_with_name]?.url)
}}/>
<Icon type="md-eye"
style="margin-left: 4px;cursor: pointer;font-size: 17px;"
color={primaryColor}
on={{
['click']: _ => preview(row[link_with_name]?.url)
}}/>
</div>
)
}
} else {
renderFn = row => (
<div style="display: flex;flex-direction: column;align-items: flex-start;">
{row[link_with_name]?.map((o,oi) => (
<div style="display: flex;align-items: center;">
{
['jpg','jpeg','png','gif','svg','webp','bmp'].indexOf(o?.extension) === -1 ?
(<el-link type="primary" download={o?.original_name} href={o?.url}>
{oi+1}. { o?.original_name || o?.name }
</el-link>) : (<el-image fit="contain" style="max-width: 80px;" src={o?.url} alt={o?.original_name} preview-src-list={[o?.url]}></el-image>)
}
<Icon type="md-cloud-download"
style="margin-left: 10px;cursor: pointer;font-size: 17px;"
color={primaryColor}
on={{
['click']: _ => down(o?.url)
}}/>
<Icon type="md-eye"
style="margin-left: 4px;cursor: pointer;font-size: 17px;"
color={primaryColor}
on={{
['click']: _ => preview(o?.url)
}}/>
</div>
))}
</div>
)
}
return {
prop: field.field,
label: field.name,
width: field.width,
align: "left",
showOverflowTooltip: false,
customFn: row => renderFn(row)
}
}
//关联
if (field._relations && typeof field._relations === 'object') {
let renderFn = () => {}
const { link_relation, foreign_key, link_with_name } = field._relations;
if (link_relation === 'hasOne' || link_relation === 'newHasOne') {
renderFn = row => (
<span>
{row[link_with_name]?.name ||
row[link_with_name]?.title ||
row[link_with_name]?.no ||
row[link_with_name]?.value ||
row[link_with_name]?.biaoti ||
row[link_with_name]?.mingcheng}
</span>
)
}
if (link_relation === 'hasMany' || link_relation === 'newHasMany') {
renderFn = row => (
<div>
{row[link_with_name]?.map((o) => (
<p>
{o?.name ||
o?.title ||
o?.no ||
o?.value ||
o?.biaoti ||
o?.mingcheng}
</p>
))}
</div>
)
}
return {
prop: field.field,
label: field.name,
width: field.width,
customFn: row => renderFn(row),
fixed: field.is_fixed
}
}
//富文本
if (field.edit_input === 'richtext') {
return {
prop: field.field,
label: field.name,
width: field.width,
showOverflowTooltip: false,
customFn: row => (
<el-popover placement="bottom" trigger="click" width={row[field.field] ? 400 : 100}>
{
row[field.field] ? <div slot="default" style="width: 100%;max-height: 200px;overflow: scroll;" domPropsInnerHTML={row[field.field]}></div> : <div slot='default' style='text-align: center'></div>
}
<el-link type="primary" slot="reference">查看</el-link>
</el-popover>
),
fixed: field.is_fixed
}
}
//select内容
if (
field._params && field._params instanceof Array
) {
return {
prop: field.field,
label: field.name,
width: field.width,
customFn: row => (
<span>{ field._params.find(param => param.value == row[field.field])?.key }</span>
),
fixed: field.is_fixed
}
}
return {
prop: field.field,
label: field.name,
width: field.width,
fixed: field.is_fixed
}
})
}

@ -37,7 +37,7 @@
<template v-if="item.edit_input === 'richtext'">
<div v-html="detail[item.field]"></div>
</template>
<template>
<template v-else>
{{ contentFormat(item) }}
</template>
</el-descriptions-item
@ -102,7 +102,7 @@ export default {
},
methods: {
open(url) {
this.codeUri = `http://view.ali251.langye.net:8012/onlinePreview?url=${encodeURIComponent(
this.codeUri = `${process.env.VUE_APP_PREVIEW_API}?url=${encodeURIComponent(
new Buffer(url).toString("base64")
)}`;
@ -148,13 +148,21 @@ export default {
Promise.all(promiseAll).then(res => {
if (item.edit_input !== 'files') {
let dataTable = this.allTables.find(t => t.table_name === res[1].relation[0].link_table_name);
formShow({ id: dataTable.id }).then(res1 => {
if (dataTable) {
formShow({ id: dataTable?.id }).then(res1 => {
this.linkTableList.push({
value: res[0].data?.map(o => o[res[1]?.relation[0]?.link_with_name]),
field: this.formatColumn(res1),
title: res[1]?.name
})
})
} else {
this.linkTableList.push({
value: res[0].data?.map(o => o[res[1]?.relation[0]?.link_with_name]),
field: this.formatColumn(res1),
value: this.detail[item?._relations?.link_with_name],
field: this.formatColumn(res[1]),
title: res[1]?.name
})
})
}
} else {
this.linkTableList.push({
value: res[0].data?.map(o => o[res[1]?.relation[0]?.link_with_name]),

@ -34,195 +34,208 @@ export default {
},
[
h(
"el-form",
"el-scrollbar",
{
ref: "elForm",
props: {
model: this.form,
labelWidth: "80px",
rules: this.rules,
labelPosition: "right",
size: "small",
style: {
height: "58vh",
},
},
(() => {
let dom = [];
this.formInfo
.filter((i) => i.form_show)
.forEach((i, index) => {
dom.push(
h(
"el-form-item",
{
ref: `elFormItem${i.field}`,
style: {
width: "100%",
},
props: {
label: i.name,
prop: i.field,
required:
i.validation instanceof Array
? !!i.validation.find((i) => i === "required")
: false,
},
},
this.$scopedSlots[i.field]
? this.$scopedSlots[i.field]({
fieldInfo: i,
form: this.form,
file: this.file,
})
: (i._relations && i.edit_input !== 'file' && i.edit_input !== 'files')
? [
h(
"el-input",
{
props: {
readonly: true,
value:
i._relations.link_relation ===
"newHasOne" ||
i._relations.link_relation === "hasOne"
? this.originalForm[
i._relations.link_with_name
]?.name ||
this.originalForm[
i._relations.link_with_name
]?.mingcheng ||
this.originalForm[
i._relations.link_with_name
]?.no ||
this.originalForm[
i._relations.link_with_name
]?.id
: this.originalForm[
i._relations.link_with_name
]
?.map(
(j) =>
j[i._relations.custom_form_field]
)
?.toString(),
},
on: {
// ['focus']:e => {
// this.$refs['linkPickModal'].show()
// }
},
},
[
h("el-button", {
props: {
icon: "el-icon-arrow-right",
},
slot: "append",
on: {
click: (e) => {
this.pickedLinkField.field = i.field;
this.pickedLinkField.linkType =
i._relations.link_relation;
this.pickedLinkField.linkTableName =
i._relations.link_table_name;
this.pickedLinkField.originalRows =
this.originalForm[
i._relations.link_with_name
];
this.$refs["linkPickModal"].show();
[
h(
"el-form",
{
ref: "elForm",
class: "form-body",
props: {
model: this.form,
labelWidth: "80px",
rules: this.rules,
labelPosition: "right",
size: "small",
},
},
(() => {
let dom = [];
this.formInfo
.filter((i) => i.form_show)
.forEach((i, index) => {
dom.push(
h(
"el-form-item",
{
ref: `elFormItem${i.field}`,
style: {
width: "100%",
},
props: {
label: i.name,
prop: i.field,
required:
i.validation instanceof Array
? !!i.validation.find((i) => i === "required")
: false,
},
},
this.$scopedSlots[i.field]
? this.$scopedSlots[i.field]({
fieldInfo: i,
form: this.form,
file: this.file,
})
: i._relations &&
i.edit_input !== "file" &&
i.edit_input !== "files"
? [
h(
"el-input",
{
props: {
readonly: true,
value:
(this.pickModalText[i.field]) || (i._relations.link_relation ===
"newHasOne" ||
i._relations.link_relation === "hasOne"
? this.originalForm[
i._relations.link_with_name
]?.name ||
this.originalForm[
i._relations.link_with_name
]?.mingcheng ||
this.originalForm[
i._relations.link_with_name
]?.no ||
this.originalForm[
i._relations.link_with_name
]?.id || this.form[i.field]
: this.originalForm[
i._relations.link_with_name
]
?.map(
(j) =>
j[
i._relations
.custom_form_field
]
)
?.toString()),
},
},
}),
on: {
['focus']:e => {
this.pickedLinkField.field = i.field;
this.pickedLinkField.linkType =
i._relations.link_relation;
this.pickedLinkField.linkTableName =
i._relations.link_table_name;
this.pickedLinkField.originalRows =
this.originalForm[
i._relations.link_with_name
];
this.$refs["linkPickModal"].show();
}
},
}
),
]
),
]
: [
h(
domMap.get(i.edit_input),
{
ref: `elEdit_${i.field}`,
style: {
width: "100%",
},
props: {
...addPropsMap.get(i.edit_input),
...this.extraProps(i),
placeholder: i.help,
value: this.form[i.field],
},
attrs: {
placeholder: i.help || `请填写${i.name}`,
},
on: {
[this.getEventType(i.edit_input)]: (e) => {
if (i.field) {
this.form[i.field] = e;
this.form = Object.assign({}, this.form);
}
},
},
scopedSlots:
i.edit_input === "file" ||
i.edit_input === "files"
? {
file: (scope) => {
let { file } = scope;
return [
h("div", {}, [
h("i", {
class: {
"el-icon-circle-check":
file.status === "success",
"el-icon-loading":
file.status === "uploading",
},
style: {
color:
file.status === "success"
? "green"
: "",
},
}),
h(
"a",
{
attrs: {
href: file.url,
download: file.name,
},
: [
h(
domMap.get(i.edit_input),
{
ref: `elEdit_${i.field}`,
style: {
width: "100%",
},
props: {
...addPropsMap.get(i.edit_input),
...this.extraProps(i),
placeholder: i.help,
value: this.form[i.field],
},
attrs: {
placeholder: i.help || `请填写${i.name}`,
},
on: {
[this.getEventType(i.edit_input)]: (
e
) => {
if (i.field) {
this.form[i.field] = e;
this.form = Object.assign(
{},
this.form
);
}
},
},
scopedSlots:
i.edit_input === "file" ||
i.edit_input === "files"
? {
file: (scope) => {
let { file } = scope;
return [
h("div", {}, [
h("i", {
class: {
"uploaded-a":
file.status === "success",
"el-icon-circle-check":
file.status ===
"success",
"el-icon-loading":
file.status ===
"uploading",
},
style: {
padding: "0 4px",
color:
file.status ===
"success"
? "green"
: "",
},
}),
h(
"a",
{
attrs: {
href: file.url,
download: file.name,
},
class: {
"uploaded-a":
file.status ===
"success",
},
style: {
padding: "0 4px",
},
},
file.name
),
]),
h("i", {
class: "el-icon-close",
on: {
["click"]: () =>
this.fileRemoveHandler(
file,
i.field
),
},
file.name
),
]),
h("i", {
class: "el-icon-close",
on: {
["click"]: () =>
this.fileRemoveHandler(
file,
i.field
),
},
}),
];
},
}
: "",
},
this.optionsRender(h, i)
),
]
)
);
});
return dom;
})()
}),
];
},
}
: "",
},
this.optionsRender(h, i)
),
]
)
);
});
return dom;
})()
),
]
),
h("template", { slot: "footer" }, [
h(
@ -271,8 +284,9 @@ export default {
originalRows: this.pickedLinkField.originalRows,
},
on: {
["confirm"]: ({ field, value }) => {
["confirm"]: ({ field, value, text }) => {
this.form[field] = value;
this.pickModalText[field] = text;
},
},
}),
@ -294,6 +308,7 @@ export default {
field: "",
originalRows: [],
},
pickModalText: {}
};
},
methods: {
@ -314,16 +329,16 @@ export default {
if (info.edit_input === "checkbox" || info.edit_input === "radio") {
return info._params && info._params instanceof Array
? info._params.map((i) =>
h("el-option", {
props: {
label:
i.key || i.value || i.name || i.no || i.mingcheng || i.id,
value: info._relations
? i[info._relations.foreign_key]
: i.value,
},
})
)
h("el-option", {
props: {
label:
i.key || i.value || i.name || i.no || i.mingcheng || i.id,
value: info._relations
? i[info._relations.foreign_key]
: i.value,
},
})
)
: [];
}
if (info.edit_input === "file" || info.edit_input === "files") {
@ -443,21 +458,21 @@ export default {
if (i && (i.edit_input === "file" || i.edit_input === "files")) {
res[i._relations.link_with_name]
? (this.file[i.field] =
res[i._relations.link_with_name] instanceof Array
? res[i._relations.link_with_name].map((i) => {
return {
name: i?.original_name,
url: i?.url,
response: i,
};
})
: [
{
name: res[i._relations.link_with_name]?.original_name,
url: res[i._relations.link_with_name]?.url,
response: res[i._relations.link_with_name],
},
])
res[i._relations.link_with_name] instanceof Array
? res[i._relations.link_with_name].map((i) => {
return {
name: i?.original_name,
url: i?.url,
response: i,
};
})
: [
{
name: res[i._relations.link_with_name]?.original_name,
url: res[i._relations.link_with_name]?.url,
response: res[i._relations.link_with_name],
},
])
: (this.file[i.field] = []);
return
@ -515,10 +530,10 @@ export default {
if (info.edit_input === "files") {
copyForm[info._relations.link_with_name] = this.file[
info.field
]?.map((i) => {
]?.map((i) => {
return {
upload_id: i?.response?.id,
original_name: i?.response?.original_name
...i?.response
};
});
} else {
@ -526,7 +541,7 @@ export default {
info.field
] instanceof Array ? copyForm[
info.field
]?.map((i) => {
]?.map((i) => {
return {
[info._relations.custom_form_field]: i,
//...copyRelation,
@ -606,12 +621,29 @@ export default {
this.form[i.field] = "";
if (
i.validation instanceof Array &&
i.validation.length > 0 &&
!!i.validation.find((i) => i === "required")
i.validation.length > 0
) {
this.rules[i.field] = [
{ required: true, message: `请填写${i.name}` },
];
this.rules[i.field] = []
i.validation.forEach((j) => {
if (j === "required") {
this.rules[i.field].push({ required: true, message: `请填写${i.name}` })
} else {
this.rules[i.field].push({
validator: (rule, value, callback) => {
if (value === '') {
callback()
return
}
if (validation.get(j).test(value)) {
callback()
} else {
callback(new Error(`${i.name}验证不通过`))
}
},
trigger: 'blur'
})
}
})
}
if (i.edit_input === "files") {
this.form[i.field] = [];
@ -626,7 +658,7 @@ export default {
});
document.documentElement.style.setProperty(
"--column-num",
Math.floor(newVal.length / 8).toString()
newVal.length > 8 ? "2" : "1"
);
},
//immediate: true,
@ -664,4 +696,9 @@ export default {
color: red;
text-decoration: underline;
}
.form-body {
display: grid;
grid-gap: 10px;
grid-template-columns: repeat(var(--column-num), 1fr);
}
</style>

@ -9,8 +9,8 @@
placeholder="搜索条目"
>
<Option v-for="item in fields" :key="item.id" :value="item.field">{{
item.name
}}</Option>
item.name
}}</Option>
</Select>
<Select
v-model="select.filter[0].op"
@ -18,8 +18,8 @@
placeholder="搜索条件"
>
<Option v-for="item in op" :key="item.value" :value="item.value">{{
item.label
}}</Option>
item.label
}}</Option>
</Select>
<template v-if="select.filter[0].op !== 'range'">
<Input
@ -37,7 +37,7 @@
@input="(e) => inputStartHandler(e, select.filter[0])"
/>
<span style="margin-left: 10px; display: flex; align-items: center"
></span
></span
>
<Input
:value="select.filter[0].value.split(',')[1]"
@ -50,7 +50,7 @@
style="margin-left: 10px"
type="primary"
@click="$refs['table'].getTableData(true)"
>查询</Button
>查询</Button
>
</div>
<xy-table
@ -70,10 +70,10 @@
<template #footer>
<span>
<el-button size="mini" @click="dialogVisible = false"
> </el-button
> </el-button
>
<el-button size="mini" type="primary" @click="confirm"
> </el-button
> </el-button
>
</span>
</template>
@ -92,7 +92,7 @@ export default {
field: String,
originalRows: {
default: () => [],
type: Array,
type: [Array,Object],
},
},
data() {
@ -249,18 +249,19 @@ export default {
confirm() {
this.linkType === "hasMany" || this.linkType === "newHasMany"
? this.$emit("confirm", {
field: this.field,
value: Array.from(
new Set([
...this.$refs["table"].getSelection()?.map((i) => i.id),
...this.originalRowIds,
])
),
})
field: this.field,
value: Array.from(
new Set([
...this.$refs["table"].getSelection()?.map((i) => i.id),
...this.originalRowIds,
])
),
})
: this.$emit("confirm", {
field: this.field,
value: this.tempRow.id,
});
field: this.field,
value: this.tempRow.id,
text: this.tempRow.name || this.tempRow.value || this.tempRow.mingcheng || this.tempRow.no || this.tempRow.id
});
this.dialogVisible = false;
},
},

@ -22,7 +22,7 @@
v-for="item in form"
:key="item.id"
:value="item.field"
>{{ item.name }}</Option
>{{ item.name }}</Option
>
</Select>
<Select
@ -34,7 +34,7 @@
v-for="item in op"
:key="item.value"
:value="item.value"
>{{ item.label }}</Option
>{{ item.label }}</Option
>
</Select>
<template
@ -64,7 +64,7 @@
v-for="item in getColumnParams(select.filter[0].key)"
:key="item.id"
:value="getColumnField(select.filter[0].key)._relations ? item[getColumnField(select.filter[0].key)._relations.foreign_key] : item.value"
>{{
>{{
item.key || item.value || item.name || item.no || item.mingcheng || item.id
}}</Option
>
@ -83,7 +83,7 @@
display: flex;
align-items: center;
"
></span
></span
>
<Input
:value="select.filter[0].value.split(',')[1]"
@ -96,7 +96,7 @@
style="margin-left: 10px"
type="primary"
@click="$refs['xyTable'].getTableData(true)"
>查询</Button
>查询</Button
>
<xy-selectors
@ -121,7 +121,7 @@
v-for="item in form"
:key="item.id"
:value="item.field"
>{{ item.name }}</Option
>{{ item.name }}</Option
>
</Select>
<Select
@ -133,7 +133,7 @@
v-for="item in op"
:key="item.value"
:value="item.value"
>{{ item.label }}</Option
>{{ item.label }}</Option
>
</Select>
<template
@ -161,7 +161,7 @@
v-for="item in getColumnParams(item.key)"
:key="item.id"
:value="getColumnField(item.key)._relations ? item[getColumnField(item.key)._relations.foreign_key] : item.value"
>{{
>{{
item.key || item.value || item.name || item.no || item.mingcheng || item.id
}}</Option
>
@ -215,19 +215,19 @@
@click="
$refs['dialog'].setType('add'), $refs['dialog'].show()
"
>新增</Button
>新增</Button
>
</template>
<template #import>
<Button type="primary" @click="$refs['imports'].show()"
>导入</Button
>导入</Button
>
</template>
<template #export>
<Button
type="primary"
@click="exportExcel(new Date().getTime().toString())"
>导出</Button
>导出</Button
>
</template>
</header-content>
@ -235,8 +235,8 @@
</LxHeader>
</div>
</div>
<!--$refs['drawer'].setId(row.id);
$refs['drawer'].show();-->
<!--$refs['drawer'].setId(row.id);
$refs['drawer'].show();-->
<xy-table
:auths="auths_auth_mixin"
:delay-req="true"
@ -244,7 +244,7 @@
ref="xyTable"
:border="true"
:action="index"
:req-opt="select"
:req-opt="tableSelect"
:destroy-req-opt="select"
:table-item="table"
@detail="
@ -295,7 +295,8 @@ import { getparameter } from "@/api/system/dictionary";
import { show } from "@/api/system/customForm";
import * as XLSX from "xlsx";
import { saveAs } from "file-saver";
import { listdept } from "@/api/system/department"
import { listCommondepartment } from "@/api/common";
import { getRenderTable, getForm } from "@/utils/table"
import dialoger from "./dialog.vue";
import LxHeader from "@/components/LxHeader/index.vue";
@ -327,6 +328,7 @@ export default {
},
],
},
selectQuery: [],
form: [],
table: [],
customForm: {
@ -400,170 +402,52 @@ export default {
console.warn(err);
}
}
const res = await show({ id: this.customForm.customFormId }, false);
//
//
let baseTable = new Map([
['departments', async () => {
const res = await listdept()
return res
}],
['admins',[]]
])
let { fields, relation } = res;
let fieldRes = fields.sort((a,b) => a.sort - b.sort)
if (
!fields ||
!relation ||
!fields instanceof Array ||
!relation instanceof Array
) {
throw new Error("fields或relation格式错误");
}
fieldRes?.forEach((i, index) => {
i._relations = relation.find((j) => j.custom_form_field === i.field);
if (i.select_item && typeof i.select_item === 'object') {
let keys = Object.keys(i.select_item)
i._params = keys.map(key => {
return {
key,
value: i.select_item[key]
}
})
}
if (i.edit_input === 'file' || i.edit_input === 'files') {
return
}
if (i._relations) {
if (baseTable.get(i._relations.link_table_name)) {
baseTable.get(i._relations.link_table_name)().then(res => i._params = res)
} else {
i._params = i._relations.parameter_id
? getparameter({ id: i._relations.parameter_id },false).then((res) => {
i._params = res.detail;
})
: this.index({
table_name: i._relations.link_table_name,
page: 1,
page_size: 9999,
}).then((res) => {
i._params = res.data;
});
}
if (this.$route.meta.params?.select) {
try {
this.selectQuery = JSON.parse(decodeURIComponent(this.$route.meta.params?.select));
} catch (err) {
console.warn(err);
}
});
this.form = fields;
console.log(111, this.form);
this.form
?.filter((i) => i.list_show)
.forEach((i) => {
if (i._relations) return
let linkOb = {};
}
if (i.edit_input === "richtext") {
linkOb.customFn = (row) => {
return (
<div
style={{ "max-height": "55px","overflow": "scroll" }}
domPropsInnerHTML={row[i.field]}
></div>
);
};
}
if (
i.select_item &&
typeof i.select_item === "object" &&
!(i.select_item instanceof Array)
) {
let keys = Object.keys(i.select_item);
linkOb.customFn = (row) => {
let paramMap = new Map();
keys.forEach((key) => {
paramMap.set(i.select_item[key], key);
});
const { fieldRes, selectItemMap } = await getForm(this.customForm.customFormId);
this.form = fieldRes;
this.table = getRenderTable(this, this.form);
},
return <span>{paramMap.get(row[i.field]?.toString())}</span>;
};
}
if (i._relations) {
let { link_relation, foreign_key, link_with_name } = i._relations;
if (link_relation === "newHasOne" || link_relation === "hasOne") {
linkOb.customFn = (row) => {
if (i.edit_input === "file") {
return (
<a
download={row[link_with_name]?.original_name}
href={row[link_with_name]?.url}
>
{row[link_with_name]?.original_name}
</a>
);
} else {
return (
<span>
{row[link_with_name]?.name ||
row[link_with_name]?.no ||
row[link_with_name]?.value}
</span>
);
}
};
adjustAlignment () {
if (this.firstAdjustTable) {
const data = this.$refs['xyTable'].getListData();
if (data.length < 2) return;
try {
this.form.filter(i => i.list_show).forEach((i) => {
let maxLength = -Infinity;
let minLength = Infinity;
let numberLength = 0;
let temp = 0;
while (temp < data.length) {
maxLength = Math.max(maxLength, data[temp][i.field]?.length??0);
minLength = Math.min(minLength, data[temp][i.field]?.length??0);
numberLength += /^-?[0-9]+(\.[0-9]+)?$/.test(data[temp][i.field]) ? 1 : 0;
temp++;
}
if (link_relation === "hasMany" || link_relation === "newHasMany") {
linkOb.customFn = (row) => {
if (i.edit_input === "files") {
return (
<div style="display: flex;flex-direction: column;">
{row[link_with_name]?.map((o) => (
<a>
{ o?.original_name || o?.name }
</a>
))}
</div>
)
} else {
return (
<div>
{row[link_with_name]?.map((o) => (
<p>
{o?.name ||
o?.no ||
o?.value ||
o?.biaoti ||
o?.mingcheng}
</p>
))}
</div>
);
}
};
if (numberLength === temp) {
this.table.find(a => a.prop === i.field).align = 'right';
}
}
let alignLeft = []
this.table.push(
Object.assign(
{
prop: i.field,
label: i.name,
width: i.width,
align: alignLeft.find(m => m === i.field) ? 'left' : 'center',
fixed: i.is_fixed,
},
linkOb
)
);
});
this.table.unshift({
type: "index",
width: 60,
label: "序号",
});
},
else if (Math.abs(maxLength - minLength) > 4) {
this.table.find(a => a.prop === i.field).align = 'left';
}
})
console.log(this.table)
} catch (e) {
console.error(e)
}
this.$nextTick(() => {
this.$refs['xyTable'].doLayout();
this.firstAdjustTable = false;
})
}
}
},
computed: {
@ -587,6 +471,14 @@ export default {
? this.form.find((i) => i.field === field)._params
: [];
};
},
tableSelect () {
let filter = [...this.select.filter,...this.selectQuery]
return {
...this.select,
filter
}
}
},
created() {
@ -619,15 +511,4 @@ export default {
padding: 0 10px;
}
}
a {
color: red;
text-decoration: none;
transition: all 0.2s;
}
a:hover {
color: red;
text-decoration: underline;
}
</style>

@ -139,15 +139,7 @@
<el-button
type="primary"
size="mini"
@click="
$store.commit('form/SPLICE_FORM_LIST', {
index: selectedIndex,
length: 1,
}),
$store.commit('form/CLEAR_SELECTED_INDEX'),
$store.commit('form/CLEAR_SELECTED'),
$refs['el-popover'].doClose()
"
@click="destroyField"
>确定</el-button
>
</div>
@ -236,6 +228,10 @@ export default {
this.$store.commit("form/CLEAR_SELECTED");
this.$store.commit("form/CLEAR_SELECTED_INDEX");
},
destroyField () {
this.$store.dispatch('form/deleteField').then((res) => res ? this.$emit('refresh') : '')
}
},
computed: {
...mapState("form", ["selectedForm", "formList", "selectedIndex"]),

@ -9,6 +9,14 @@
<template #title>
<div class="btns">
<span class="title">{{ custom_form.name }}</span>
<el-button
size="small"
type="primary"
icon="el-icon-download"
circle
title="生成下载表格模板"
@click="submitUpload"
></el-button>
<el-button
size="small"
type="primary"
@ -39,7 +47,7 @@
<draggable
v-model="types"
:sort="false"
:group="{ name: 'items', pull: 'clone' }"
:group="{ name: 'items', pull: 'clone', put: false }"
>
<div class="type-item" v-for="item in types">
{{ item.name }}
@ -101,7 +109,7 @@
</div>
</template>
<template #right>
<editPane :rules="rules" :types="types"></editPane>
<editPane :rules="rules" :types="types" @refresh="$store.dispatch('form/getFormList', custom_form_id)"></editPane>
</template>
</Split>
</template>
@ -233,11 +241,32 @@ export default {
}
},
submitUpload () {
this.$store.dispatch("form/submitUpload",this.custom_form_id).then((res) => {
setTimeout(() => {
update({ id: this.custom_form_id })
.then((res) => {
this.$message({
type: "success",
message: "数据库同步成功",
});
})
.catch((err) => {
this.$message({
type: "error",
message: "数据库同步失败,请手动同步",
});
});
}, 2000);
});
},
submit() {
this.$store.dispatch("form/submit",this.custom_form_id).then((res) => {
setTimeout(() => {
update({ id: this.custom_form_id })
.then((res) => {
this.$store.dispatch("form/getFormList", this.custom_form_id);
this.$message({
type: "success",
message: "数据库同步成功",

@ -1,29 +1,29 @@
<template>
<div>
<el-dialog title="关联" :visible.sync="dialogVisible" width="66%">
<el-drawer direction="rtl"
title="关联"
:visible.sync="dialogVisible"
size="58%"
:before-close="(done) => {
$confirm('确认关闭?').then(_ => { done() });
}">
<template>
<el-button size="small" type="primary" icon="el-icon-plus" @click="list.push({ link_table_name: '',local_key: '',foreign_key: '',link_relation: '' })"></el-button>
<div style="padding: 20px;">
<el-button size="small" type="primary" icon="el-icon-plus" @click="list.push({ link_table_name: '',local_key: '',foreign_key: '',link_relation: '' })"></el-button>
<xy-table
style="margin-top: 10px;"
:auths="[]"
size="small"
:is-page="false"
:list="list"
:table-item="table"
>
</xy-table>
</template>
<template #footer>
<span class="dialog-footer">
<el-button @click="dialogVisible = false"> </el-button>
<el-button type="primary" @click="dialogVisible = false"
> </el-button
<xy-table
style="margin-top: 10px;"
:auths="[]"
size="small"
:is-page="false"
:list="list"
:table-item="table"
>
</span>
</xy-table>
</div>
</template>
</el-dialog>
</el-drawer>
</div>
</template>
@ -197,6 +197,7 @@ export default {
{
prop: 'operate',
label: '操作',
width: 180,
align: 'left',
customFn:(row, scope) => {
return [(

@ -1,6 +1,6 @@
<template>
<div class="container">
<!-- 查询配置 -->
<!-- 查询配置 -->
<div style="padding: 0px 20px">
<div ref="lxHeader">
<LxHeader icon="md-apps" style="margin-bottom: 10px; border: 0px; margin-top: 15px" text="权限管理">
@ -44,8 +44,8 @@
{{ data.name }}
</div>
<div class="action-item">
<el-checkbox v-for="(item, index) in data.auth_node_tags_array" :key="index"
v-model="item.checked" @change="()=>{}"
<el-checkbox v-for="(item, index) in data.auth_node_tags_array" :key="data.name+item.id"
v-model="item.checked" @change="()=>{tree = Object.assign([], tree)}"
>
{{ item.name }}
</el-checkbox>
@ -116,10 +116,10 @@ export default {
for (let mod of response) {
mod.rowid = mod.id.toString()
console.log(mod)
if (cur == 0) {
that.activeRole = mod.rowid
that.loadPermisstions(0, that.activeRole)
that.togglePermission(0, that.activeRole)
//TODO: that.loadPermisstions(0, that.activeRole)
}
cur++
}
@ -137,7 +137,7 @@ export default {
let children = tree.children
children.forEach((menu, index3) => {
menu.auth_node_tags_array.map((m, index4) => {
menu.auth_node_tags_array.forEach((m, index4) => {
m.checked = false
that.$forceUpdate()
@ -149,7 +149,35 @@ export default {
})
},
roleChange(tab, event) {
this.loadPermisstions(parseInt(tab.index), tab.name)
this.togglePermission(parseInt(tab.index), tab.name)
// TODO: this.loadPermisstions(parseInt(tab.index), tab.name)
},
togglePermission (index, name) {
let select = this.rolelist[index].permissions;
this.$refs.tree.setCheckedKeys([]);
this.activeRole = name;
this.$refs["tree"].setCheckedKeys(select.map(item => item.id));
const toggleAuth = (arr, findId, selectItem) => {
for (let i of arr) {
if (i.id === findId) {
console.log(i)
if (i.auth_node_tags) {
i.auth_node_tags_array.forEach(item => {
this.$set(item, "checked", selectItem.has_auth_node_tags.indexOf(item.tag) > -1);
})
}
} else {
if (i.children && i.children.length > 0) {
toggleAuth(i.children, findId, selectItem)
}
}
}
}
select.filter(i => i.auth_node_tags && i.auth_node_tags.length > 0).forEach(i => {
toggleAuth(this.tree, i.id, i)
})
this.tree = Object.assign([], this.tree)
},
loadPermisstions(index, name) {
let select = this.rolelist[index].permissions
@ -157,13 +185,27 @@ export default {
this.activeRole = name
let that = this
const resolveChildren = (arr) => {
let temp = [];
if (arr.children && arr.children.length > 0) {
arr.children.forEach((child) => {
temp.push(child)
resolveChildren(child)
})
}
return temp;
}
this.tree.forEach((tree, index1) => {
let children = tree.children
if (tree.auth_node_tags) {
tree.auth_node_tags_array.forEach((auth) => {
this.$set(auth, "checked", true)
})
}
let children = resolveChildren(tree)
select.forEach((item, index2) => {
let selectMenu = children.filter(m => {
return m.id == item.id
})
selectMenu.forEach((menu, index3) => {
if (item.has_auth_node_tags.length > 0) {
menu.auth_node_tags_array.forEach((m, index4) => {
@ -226,6 +268,10 @@ export default {
</script>
<style lang="less" scoped>
::v-deep .el-tree-node__content {
align-items: flex-start;
height: auto;
}
.t-tree {
position: absolute;
width: 100%;
@ -279,7 +325,7 @@ export default {
.action-group {
width: 100%;
display: flex;
//display: flex;
}
.action-text {
@ -288,12 +334,13 @@ export default {
}
.action-item {
flex: 1;
display: flex;
flex-wrap: wrap;
}
.action-item > label {
width: 55px;
margin-left: 3px;
//width: 55px;
//margin-left: 3px;
}
.action-container >>> .el-tree-node {
@ -301,6 +348,11 @@ export default {
}
.action-container >>> .el-checkbox__label {
padding-left: 5px;
//padding-left: 5px;
}
</style>
<style>
.action-item > .el-checkbox .el-checkbox__inner {
border-radius: 100%;
}
</style>

@ -24,8 +24,8 @@ module.exports = {
* In most cases please use '/' !!!
* Detail: https://cli.vuejs.org/config/#publicpath
*/
publicPath: '/admin/',
outputDir: '/Users/liuxiangyu/Work/z-zhongjia/app/zhongjia-finance-service/public/admin',
publicPath: process.env.ENV === 'staging' ? '/admin_test' : '/admin',
outputDir: './dist',
assetsDir: 'static',
css: {
loaderOptions: { // 向 CSS 相关的 loader 传递选项

Loading…
Cancel
Save