master
xy 2 years ago
parent 54b0cbb3e4
commit e615d89494

@ -2,5 +2,5 @@
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_BASE_API=http://jiwei.ali251.langye.net
VUE_APP_UPLOAD_API=http://jiwei.ali251.langye.net/api/admin/upload-file

@ -2,5 +2,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_BASE_API = http://jiwei.ali251.langye.net
VUE_APP_UPLOAD_API =http://jiwei.ali251.langye.net/api/admin/upload-file

@ -4,6 +4,9 @@
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
<meta http-equiv="pragram" content="no-cache">
<meta http-equiv="cache-control" content="no-cache, no-store, must-revalidate">
<meta http-equiv="expires" content="0">
<link rel="icon" href="<%= BASE_URL %>favicon.ico">
<title><%= webpackConfig.name %></title>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 44 KiB

After

Width:  |  Height:  |  Size: 88 KiB

@ -31,7 +31,7 @@ export default {
},
};
</script>
<style lang="less" scoped>
<style lang="scss" scoped>
.v-header {
display: flex;
border-bottom: 1px solid #dcdee2;
@ -42,9 +42,9 @@ export default {
// padding-top: 10px;
font-weight: bold;
font-size: 15px;
color: #0077CC;
color: $primaryColor;
white-space: nowrap;
border-bottom: 2px solid #0077CC;
border-bottom: 2px solid $primaryColor;
> span {
position: relative;

@ -997,6 +997,8 @@ export default {
}
.xy-table__setting {
border-color: $primaryColor;
background: $primaryColor;
font-size: 14px;
position: absolute;

@ -36,8 +36,7 @@
transition: opacity 1.5s;
}
.sidebar-name-logo {
width: 120px;
height: 22px;
width: 144px;
}
.sidebarLogoFade-enter,

@ -8,7 +8,7 @@ import getPageTitle from '@/utils/get-page-title'
NProgress.configure({ showSpinner: false }) // NProgress Configuration
const whiteList = ['/login'] // no redirect whitelist
const whiteList = ['/login','/h5/login'] // no redirect whitelist
router.beforeEach(async(to, from, next) => {
// start progress bar
@ -18,12 +18,19 @@ router.beforeEach(async(to, from, next) => {
document.title = getPageTitle(to.meta.title)
// determine whether the user has logged in
const hasToken = getToken()
const hasToken = !!(getToken() && getToken() !== 'undefined' && getToken() !== 'null')
// if (whiteList.indexOf(to.path) !== -1) {
// // in the free login whitelist, go directly
// next()
// return
// }
if (hasToken) {
if (to.path === '/login') {
if (to.path === '/login' || to.path === '/h5/login') {
// if is logged in, redirect to the home page
next({ path: '/' })
let isH5 = to.path !== '/login'
next({ path: isH5 ? '/h5' : '/' })
NProgress.done()
} else {
// determine whether the user has obtained his permission roles through getInfo
@ -34,24 +41,25 @@ router.beforeEach(async(to, from, next) => {
try {
// get user info
// note: roles must be a object array! such as: ['admin'] or ,['developer','editor']
const { roles } = await store.dispatch('user/getInfo')
// generate accessible routes map based on roles
const accessRoutes = await store.dispatch('permission/generateRoutes', roles)
if (!/^\/h5.*/.test(to.path)) {
const { roles } = await store.dispatch('user/getInfo')
//console.log(accessRoutes)
// dynamically add accessible routes
router.addRoutes(accessRoutes)
// generate accessible routes map based on roles
const accessRoutes = await store.dispatch('permission/generateRoutes', roles)
// hack method to ensure that addRoutes is complete
// set the replace: true, so the navigation will not leave a history record
next({ ...to, replace: true })
//console.log(accessRoutes)
// dynamically add accessible routes
router.addRoutes(accessRoutes)
next({ ...to, replace: true })
} else {
next();
}
} catch (error) {
console.log(error)
// remove token and go to login page to re-login
await store.dispatch('user/resetToken')
Message.error(error || 'Has Error')
next(`/login?redirect=${to.path}`)
next(`${/^\/h5.*/.test(to.path) ? '/h5/login' : '/login'}?redirect=${to.path}`)
NProgress.done()
}
}
@ -64,7 +72,7 @@ router.beforeEach(async(to, from, next) => {
next()
} else {
// other pages that do not have permission to access are redirected to the login page.
next(`/login?redirect=${to.path}`)
next(`${/^\/h5.*/.test(to.path) ? '/h5/login' : '/login'}?redirect=${to.path}`)
NProgress.done()
}
}

@ -73,7 +73,28 @@ export const constantRoutes = [{
icon: 'dashboard'
}
}, ]
}
},
{
path: "/h5/index",
component: () => import("@/views/h5/index.vue"),
meta: {
title: "首页",
},
hidden: true
},
{
path: '/h5/login',
component:() => import("@/views/h5/login/login.vue"),
meta: {
title: "登录",
},
hidden: true
},
{
path: '/h5',
redirect: '/h5/index'
},
]

@ -47,3 +47,20 @@
.el-range-separator {
box-sizing: content-box;
}
//table padding
.v-table .el-table__body td {
padding: 4px 0!important;
}
.el-table .cell {
padding: 0 5px!important;
}
//el-lading color
.el-loading-spinner .path {
stroke: $primaryColor;
}
.el-loading-spinner .el-loading-text {
color: $primaryColor;
}

@ -1,8 +1,8 @@
@font-face {
font-family: "iconfont"; /* Project id 4052909 */
src: url('iconfont.woff2?t=1683361610626') format('woff2'),
url('iconfont.woff?t=1683361610626') format('woff'),
url('iconfont.ttf?t=1683361610626') format('truetype');
font-family: "iconfont"; /* Project id 4379961 */
src: url('iconfont.woff2?t=1702971718309') format('woff2'),
url('iconfont.woff?t=1702971718309') format('woff'),
url('iconfont.ttf?t=1702971718309') format('truetype');
}
.iconfont {
@ -13,107 +13,67 @@
-moz-osx-font-smoothing: grayscale;
}
.icon-jurassic_process-list:before {
content: "\e6c4";
.icon-zuzhibumen:before {
content: "\e68b";
}
.icon-biaodan:before {
content: "\e663";
.icon-report:before {
content: "\e622";
}
.icon-biaozhunhuaguizeguanli:before {
content: "\e60a";
.icon-zhuantishenhedan-lanmumingcheng:before {
content: "\e686";
}
.icon-a-zhidu6:before {
content: "\eb07";
.icon-bumen:before {
content: "\e651";
}
.icon-dat:before {
content: "\e691";
.icon-yusherenyuan:before {
content: "\e65c";
}
.icon-audio:before {
content: "\e692";
}
.icon-video:before {
content: "\e693";
}
.icon-zip:before {
content: "\e694";
}
.icon-image:before {
content: "\e695";
}
.icon-pdf:before {
content: "\e696";
}
.icon-ppt:before {
content: "\e697";
.icon-tongji:before {
content: "\e878";
}
.icon-21excel:before {
content: "\e698";
.icon-qingdankushoucang:before {
content: "\e62c";
}
.icon-21word:before {
content: "\e699";
.icon-qingdan:before {
content: "\e645";
}
.icon-21move:before {
content: "\e69a";
.icon-wj-mxjl:before {
content: "\e742";
}
.icon-21setting:before {
content: "\e69b";
}
.icon-21upload:before {
content: "\e69c";
}
.icon-21download:before {
content: "\e69d";
}
.icon-21cancel:before {
content: "\e69e";
}
.icon-21ok:before {
content: "\e69f";
}
.icon-21copy:before {
content: "\e6a0";
.icon-meiriqingdan:before {
content: "\e692";
}
.icon-21delete:before {
content: "\e6a1";
.icon-leixing:before {
content: "\e617";
}
.icon-21edit:before {
content: "\e6a2";
.icon-tongji1:before {
content: "\e680";
}
.icon-21new:before {
content: "\e6a3";
.icon-houtaiguanli-lanmuguanli:before {
content: "\e6d9";
}
.icon-21folder:before {
content: "\e6a4";
.icon-statistics-full:before {
content: "\e86b";
}
.icon-21mutil:before {
content: "\e6a5";
.icon-lanmu:before {
content: "\e649";
}
.icon-21file:before {
content: "\e6a6";
.icon-kelong:before {
content: "\e612";
}

Binary file not shown.

Binary file not shown.

Binary file not shown.

@ -96,7 +96,7 @@ div:focus {
}
.v-table .el-table__body td {
padding: 9px 0 !important;
//padding: 9px 0 !important;
}
.v-table .el-table__footer td {

@ -11,7 +11,7 @@
transition: width 0.28s;
width: $sideBarWidth !important;
//background-color: $menuBg;
background: linear-gradient(180deg, #0284cd, #0077CC);
background: linear-gradient(180deg, #f5453f, #af160f);
box-shadow: 1px 1px 15px 0px rgba(17, 76, 157, 0.2);
height: 100%;
position: fixed;
@ -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;

@ -13,7 +13,7 @@ $subMenuHover:rgba(242, 242, 242, .4);
$submenuActiveBg:rgba(242, 242, 242, .4);
$sideBarWidth: 210px;
$primaryColor: #0077CC;
$primaryColor: #c4312b;
// the :export directive is the magic sauce for webpack
// https://www.bluematador.com/blog/how-to-share-variables-between-js-and-sass
:export {

@ -1,4 +1,4 @@
@import '~view-design/src/styles/index.less';
// Here are the variables to cover, such as:
@primary-color: #0077CC;
@primary-color: #c4312b;

@ -1,15 +1,18 @@
import Cookies from 'js-cookie'
const TokenKey = 'ywybs_token'
const TokenKey_h5 = 'ywybs_token_h5'
export function getToken() {
return Cookies.get(TokenKey)
let flag = /\/h5.*/.test(window.location.href)
return Cookies.get(flag ? TokenKey_h5 : TokenKey)
}
export function setToken(token) {
return Cookies.set(TokenKey, token)
let flag = /\/h5.*/.test(window.location.href)
return Cookies.set(flag ? TokenKey_h5 : TokenKey, token)
}
export function removeToken() {
return Cookies.remove(TokenKey)
let flag = /\/h5.*/.test(window.location.href)
return Cookies.remove(flag ? TokenKey_h5 : TokenKey)
}

@ -0,0 +1,81 @@
import { show } from "@/api/system/customForm";
import { listdept } from "@/api/system/department";
import { getparameter } from "@/api/system/dictionary";
import { index as baseFormIndex } from "@/api/system/baseForm";
export async function resolveFormInfo(customFormId,filterType = 'table') {
const res = await show({ id: customFormId }, false);
//字段处理
//初始表白名单
let baseTable = new Map([
[
"departments",
async () => {
const res = await listdept();
return res;
},
],
["admins", []],
]);
let { fields, relation } = res;
let fieldRes = fields.filter(i => {
if (filterType === 'table') {
return i.list_show;
} else {
return i.form_show;
}
}).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: /^\d*$/.test(i.select_item[key])
? Number(i.select_item[key])
: 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;
}
)
: baseFormIndex({
table_name: i._relations.link_table_name,
page: 1,
page_size: 9999,
}).then((res) => {
i._params = res.data;
});
}
}
});
return fieldRes;
}

@ -171,3 +171,20 @@ export function debounce(func, delay) {
}
}
/**
*对象数组去重
*@param { array<obj> } arr
*@param { string } prop
*@return array<obj>
**/
export function deWeightArrObj (arr, prop = 'id') {
if (arr && (arr instanceof Array) && (typeof prop === 'string')) {
let map = new Map();
for (let item of arr) {
if (!map.has(item[prop])) {
map.set(item[prop], item);
}
}
return [...map.values()];
}
}

@ -61,7 +61,7 @@ service.interceptors.response.use(
*/
response => {
if(loading){
loading?.close()
loading.close()
}
const res = response.data

@ -93,22 +93,22 @@ export default {
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.form[i.field]
: this.originalForm[
this.pickedLinkField.text[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(
@ -118,7 +118,7 @@ export default {
.custom_form_field
]
)
?.toString(),
?.toString())),
},
on: {
['focus']:e => {
@ -284,8 +284,12 @@ export default {
originalRows: this.pickedLinkField.originalRows,
},
on: {
["confirm"]: ({ field, value }) => {
this.form[field] = value;
["confirm"]: ({ field, value, text }) => {
this.$set(this.form,field,value);
//this.form[field] = value;
this.$set(this.pickedLinkField.text,field,text || "")
//this.pickedLinkField.text[field] = text || "";
console.log(this.form)
},
},
}),
@ -306,6 +310,7 @@ export default {
linkTableName: "",
field: "",
originalRows: [],
text: {}
},
};
},
@ -650,6 +655,7 @@ export default {
this.$nextTick(() => this.getDetail());
}
} else {
this.pickedLinkField.text = {};
this.originalForm = {};
this.file = {};
this.id = "";

@ -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 || this.originalRowIds[0],
text: this.tempRow.name || this.tempRow.value || this.tempRow.mingcheng || this.tempRow.no || this.tempRow.id
});
this.dialogVisible = false;
},
},
@ -275,13 +276,20 @@ export default {
if (newVal) {
} else {
this.tempRow = {};
this.originalRowIds = [];
this.$refs["table"].clearSelection();
}
},
originalRows(newVal) {
this.originalRowIds = newVal.map((i) => i[this.field]);
if (newVal) {
if (this.linkType === 'hasMany' || this.linkType === 'newHasMany') {
this.originalRowIds = newVal.map((i) => i[this.field]);
this.selectRows();
this.selectRows();
} else {
this.originalRowIds = [newVal.id]
}
}
},
},
};

@ -471,7 +471,6 @@ export default {
this.form
?.filter((i) => i.list_show)
.forEach((i) => {
if (i._relations) return
let linkOb = {};
if (i.edit_input === "richtext") {

@ -1,81 +1,24 @@
<template>
<div>
<div class="boxlist">
<div class="box box1">
<div class="boxtitle">
<span>营业统计</span>
<i class="el-icon-data-line statIcon"></i>
</div>
<div class="bline"></div>
<div class="boxcontentsubtitle">服务金额</div>
<div class="boxcontent">
<div class="boxcontentitem">
<div class="boxcontentitem-big">
{{totaldata.business.server_money_total}}
</div>
<div style="display: flex;justify-content: space-around;">
<div class="boxcontentitem-small">
<span>{{totaldata.business.nurse_money_total}}</span>
<span>护工金额</span>
</div>
<div class="boxcontentitem-small">
<span>{{totaldata.business.remain_money_total}}</span>
<span>留存金额</span>
</div>
</div>
</div>
</div>
</div>
<div class="box box2">
<div class="boxtitle">
<span>人效统计</span>
<i class="el-icon-user statIcon"></i>
</div>
<div class="bline"></div>
<div class="boxcontentsubtitle">总服务时长</div>
<div class="boxcontent">
<div class="boxcontentitem">
<div class="boxcontentitem-big">
{{totaldata.person_efficiency.server_time_total}}
分钟
</div>
<div style="display: flex;justify-content: space-around;">
<div class="boxcontentitem-small">
<span>{{totaldata.person_efficiency.expect}}</span>
<span> 照护人员数</span>
</div>
<div class="boxcontentitem-small">
<span>{{totaldata.person_efficiency.act}} </span>
<span>天数</span>
</div>
</div>
</div>
</div>
</div>
<div class="box box3">
<div class="boxtitle">
<span>客户统计</span>
<i class="el-icon-s-custom statIcon"></i>
<span>填报统计</span>
<i class="el-icon-document statIcon"></i>
</div>
<div class="bline"></div>
<div class="boxcontentsubtitle">活跃客户</div>
<div class="boxcontentsubtitle">填报数量</div>
<div class="boxcontent">
<div class="boxcontentitem">
<div class="boxcontentitem-big">
{{totaldata.customer.active}}
{{0}}
</div>
<div style="display: flex;justify-content: space-around;">
<div class="boxcontentitem-small">
<span>{{totaldata.customer.add}}</span>
<span>新增</span>
</div>
<div class="boxcontentitem-small">
<span>{{totaldata.customer.wash}}</span>
<span>流失</span>
<span>{{0}}</span>
<span>超期填报</span>
</div>
</div>
</div>
@ -85,23 +28,19 @@
<div class="box box4">
<div class="boxtitle">
<span>订单统计</span>
<i class="el-icon-document statIcon"></i>
<span>按部门统计</span>
<i class="el-icon-s-marketing statIcon"></i>
</div>
<div class="bline"></div>
<div class="boxcontentsubtitle">服务订单</div>
<div class="boxcontentsubtitle">部门数量</div>
<div class="boxcontent">
<div class="boxcontentitem">
<div class="boxcontentitem-big">{{totaldata.order.server_total}}
<div class="boxcontentitem-big">{{0}}
</div>
<div style="display: flex;justify-content: space-around;">
<div class="boxcontentitem-small">
<span>{{totaldata.order.cycle_total}}</span>
<span>周期性订单</span>
</div>
<div class="boxcontentitem-small">
<span>{{totaldata.order.unit_total}}</span>
<span>单次订单</span>
<span>{{0}}</span>
<span>存在超期</span>
</div>
</div>
</div>
@ -192,10 +131,8 @@
.box {
flex: 1;
position: relative;
width: 33%;
margin-left: 0.5%;
margin-right: 0.5%;
margin-bottom: 2.375rem;
box-shadow: 0px 8px 15px 0px rgba(212, 84, 32, 0.3100);
border-radius: 8px;
@ -203,6 +140,10 @@
opacity: 0.8;
padding: 1.25rem 0;
& + & {
margin-left: 1%;
}
.boxcontentsubtitle {
color: #FFFFFF;
text-align: center;

@ -14,7 +14,7 @@
import PanelGroup from './components/PanelGroup'
import {
getChartsHome
} from "../../api/dashboard.js"
} from "@/api/dashboard"
export default {
components: {

@ -0,0 +1,17 @@
<template>
<div>
</div>
</template>
<script>
export default {
data() {
return {}
},
methods: {},
computed: {},
}
</script>
<style scoped lang="scss">
</style>

@ -0,0 +1,51 @@
<template>
<div>
<Menu class="menu" mode="horizontal" theme="primary" active-name="1">
<MenuItem name="1">
<Icon type="ios-paper" />
内容管理
</MenuItem>
<MenuItem name="2">
<Icon type="ios-people" />
用户管理
</MenuItem>
<Submenu name="3">
<template slot="title">
<Icon type="ios-stats" />
统计分析
</template>
<MenuGroup title="使用">
<MenuItem name="3-1">新增和启动</MenuItem>
<MenuItem name="3-2">活跃分析</MenuItem>
<MenuItem name="3-3">时段分析</MenuItem>
</MenuGroup>
<MenuGroup title="留存">
<MenuItem name="3-4">用户留存</MenuItem>
<MenuItem name="3-5">流失用户</MenuItem>
</MenuGroup>
</Submenu>
<MenuItem name="4">
<Icon type="ios-construct" />
综合设置
</MenuItem>
</Menu>
</div>
</template>
<script>
export default {
data() {
return {
}
},
methods: {},
computed: {},
}
</script>
<style scoped lang="scss">
.menu {
display: flex;
justify-content: center;
}
</style>

@ -0,0 +1,670 @@
<template>
<div>
<!-- 查询配置 -->
<div>
<div ref="lxHeader">
<LxHeader
icon="md-apps"
:text="$route.meta.title"
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">
<DatePicker type="year" style="width: 100px;"></DatePicker>
<Select
v-model="select.filter[0].key"
style="width: 100px;margin-left: 10px;"
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>
<template
v-if="
select.filter[0].op !== 'range' &&
!columnArrTest(select.filter[0].key)
"
>
<Input
v-model="select.filter[0].value"
style="width: 150px; margin-left: 10px"
placeholder="请填写关键词"
/>
</template>
<template
v-else-if="
select.filter[0].op !== 'range' &&
columnArrTest(select.filter[0].key)
"
>
<Select
v-model="select.filter[0].value"
style="width: 150px; margin-left: 10px"
placeholder="请选择关键词"
>
<Option
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
>
</Select>
</template>
<template v-else>
<Input
:value="select.filter[0].value.split(',')[0]"
style="width: 150px; margin-left: 10px"
placeholder="范围开始关键词"
@input="(e) => inputStartHandler(e, select.filter[0])"
/>
<span
style="
margin-left: 10px;
display: flex;
align-items: center;
"
></span
>
<Input
:value="select.filter[0].value.split(',')[1]"
style="width: 150px; margin-left: 10px"
placeholder="范围结束关键词"
@input="(e) => inputEndHandler(e, select.filter[0])"
/>
</template>
<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"
:key="`${item.value}-${index}`"
>
<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>
<template
v-if="
item.op !== 'range' && !columnArrTest(item.key)
"
>
<Input
v-model="item.value"
style="width: 150px; margin-left: 10px"
placeholder="请填写关键词"
/>
</template>
<template
v-else-if="
item.op !== 'range' && columnArrTest(item.key)
"
>
<Select
v-model="item.value"
style="width: 150px; margin-left: 10px"
placeholder="请选择关键词"
>
<Option
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
>
</Select>
</template>
<template v-else>
<Input
:value="item.value.split(',')[0]"
style="width: 150px; margin-left: 10px"
placeholder="范围开始关键词"
@input="(e) => inputStartHandler(e, item)"
/>
<span style="margin-left: 10px"></span>
<Input
:value="item.value.split(',')[1]"
style="width: 150px; margin-left: 10px"
placeholder="范围结束关键词"
@input="(e) => inputEndHandler(e, item)"
/>
</template>
<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>
<template #import>
<Button type="primary" @click="$refs['imports'].show()"
>导入</Button
>
</template>
<template #export>
<Button
type="primary"
@click="exportExcel(new Date().getTime().toString())"
>导出</Button
>
</template>
</header-content>
</slot>
</LxHeader>
</div>
</div>
<!--$refs['drawer'].setId(row.id);
$refs['drawer'].show();-->
<xy-table
:auths="auths_auth_mixin"
:delay-req="true"
:destroy-action="destroy"
ref="xyTable"
:border="true"
:action="index"
:req-opt="tableSelect"
:destroy-req-opt="select"
:table-item="table"
@detail="
(row) => {
$router.push({
path: $route.path + '/detail/' + row.id
})
}
"
@editor="
(row) => {
$refs['dialog'].setId(row.id);
$refs['dialog'].setType('editor');
$refs['dialog'].show();
}
"
>
<template #pid>
<Button type="primary" size="small" @click="$refs['dialog'].setType('add'),$refs['dialog'].show()"></Button>
</template>
</xy-table>
<dialoger
:table-name="customForm.tableName"
:form-info="form"
ref="dialog"
@refresh="$refs['xyTable'].getTableData()"
>
</dialoger>
<drawer
:table-name="customForm.tableName"
:form-info="form"
ref="drawer"
></drawer>
<imports
:table-name="customForm.tableName"
:form-info="form"
ref="imports"
@refresh="$refs['xyTable'].getTableData()"
></imports>
</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 { download } from "@/utils/downloadRequest";
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 dialoger from "@/views/component/dialog.vue";
import LxHeader from "@/components/LxHeader/index.vue";
import headerContent from "@/components/LxHeader/XyContent.vue";
import drawer from "@/views/component/drawer.vue";
import imports from "@/views/component/imports.vue";
export default {
components: {
LxHeader,
dialoger,
headerContent,
drawer,
imports,
},
mixins: [authMixin],
provide: {
formStore: () => this.form,
},
data() {
return {
op,
select: {
table_name: "",
filter: [
{
key: "",
op: "",
value: "",
},
],
},
selectQuery: [],
form: [],
table: [],
replaceTableRender: new Map([
["year",{ formatter:(v1, v2, val) => (val.slice(0,4)) }],
["biaodan",{ customFn:row => (<a>填报表单</a>) }]
]),
customForm: {
customFormId: "",
tableName: "",
},
};
},
methods: {
index,
destroy,
download,
reset() {
this.select.filter.splice(1);
this.select.filter[0] = {
key: "",
op: "",
value: "",
};
},
async exportExcel(sheetName) {
const res = await index(
Object.assign(this.select, { page: 1, page_size: 9999 })
);
if (res.data) {
let headers = this.form.map((i) => {
return {
key: i.field,
title: i.name,
};
});
const data = res.data.map((row) =>
headers.map((header) => row[header.key])
);
data.unshift(headers.map((header) => header.title));
const wb = XLSX.utils.book_new();
const ws = XLSX.utils.aoa_to_sheet(data);
XLSX.utils.book_append_sheet(wb, ws, sheetName);
const wbout = XLSX.write(wb, {
bookType: "xlsx",
bookSST: true,
type: "array",
});
saveAs(
new Blob([wbout], { type: "application/octet-stream" }),
`${sheetName}.xlsx`
);
}
},
//target
inputStartHandler(e, target) {
let temp = target?.value.split(",")[1];
target.value = `${e},${temp ? temp : ""}`;
},
inputEndHandler(e, target) {
let temp = target?.value.split(",")[0];
target.value = `${temp ? temp : ""},${e}`;
},
async getFormDetail() {
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);
}
}
if (this.$route.meta.params?.select) {
try {
this.selectQuery = JSON.parse(decodeURIComponent(this.$route.meta.params?.select));
} catch (err) {
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)
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],
};
});
}
}
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;
});
}
}
});
this.form = fields;
console.log(111, this.form);
this.form
?.filter((i) => i.list_show)
.forEach((i) => {
if (this.replaceTableRender.get(i.field)) {
this.table.push({
prop: i.field,
label: i.name,
width: i.width,
fixed: i.is_fixed,
...this.replaceTableRender.get(i.field)
})
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);
});
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>
);
}
};
}
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>
);
}
};
}
}
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: "序号",
});
},
},
computed: {
columnArrTest() {
return function (field) {
return this.form.find((i) => i.field === field)
? this.form.find((i) => i.field === field).search_input === "checkbox" || this.form.find((i) => i.field === field).search_input === "radio"
: false;
};
},
getColumnField() {
return function (field) {
return this.form.find((i) => i.field === field)
? this.form.find((i) => i.field === field)
: {};
};
},
getColumnParams() {
return function (field) {
return this.form.find((i) => i.field === field)
? this.form.find((i) => i.field === field)._params
: [];
};
},
tableSelect () {
let filter = [...this.select.filter,...this.selectQuery]
return {
...this.select,
filter
}
}
},
created() {
this.getFormDetail();
},
};
</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;
margin-top: 10px;
& > span {
padding: 0 10px;
}
}
a {
color: red;
text-decoration: none;
transition: all 0.2s;
}
a:hover {
color: red;
text-decoration: underline;
}
</style>

@ -7,7 +7,7 @@ function resolve(dir) {
}
const name = defaultSettings.title // page title
const timeStamp = new Date().getTime()
// If your port is set to 80,
// use administrator privileges to execute the command line.
// For example, Mac: sudo npm run
@ -35,6 +35,10 @@ module.exports = {
sass:{
prependData: '@import "@/styles/index.scss";'
}
},
extract: { // 打包后css文件名称添加时间戳
filename: `static/css/[name].${timeStamp}.css`,
chunkFilename: `static/css/chunk.[id].${timeStamp}.css`
}
},
lintOnSave: process.env.NODE_ENV === 'development',
@ -65,6 +69,10 @@ module.exports = {
alias: {
'@': resolve('src')
}
},
output: {
filename: `js/[name]-${new Date().getTime()}.js`,
chunkFilename: `js/[name]-${new Date().getTime()}.js`
}
},
chainWebpack(config) {

Loading…
Cancel
Save