初始提交

This commit is contained in:
2026-01-04 11:09:06 +08:00
commit 8fa31df250
1326 changed files with 213907 additions and 0 deletions

View File

@@ -0,0 +1,242 @@
<template>
<view class="allApp-v">
<view class="notice-warp">
<view class="search-box">
<u-search :placeholder="$t('app.apply.pleaseKeyword')" v-model="keyword" height="72"
:show-action="false" @change="search" bg-color="#f0f2f6" shape="square">
</u-search>
</view>
</view>
<view class="usualList">
<view class="caption u-m-b-20">常用菜单</view>
<view class="u-flex u-flex-wrap">
<view class="item u-flex-col u-col-center" v-for="(item,i) in usualList" :key="i">
<text class="u-font-40 item-icon" :class="item.icon"
:style="{'background':item.iconBackground||'#008cff'}" />
<text class="u-font-24 u-line-1 item-text">{{item.fullName}}</text>
</view>
</view>
</view>
<CommonTabs :list="allList" @change="change" :current="current" ref="CommonTabs" isBoxShadow></CommonTabs>
<view class="allList u-m-t-20" v-if="allList.length">
<view class="u-m-t-20" v-for="(item,i) in allList" :key="i">
<template v-if="i==current && item?.children?.length">
<view v-for="(child,ii) in item.children" class="u-flex childList-item u-p-b-28" :key="ii">
<text class="u-font-40 item-icon" :class="child.icon"
:style="{'background':child.iconBackground||'#008cff'}" />
<text class="u-font-32 item-text u-m-l-28 u-m-r-28 u-line-2">{{child.fullName}}</text>
<view class="btnBox">
<u-button :custom-style="customStyle" @click="handelAdd(child)" v-if="!child.isData">添加
</u-button>
<u-button :custom-style="customStyle" type="error" @click="handelDel(child)" v-else>移除
</u-button>
</view>
</view>
</template>
</view>
</view>
<JnpfEmpty v-else />
</view>
</template>
<script>
import {
FlowEngineListAll
} from '@/api/workFlow/flowEngine'
import CommonTabs from '@/components/CommonTabs'
import {
getDataList,
getUsualList,
addUsual,
delUsual
} from '@/api/apply/apply.js'
export default {
components: {
CommonTabs
},
data() {
return {
current: 0,
usualList: [],
allList: [],
customStyle: {
width: "128rpx",
fontSize: "24rpx",
height: '60rpx'
},
type: '2',
keyword: ''
}
},
onLoad() {
this.init()
},
methods: {
init() {
uni.showLoading({
title: '加载中'
});
this.getUsualList()
},
search() {
this.searchTimer && clearTimeout(this.searchTimer);
this.searchTimer = setTimeout(() => {
this.allList = [];
this.usualList = [];
this.current = 0
this.getUsualList();
}, 300);
},
getUsualList() {
getUsualList().then(res => {
this.usualList = res.data.list.map(o => {
const objectData = o.objectData ? JSON.parse(o.objectData) : {}
return {
...o,
...objectData
}
})
})
this.getAllList()
},
getAllList() {
getDataList({
keyword: this.keyword
}).then(res => {
uni.hideLoading()
let list = JSON.parse(JSON.stringify(res.data.list))
for (let i = 0; i < list.length; i++) {
let children = list[i].children
if (Array.isArray(children) && children.length) {
for (let j = 0; j < children.length; j++) {
let iconBackground = '',
moduleId = ''
if (children[j].propertyJson) {
let propertyJson = JSON.parse(children[j].propertyJson)
iconBackground = propertyJson.iconBackgroundColor || ''
moduleId = propertyJson.moduleId || ''
}
this.$set(children[j], 'iconBackground', iconBackground)
this.$set(children[j], 'moduleId', moduleId)
}
}
}
this.allList = list.filter(o => o.children)
})
},
handelAdd(item) {
addUsual(item.id).then(res => {
this.usualList.push(item)
item.isData = true
uni.$emit('updateUsualList')
uni.showToast({
title: res.msg
})
})
},
handelDel(item) {
delUsual(item.id).then(res => {
this.usualList = this.usualList.filter(o => o.id !== item.id)
item.isData = false
uni.$emit('updateUsualList')
uni.showToast({
title: res.msg
})
})
},
change(index) {
this.current = index;
}
}
}
</script>
<style lang="scss">
page {
background-color: #f0f2f6;
}
.allApp-v {
.notice-warp {
height: 114rpx;
.search-box {
padding: 20rpx;
}
}
.caption {
font-size: 36rpx;
line-height: 80rpx;
padding: 0 32rpx;
.tip {
margin-left: 20rpx;
font-size: 24rpx;
color: #c6c6c6;
}
}
.tabs_box {
width: 100%;
.sticky {
width: 750rpx;
height: 120rpx;
color: #fff;
padding-right: 32rpx;
}
}
.usualList {
margin-top: 4.2rem;
margin-bottom: 20rpx;
background-color: #FFFFFF;
.item {
margin-bottom: 32rpx;
width: 25%;
.item-icon {
width: 88rpx;
height: 88rpx;
margin-bottom: 8rpx;
line-height: 88rpx;
text-align: center;
border-radius: 20rpx;
color: #fff;
font-size: 56rpx;
}
.item-text {
width: 100%;
text-align: center;
padding: 0 16rpx;
}
}
}
.allList {
padding: 20rpx 32rpx 0;
background-color: #FFFFFF;
.childList-item {
align-items: center;
.item-text {
width: calc(100% - 216rpx);
}
.item-icon {
width: 88rpx;
height: 88rpx;
line-height: 88rpx;
text-align: center;
border-radius: 30rpx;
color: #FFFFFF;
flex-shrink: 0;
font-size: 40rpx;
}
}
}
}
</style>

View File

@@ -0,0 +1,305 @@
<template>
<view class="catalog-v">
<uni-nav-bar class="nav" :fixed="true" :statusBar="true" :border="false" height="44" right-icon="bars"
@clickRight="clickRight" left-icon="left" @clickLeft="back">
<!-- 左边插槽 -->
<block #default>
<view class="" @click="close"
style="position: absolute;top: 0;left: 40px;bottom: 0;text-align: center;line-height: 82rpx;height: 100%;width: 40rpx;">
<u-icon name="close"></u-icon>
</view>
<view class="nav-left">
<view class="nav-left-text">{{ config.fullName }}</view>
</view>
</block>
</uni-nav-bar>
<view class="search-box_sticky" :style="{'top':topSearch+'rpx'}">
<view class="search-box">
<u-search :placeholder="$t('app.apply.pleaseKeyword')" v-model="keyword" height="72"
:show-action="false" @change="search" bg-color="#f0f2f6" shape="square">
</u-search>
</view>
</view>
<view class="workFlow-list">
<view class="part" v-if="childrenData.length">
<view class="u-flex u-flex-wrap">
<view class="item u-flex-col u-col-center" v-for="(child, ii) in childrenData" :key="ii"
@click="handelClick(child)">
<text class="u-font-40 item-icon" :class="child.icon"
:style="{ background: child.iconBackground || '#008cff' }" />
<text class="u-font-24 u-line-1 item-text">{{child.fullName}}</text>
</view>
</view>
</view>
<JnpfEmpty v-else />
</view>
<treeCollapse :show="showApply" v-if="showApply" :treeData="menuList" @change="handelClick"></treeCollapse>
</view>
</template>
<script>
import treeCollapse from '@/components/treeCollapse'
export default {
components: {
treeCollapse
},
data() {
return {
showApply: false,
topSearch: 80,
keyword: "",
statusBarHeight: "",
userInfo: {
systemIds: [],
}, //CurrentUser接口中的userInfo数据
modelId: "",
config: {},
fullName: "",
childrenData: []
};
},
computed: {
baseURL() {
return this.define.baseURL;
},
token() {
return uni.getStorageSync('token')
},
report() {
return this.define.report;
},
pcURL() {
return this.define.pcURL;
},
menuList() {
let list = uni.getStorageSync('menuList').filter(o => o.enCode !== 'workFlow')
return list
}
},
onLoad(e) {
this.config = JSON.parse(this.jnpf.base64.decode(e.config)) || {};
if (Array.isArray(this.config.children) && this.config.children.length) this.childrenData = JSON.parse(JSON
.stringify(this.config.children))
this.keyword = ""
this.handleData(this.childrenData)
uni.setNavigationBarTitle({
title: this.config.fullName
})
this.getStatusBarHeight();
},
methods: {
close() {
uni.switchTab({
url: '/pages/index/index',
});
},
back() {
uni.navigateBack({
delta: 1
})
},
clickRight() {
this.handleData(this.menuList)
this.$nextTick(() => {
this.showApply = !this.showApply
})
},
handleData(childrenData) {
const loop = (list, parent) => {
for (let i = 0; i < list.length; i++) {
let propertyJson = JSON.parse(list[i].propertyJson)
this.$set(list[i], 'moduleId', propertyJson.moduleId)
if (list[i].children && Array.isArray(list[i].children)) {
loop(list[i].children, list[i])
}
}
}
loop(childrenData)
},
getStatusBarHeight() {
let that = this
wx.getSystemInfo({
success(res) {
that.statusBarHeight = res.statusBarHeight;
},
});
// #ifdef APP-PLUS
uni.getSystemInfo({
success(res) {
that.statusBarHeight = res.statusBarHeight;
let topSearch = 75 + that.statusBarHeight * 2
that.topSearch = topSearch
}
})
// #endif
},
search() {
this.searchTimer && clearTimeout(this.searchTimer);
this.searchTimer = setTimeout(() => {
if (!this.keyword) return this.childrenData = JSON.parse(JSON.stringify(this.config.children))
const regex = new RegExp(this.keyword, 'i');
this.childrenData = this.childrenData.filter(item => regex.test(item.fullName))
}, 300);
},
handelClick(item) {
this.showApply = false
this.modelId = item.moduleId
if (item.type == 1) {
uni.navigateTo({
url: "/pages/apply/catalog/index?config=" +
this.jnpf.base64.encode(JSON.stringify(item)),
fail: () => {
this.$u.toast("暂无此页面");
},
});
return;
}
let url = ''
// 2-页面 11-回传表单
if (item.type == 2 || item.type == 11) {
if (!item.pageAddress) {
this.$u.toast("暂无此页面");
return;
}
url = item.pageAddress + "?menuId=" + item.id + "&fullName=" + item.fullName
}
// 3-在线表单 9-流程
if (item.type == 3 || item.type == 9) {
if (!item.moduleId) {
this.$u.toast("暂无此页面");
return;
}
url = "/pages/apply/dynamicModel/index?config=" + this.jnpf.base64.encode(JSON.stringify(item))
}
// 外链
if (item.type == 7) {
if (!item.pageAddress) {
this.$u.toast("暂无此页面");
return;
}
url = "/pages/apply/externalLink/index?url=" + encodeURIComponent(item.pageAddress) + "&fullName=" +
item.fullName + "&type=" + item.type
}
// 报表(原)
if (item.type == 5) {
if (!item.moduleId) {
this.$u.toast("暂无此页面");
return;
}
userInfo = uni.getStorageSync('userInfo') || {}
const appCode = userInfo.systemCode
const urlPre = encodeURIComponent(
`${this.report}/preview.html?id=${item.moduleId}&token=${this.token}&appCode=${appCode}&page=1&from=menu`
)
url = "/pages/apply/externalLink/index?url=" + urlPre + "&fullName=" + item.fullName + "&type=" +
item.type
}
// 报表
if (item.type == 10) {
if (!item.moduleId) {
this.$u.toast("暂无此页面");
return;
}
const urlPre = encodeURIComponent(
`${this.pcURL}/reportPreview?id=${item.moduleId}&token=${this.token}&from=app`
);
url = "/pages/apply/externalLink/index?url=" + urlPre + "&fullName=" + item.fullName + "&type=" +
item.type
}
// 门户
if (item.type == 8) {
if (!item.moduleId) {
this.$u.toast("暂无此页面");
return;
}
url = "/pages/portal/scanPortal/index?id=" + item.moduleId + "&portalType=1&fullName=" +
item.fullName
}
if (!url) return;
uni.navigateTo({
url,
fail: () => {
this.$u.toast("暂无此页面");
},
});
}
},
};
</script>
<style lang="scss">
page {
background-color: #f0f2f6;
}
.catalog-v {
.search-box_sticky {
margin-bottom: 20rpx;
.search-box {
padding: 20rpx;
}
}
.nav {
z-index: 99999;
:deep(.uni-navbar__content) {
z-index: 99999;
}
:deep(.uni-navbar__header-container) {
justify-content: center;
}
}
.nav-left {
max-width: 100%;
display: flex;
align-items: center;
.nav-left-text {
font-weight: 700;
font-size: 29rpx;
flex: 1;
min-width: 0;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
}
.select-box,
.u-drawer {
max-height: 600rpx;
:deep(.u-drawer-content) {
height: 100% !important;
}
.currentItem {
color: #2979ff;
}
}
.search-box {
overflow-y: overlay;
height: 112rpx;
width: 100%;
padding: 20rpx 20rpx;
z-index: 10000;
background: #fff;
}
.workFlow-list {
.part {
.item {
margin-bottom: 0;
padding: 1rem 0;
}
}
}
}
</style>

View File

@@ -0,0 +1,228 @@
<template>
<view class="jnpf-wrap jnpf-wrap-form">
<JnpfParser :formConf="formConf" ref="dynamicForm" v-if="!loading" @submit="sumbitForm" :key="key" />
<view class="buttom-actions">
<u-button class="buttom-btn" @click.stop="cancel">取消</u-button>
<u-button class="buttom-btn" type="primary" @click.stop="submit" :loading="btnLoading">
{{config.confirmButtonText||'确定'}}
</u-button>
</view>
</view>
</template>
<script>
import {
getConfigDataByMenuId,
getModelInfo,
createModel
} from '@/api/apply/visualDev'
import {
getDataInterfaceRes
} from '@/api/common'
export default {
data() {
return {
config: {},
id: "",
modelId: "",
formConf: {},
dataForm: {},
key: +new Date(),
loading: false,
btnLoading: false,
isPreview: true,
formData: {},
isAdd: false,
userInfo: {}
}
},
onLoad(e) {
this.userInfo = uni.getStorageSync('userInfo') || {}
this.loading = true
let data = e.data ? JSON.parse(decodeURIComponent(e.data)) : {}
this.config = data.config
this.id = data.id
this.modelId = data.modelId
this.isPreview = data.isPreview
if (this.id != null && this.id != undefined && this.id != '') {
this.isAdd = false
} else {
this.isAdd = true
}
uni.setNavigationBarTitle({
title: this.config.popupTitle
})
if (this.config.modelId) this.getConfigData(data.row)
},
methods: {
getConfigData(row) {
getConfigDataByMenuId({
menuId: this.config.modelId
}).then(res => {
this.config.modelId = res.data.id
if (res.code !== 200 || !res.data) {
uni.showToast({
title: res.msg || '请求出错,请重试',
icon: 'none'
})
return
}
this.formConf = JSON.parse(res.data.formData)
const setDataFun = (formData) => {
if (this.config.formOptions.length) {
for (let k in formData) {
for (let i = 0; i < this.config.formOptions.length; i++) {
const e = this.config.formOptions[i]
if (e.currentField == '@formId') this.formData[e.field] = formData.id;
if (e.currentField == k) this.formData[e.field] = formData[k]
}
}
}
this.fillFormData(this.formConf, this.formData)
this.key = +new Date()
this.loading = false
}
if (this.id) {
getModelInfo(this.modelId, this.id).then(res => {
let dataForm = res.data
if (!dataForm.data) return
const formData = JSON.parse(dataForm.data)
this.formData = {}
setDataFun({
...formData,
id: this.id
})
})
} else {
const formData = row
setDataFun(formData)
}
}).catch(() => {})
},
fillFormData(form, data) {
const loop = list => {
for (let i = 0; i < list.length; i++) {
let item = list[i]
let vModel = item.__vModel__
let config = item.__config__
if (vModel) {
let val = data.hasOwnProperty(vModel) ? data[vModel] : config.defaultValue
if (!config.isSubTable) config.defaultValue = val
if (config.defaultCurrent) {
if (config.jnpfKey === 'datePicker') {
if (!data.hasOwnProperty(vModel)) {
let format = this.jnpf.handelFormat(item.format)
let dateStr = this.jnpf.toDate(new Date().getTime(), format)
let time = format === 'yyyy' ? '-01-01 00:00:00' : format === 'yyyy-MM' ?
'-01 00:00:00' : format === 'yyyy-MM-dd' ?
' 00:00:00' : ''
val = new Date(dateStr + time).getTime()
config.defaultValue = val
}
}
if (config.jnpfKey === 'timePicker') {
if (!data.hasOwnProperty(vModel)) {
config.defaultValue = this.jnpf.toDate(new Date(), item.format)
}
}
if (config.jnpfKey === 'organizeSelect' && this.userInfo.organizeIds?.length) {
config.defaultValue = item.multiple ? this.userInfo.organizeIds :
this.userInfo.organizeId
}
if (config.jnpfKey === 'posSelect' && this.userInfo.positionIds?.length) {
config.defaultValue = item.multiple ? this.userInfo.positionIds :
this.userInfo.positionId
}
const userId = this.userInfo.userId
if (config.jnpfKey === 'userSelect' && userId) {
config.defaultValue = item.multiple ? [userId] : userId;
}
if (config.jnpfKey === 'usersSelect' && userId) {
config.defaultValue = [userId + '--user'];
}
if (config.jnpfKey === 'sign' && this.userInfo.signImg) {
config.defaultValue = this.userInfo.signImg
}
}
let noShow = !item.__config__.noShow ? false : item.__config__.noShow
let isVisibility = false
if (!item.__config__.visibility || (Array.isArray(item.__config__.visibility) && item
.__config__.visibility.includes('app'))) isVisibility = true
this.$set(item.__config__, 'isVisibility', isVisibility)
this.$set(item.__config__, 'noShow', noShow)
} else {
let noShow = false,
isVisibility = false
if (!item.__config__.visibility || (Array.isArray(item.__config__.visibility) && item
.__config__.visibility.includes('app'))) isVisibility = true
this.$set(item.__config__, 'isVisibility', isVisibility)
this.$set(item.__config__, 'noShow', noShow)
}
if (item.__config__ && item.__config__.children && Array
.isArray(item.__config__.children)) {
loop(item.__config__.children)
}
}
}
loop(form.fields)
},
cancel() {
uni.navigateBack();
},
sumbitForm(data, callback) {
if (!data) return
this.btnLoading = true
const successFun = (res, callback) => {
if (callback && typeof callback === "function") callback()
uni.showToast({
title: res.msg,
complete: () => {
setTimeout(() => {
this.btnLoading = false
if (this.config.isRefresh) uni.$emit('refresh')
uni.navigateBack()
}, 1500)
}
})
}
if (this.config.customBtn) {
const query = {
paramList: this.jnpf.getParamList(this.config.templateJson, {
...data,
id: this.id
}) || []
};
getDataInterfaceRes(this.config.interfaceId, query).then(res => {
successFun(res, callback)
}).catch(() => {
this.btnLoading = false
})
} else {
this.dataForm.data = JSON.stringify(data)
createModel(this.config.modelId, this.dataForm).then(res => {
successFun(res, callback)
}).catch(() => {
this.btnLoading = false
})
}
},
submit() {
if (this.isPreview) {
uni.showToast({
title: '功能预览不支持数据保存',
icon: 'none'
})
return
}
this.$refs.dynamicForm && this.$refs.dynamicForm.submitForm()
},
}
}
</script>
<style scoped lang="scss">
page {
background-color: #f0f2f6;
}
</style>

View File

@@ -0,0 +1,75 @@
import {
deteleModel
} from '@/api/apply/visualDev'
export default {
data() {
return {
slide: '',
slide2: '',
checkedAll: false,
ids: [],
showTop: false,
}
},
methods: {
/* 批量删除 */
batchDelete() {
if (!this.selectItems.length) {
return this.$u.toast('请选择一条数据')
}
uni.showModal({
title: '提示',
content: '删除后数据无法恢复',
success: (res) => {
if (res.confirm) {
const uniqueIds = new Set();
this.selectItems.forEach(item => {
uniqueIds.add(item.id);
});
const ids = [...uniqueIds];
let data = {
flowId: this.config.flowId,
ids
};
deteleModel(data, this.modelId).then(res => {
this.selectItems = [];
this.$u.toast(res.msg)
this.mescroll.resetUpScroll()
})
}
}
})
},
openBatchOperate() {
this.showTop = !this.showTop
if (this.showTop) {
this.slide = 'slide-up'
this.slide2 = 'slide-up2'
}
},
checkAll() {
this.checkedAll = !this.checkedAll
this.list = this.list.map(o => ({
...o,
checked: false
}))
if (this.checkedAll) {
this.list = this.list.map(o => ({
...o,
checked: true
}))
}
},
cancel() {
this.list = this.list.map(o => ({
...o,
checked: false
}))
this.showTop = false
this.checkedAll = false
this.$nextTick(() => {
this.$refs.list.handleCheckAll()
})
}
}
}

View File

@@ -0,0 +1,596 @@
<template>
<view :class="{'item-card':config.jnpfKey==='card'}"
v-if="!config.noShow && (!config.visibility || (Array.isArray(config.visibility) && config.visibility.includes('app')))">
<template v-if="config.layout==='colFormItem'">
<JnpfText v-if="config.jnpfKey=='text'" :content="item.content" :textStyle="item.textStyle" />
<JnpfDivider v-else-if="config.jnpfKey==='divider'" :content="item.content" />
<JnpfGroupTitle v-else-if="config.jnpfKey=='groupTitle'" :content="item.content"
:content-position="item.contentPosition" :helpMessage="item.helpMessage" @groupIcon="clickIcon(item)" />
<u-form-item v-else-if="config.jnpfKey==='popupSelect' || config.jnpfKey==='relationForm'"
:label="realLabel" :prop="item.__vModel__" class="popup-select" :label-width="labelWidth"
:left-icon="leftIcon" :left-icon-style="{'color':'#a8aaaf'}" @clickIcon="clickIcon(item)">
<view class="detail-text-box" v-if="config.jnpfKey==='popupSelect'">
<view class="jnpf-detail-text">
{{formData[item.__vModel__]}}
</view>
<DisplayList v-if="Object.keys(extraObj).length" :extraObj="extraObj"
:extraOptions="item.extraOptions">
</DisplayList>
</view>
<view class="detail-text-box" @click.native="toDetail(item)" v-if="config.jnpfKey==='relationForm'">
<view class="jnpf-detail-text" style="color:rgb(41, 121, 255)">
{{formData[item.__vModel__]}}
</view>
<DisplayList v-if="Object.keys(extraObj).length" :extraObj="extraObj"
:extraOptions="item.extraOptions">
</DisplayList>
</view>
</u-form-item>
<u-form-item v-else :label="realLabel" :prop="item.__vModel__" :label-width="labelWidth"
:left-icon="leftIcon" :left-icon-style="{'color':'#a8aaaf'}" @clickIcon="clickIcon(item)">
<JnpfUploadImg v-if="config.jnpfKey==='uploadImg'" v-model="config.defaultValue" detailed />
<!-- #ifndef APP-HARMONY -->
<JnpfUploadFile v-else-if="config.jnpfKey=='uploadFile'" v-model="config.defaultValue" detailed />
<!-- #endif -->
<!-- #ifdef APP-HARMONY -->
<JnpfUploadFileH v-else-if="config.jnpfKey=='uploadFile'" v-model="config.defaultValue" detailed />
<!-- #endif -->
<JnpfColorPicker v-else-if="config.jnpfKey==='colorPicker'" v-model="config.defaultValue"
:colorFormat="item.colorFormat" disabled />
<JnpfRate v-else-if="config.jnpfKey==='rate'" v-model="config.defaultValue" :max="item.count"
:allowHalf="item.allowHalf" disabled />
<JnpfEditor v-else-if="config.jnpfKey==='editor'" v-model="config.defaultValue" detailed />
<JnpfBarcode v-else-if="config.jnpfKey=='barcode'" :staticText="item.staticText" :width="item.width"
:height="item.height" :format="item.format" :dataType="item.dataType" :lineColor="item.lineColor"
:background="item.background" :relationField="item.relationField+'_id'" :formData="formData" />
<JnpfQrcode v-else-if="config.jnpfKey=='qrcode'" :staticText="item.staticText" :width="item.width"
:dataType="item.dataType" :colorDark="item.colorDark" :colorLight="item.colorLight"
:relationField="item.relationField+'_id'" :formData="formData" />
<JnpfInputNumber v-else-if="config.jnpfKey=='inputNumber'" v-model="config.defaultValue"
:step='item.step' :max='item.max||999999999999999' :min='item.min||-999999999999999'
:disabled="item.disabled" :placeholder="item.placeholder" :isAmountChinese="item.isAmountChinese"
:thousands="item.thousands" :addonAfter="item.addonAfter" :addonBefore="item.addonBefore"
:controls="item.controls" :precision="item.precision" detailed />
<JnpfCalculate v-else-if="config.jnpfKey==='calculate'" :expression='item.expression'
:vModel='item.__vModel__' :config='config' :formData='formData' v-model="config.defaultValue"
:precision="item.precision" :isAmountChinese="item.isAmountChinese" :thousands="item.thousands"
:roundType="item.roundType" :dateCalConfig="item.dateCalConfig" :type="item.type" />
<JnpfDateCalculate v-else-if="config.jnpfKey==='dateCalculate'" :expression='item.expression'
:vModel='item.__vModel__' :config='config' :formData='formData' v-model="config.defaultValue"
:startRelationField="item.startRelationField" :startTimeType="item.startTimeType"
:startTimeValue="item.startTimeValue" :format="item.format" />
<JnpfLink v-else-if="config.jnpfKey=='link'" :content="item.content" :href="item.href"
:target='item.target' :textStyle="item.textStyle" />
<JnpfAlert v-else-if="config.jnpfKey=='alert'" :type="item.type" :title="item.title"
:tagIcon='item.tagIcon' :showIcon="item.showIcon" :closable="item.closable"
:description="item.description" :closeText="item.closeText" />
<JnpfButton v-else-if="config.jnpfKey=='button'" :buttonText="item.buttonText" :align="item.align"
:type="item.type" :disabled="item.disabled" />
<JnpfSlider v-else-if="config.jnpfKey=='slider'" v-model="config.defaultValue" :step="item.step"
:min="item.min||0" :max="item.max||100" disabled />
<JnpfSign v-else-if="config.jnpfKey=='sign'" v-model="config.defaultValue" detailed />
<JnpfSignature v-else-if="config.jnpfKey=='signature'" v-model="config.defaultValue" detailed />
<JnpfLocation v-else-if="config.jnpfKey=='location'" v-model="config.defaultValue"
:enableLocationScope="item.enableLocationScope" detailed />
<!--end labelwidth=0-->
<template v-else>
<JnpfInput v-if="config.jnpfKey=='input'" v-model="config.defaultValue" detailed
:useMask="item.useMask" :maskConfig="item.maskConfig" :addonBefore="item.addonBefore"
:addonAfter="item.addonAfter" />
<view class="jnpf-detail-text" v-else>{{ getValue(item) }}</view>
</template>
</u-form-item>
</template>
<template v-else>
<view class="jnpf-card" v-if="config.jnpfKey==='card'||config.jnpfKey==='row'">
<view class="jnpf-card-cap u-line-1 u-flex" v-if="item.header" @click="clickIcon(item)">
{{item.header}}
<u-icon :name="config.tipLabel? 'question-circle-fill':''" class="u-m-l-10" color="#a0acb7" />
</view>
<Item v-for="(child, index) in config.children" :key="config.renderKey+index" :itemData="child"
:formConf="formConf" :formData="formData" @toDetail="toDetail" @clickIcon='clickIcon' />
</view>
<template v-if="config.jnpfKey==='table'">
<view class="jnpf-table">
<view class="jnpf-table-title u-line-1" @click="clickIcon(item)">
{{config.label}}
<u-icon v-if="config.tipLabel" :name="'question-circle-fill'" class="u-m-l-10"
color="#a0acb7" />
</view>
<view v-for="(column,columnIndex) in config.defaultValue" :key="columnIndex">
<view class="jnpf-table-item-title">
<view class="jnpf-table-item-title-num">({{columnIndex+1}})</view>
</view>
<view class="form-item-box" v-for="(childItem,cIndex) in config.children" :key="cIndex">
<u-form-item :label="childItem.__config__.showLabel?childItem.__config__.label:''"
:label-width="childItem.__config__.labelWidth ? childItem.__config__.labelWidth * 1.5 : undefined"
@clickIcon="clickIcon(childItem)"
:left-icon='childItem.__config__.tipLabel &&childItem.__config__.showLabel&& childItem.__config__.label? "question-circle-fill":""'
:left-icon-style="{'color':'#a0acb7'}"
v-if="!childItem.__config__.noShow&&(!childItem.__config__.visibility|| (Array.isArray(childItem.__config__.visibility) && childItem.__config__.visibility.includes('app')))">
<template
v-if="['relationFormAttr','popupAttr'].includes(childItem.__config__.jnpfKey)">
<view class="jnpf-detail-text" v-if="!childItem.__vModel__">
{{ column[childItem.relationField.split('_jnpfTable_')[0]+'_'+childItem.showField] }}
</view>
<view class="jnpf-detail-text" v-else>
{{column[childItem.__vModel__]}}
</view>
</template>
<view v-else-if="childItem.__config__.jnpfKey==='relationForm'" class="jnpf-detail-text"
style="color:rgb(41, 121, 255)"
@click.native="toTableDetail(childItem,column[childItem.__vModel__+'_id'])">
{{column[childItem.__vModel__]}}
</view>
<JnpfSign v-else-if="childItem.__config__.jnpfKey=='sign'"
v-model="column[childItem.__vModel__]" detailed />
<JnpfSignature v-else-if="childItem.__config__.jnpfKey=='signature'"
v-model="column[childItem.__vModel__]" detailed />
<JnpfLocation v-else-if="childItem.__config__.jnpfKey=='location'"
v-model="column[childItem.__vModel__]"
:enableLocationScope="item.enableLocationScope" detailed />
<!-- #ifndef APP-HARMONY -->
<JnpfUploadFile v-else-if="childItem.__config__.jnpfKey==='uploadFile'"
v-model="column[childItem.__vModel__]" detailed />
<!-- #endif -->
<!-- #ifdef APP-HARMONY -->
<JnpfUploadFileH v-else-if="childItem.__config__.jnpfKey==='uploadFile'"
v-model="column[childItem.__vModel__]" detailed />
<!-- #endif -->
<JnpfUploadImg v-else-if="childItem.__config__.jnpfKey==='uploadImg'"
v-model="column[childItem.__vModel__]" detailed />
<JnpfInputNumber v-else-if="childItem.__config__.jnpfKey=='inputNumber'"
v-model="column[childItem.__vModel__]" :step='childItem.step' :max='childItem.max'
:min='childItem.min' :disabled="childItem.disabled"
:placeholder="childItem.placeholder" :isAmountChinese="childItem.isAmountChinese"
:thousands="childItem.thousands" :addonAfter="childItem.addonAfter"
:addonBefore="childItem.addonBefore" :controls="childItem.controls"
:precision="childItem.precision" detailed />
<JnpfCalculate v-else-if="childItem.__config__.jnpfKey==='calculate'"
:expression='childItem.expression' :vModel='childItem.__vModel__'
:config='childItem.__config__' :formData='formData' :roundType="childItem.roundType"
:dateCalConfig="childItem.dateCalConfig" :type="childItem.type"
v-model="column[childItem.__vModel__]" :precision="childItem.precision"
:isAmountChinese="childItem.isAmountChinese" :thousands="childItem.thousands"
:rowIndex="columnIndex" />
<JnpfDateCalculate v-else-if="childItem.__config__.jnpfKey==='dateCalculate'"
:expression='childItem.expression' :vModel='childItem.__vModel__'
:config='childItem.__config__' :formData='formData'
v-model="column[childItem.__vModel__]"
:startRelationField="childItem.startRelationField"
:startTimeType="childItem.startTimeType" :startTimeValue="childItem.startTimeValue"
:format="childItem.format" :rowIndex="columnIndex" />
<JnpfRate v-else-if="childItem.__config__.jnpfKey==='rate'" :max="childItem.count"
v-model="column[childItem.__vModel__]" :allowHalf="childItem.allowHalf" disabled />
<JnpfSlider v-else-if="childItem.__config__.jnpfKey=='slider'"
v-model="column[childItem.__vModel__]" :step="childItem.step"
:min="childItem.min||0" :max="childItem.max||100" disabled />
<template v-else>
<JnpfInput v-if="childItem.__config__.jnpfKey=='input'"
v-model="column[childItem.__vModel__]" detailed :useMask="childItem.useMask"
:maskConfig="childItem.maskConfig" :addonBefore="childItem.addonBefore"
:addonAfter="childItem.addonAfter" />
<view class="jnpf-detail-text" v-else>{{column[childItem.__vModel__]}}</view>
</template>
</u-form-item>
</view>
</view>
<view class="jnpf-table-item" v-if="item.showSummary && summaryField.length">
<view class="jnpf-table-item-title u-flex u-row-between">
<text class="jnpf-table-item-title-num">{{item.__config__.label}}合计</text>
</view>
<view class=" u-p-l-20 u-p-r-20 form-item-box">
<u-form-item v-for="(item,index) in summaryField" :label="item.__config__.label"
:key="item.__vModel__">
<u-input input-align='right' v-model="item.value" disabled />
</u-form-item>
</view>
</view>
</view>
</template>
<view v-else-if="config.jnpfKey==='steps'" style="background-color: #fff;padding:15px 0">
<view class="step-container">
<u-steps :list="config.children" name="title" :mode="item.simple ? 'dot' :'number'"
@change="onStepChange($event,item)" :current="stepCurrent">
</u-steps>
</view>
<view v-for="(itemSub,i) in config.children" :key='i'>
<view v-if="i === stepCurrent">
<Item v-for="(childItem, childIndex) in itemSub.__config__.children" :key="childIndex"
:itemData="childItem" :formConf="formConf" :formData="formData" @toDetail="toDetail"
@clickIcon='clickIcon' />
</view>
</view>
</view>
<view class="jnpf-tab" v-if="config.jnpfKey==='tab'">
<u-tabs is-scroll :list="config.children" name="title" v-model="tabCurrent" @change="onTabChange" />
<view v-for="(pane,i) in config.children" :key='i'>
<view v-show="i == tabCurrent">
<Item v-for="(childItem, childIndex) in pane.__config__.children" :key="childIndex"
:itemData="childItem" :formConf="formConf" :formData="formData" @toDetail="toDetail"
@clickIcon='clickIcon' />
</view>
</view>
</view>
<template v-if="config.jnpfKey==='collapse'">
<u-collapse :head-style="{'padding-left':'20rpx'}" :accordion="item.accordion" ref="collapseRef">
<u-collapse-item :title="pane.title" v-for="(pane, i) in config.children" :key="i"
:open="config.active && config.active.indexOf(pane.name)>-1">
<Item v-for="(child, j) in pane.__config__.children" :key="child.__config__.renderKey"
:itemData="child" :formConf="formConf" :formData="formData" @toDetail="toDetail"
@clickIcon='clickIcon' />
</u-collapse-item>
</u-collapse>
</template>
</template>
</view>
</template>
<script>
import {
getRelationFormDetail,
getDataInterfaceDataInfoByIds
} from '@/api/common.js'
// #ifdef MP
import Item from './Item.vue' //兼容小程序
// #endif
import DisplayList from '@/components/displayList'
const specialList = ['link', 'editor', 'button', 'alert']
export default {
name: 'Item',
components: {
// #ifdef MP
Item,
// #endif
DisplayList
},
props: {
itemData: {
type: Object,
required: true
},
formConf: {
type: Object,
required: true
},
formData: {
type: Object,
},
},
computed: {
item() {
const item = uni.$u.deepClone(this.itemData)
this.initI18n(item)
return item
},
config() {
return this.item.__config__
},
labelWidth() {
if (specialList.indexOf(this.config.jnpfKey) > -1) return 0
return this.config.labelWidth ? this.config.labelWidth * 1.5 : undefined
},
label() {
return this.config.showLabel && specialList.indexOf(this.config.jnpfKey) < 0 ? this.config.label : ''
},
realLabel() {
return this.label ? (this.label + (this.formConf.labelSuffix || '')) : ''
},
leftIcon() {
return this.config.tipLabel && this.label && this.config.showLabel ? "question-circle-fill" : ""
}
},
data() {
return {
tabCurrent: 0,
tableData: [],
summaryField: [],
stepCurrent: 0,
extraObj: {}
}
},
created() {
this.handleSummary()
this.handleTab()
},
mounted() {
if (this.config.jnpfKey === 'collapse') {
this.$refs.collapseRef && this.$refs.collapseRef.init()
}
uni.$on('initCollapse', () => {
this.$refs.collapseRef && this.$refs.collapseRef.init()
})
this.getDataChange()
this.getDataInterfaceDataInfoByIds()
},
methods: {
onStepChange(index, item) {
if (this.stepCurrent === index) return
item.__config__.active = index
this.stepCurrent = index
this.$nextTick(() => {
uni.$emit('updateCode')
uni.$emit('initCollapse')
})
},
initI18n(item) {
const config = item.__config__
if (item.placeholderI18nCode) {
//#ifdef MP-WEIXIN
item.placeholder = this.$t(item.placeholderI18nCode);
//#endif
//#ifndef MP-WEIXIN
item.placeholder = this.$t(item.placeholderI18nCode, item.placeholder);
//#endif
}
if (item.__config__.label && item.__config__.labelI18nCode) {
//#ifdef MP-WEIXIN
item.__config__.label = this.$t(item.__config__.labelI18nCode);
//#endif
//#ifndef MP-WEIXIN
item.__config__.label = this.$t(item.__config__.labelI18nCode, item.__config__.label);
//#endif
}
if (item.__config__.tipLabel && item.__config__.tipLabelI18nCode) {
//#ifdef MP-WEIXIN
item.__config__.tipLabel = this.$t(item.__config__.tipLabelI18nCode);
//#endif
//#ifndef MP-WEIXIN
item.__config__.tipLabel = this.$t(item.__config__.tipLabelI18nCode, item.__config__.tipLabel);
//#endif
}
if (['groupTitle', 'divider', 'link', 'text'].includes(config.jnpfKey)) {
if (item.contentI18nCode) {
//#ifdef MP-WEIXIN
item.content = this.$t(item.contentI18nCode);
//#endif
//#ifndef MP-WEIXIN
item.content = this.$t(item.contentI18nCode, item.content);
//#endif
}
if (item.helpMessageI18nCode) {
//#ifdef MP-WEIXIN
item.helpMessage = this.$t(item.helpMessageI18nCode);
//#endif
//#ifndef MP-WEIXIN
item.helpMessage = this.$t(item.helpMessageI18nCode, item.helpMessage);
//#endif
}
}
if (config.jnpfKey === 'button') {
if (item.buttonTextI18nCode) {
//#ifdef MP-WEIXIN
item.buttonText = this.$t(item.buttonTextI18nCode);
//#endif
//#ifndef MP-WEIXIN
item.buttonText = this.$t(item.buttonTextI18nCode.item.buttonText);
//#endif
}
}
if (config.jnpfKey === 'alert') {
if (item.titleI18nCode) {
//#ifdef MP-WEIXIN
item.title = this.$t(item.titleI18nCode);
//#endif
//#ifndef MP-WEIXIN
item.title = this.$t(item.titleI18nCode, item.title);
//#endif
}
if (item.descriptionI18nCode) {
//#ifdef MP-WEIXIN
item.description = this.$t(item.descriptionI18nCode);
//#endif
//#ifndef MP-WEIXIN
item.description = this.$t(item.descriptionI18nCode, item.description);
//#endif
}
if (item.closeTextI18nCode) {
//#ifdef MP-WEIXIN
item.closeText = this.$t(item.closeTextI18nCode);
//#endif
//#ifndef MP-WEIXIN
item.closeText = this.$t(item.closeTextI18nCode, item.closeText);
//#endif
}
}
if (config.jnpfKey === 'card') {
if (item.headerI18nCode) {
//#ifdef MP-WEIXIN
item.header = this.$t(item.headerI18nCode);
//#endif
//#ifndef MP-WEIXIN
item.header = this.$t(item.headerI18nCode, item.header);
//#endif
}
}
if (['tab', 'collapse', 'steps'].includes(config.jnpfKey)) {
if (config.children && config.children.length) {
for (let i = 0; i < config.children.length; i++) {
if (config.children[i].titleI18nCode) {
//#ifdef MP-WEIXIN
config.children[i].title =
this.$t(config.children[i].titleI18nCode);
//#endif
//#ifndef MP-WEIXIN
config.children[i].title =
this.$t(config.children[i].titleI18nCode, config.children[i].title);
//#endif
}
}
}
if (item.headerI18nCode) {
//#ifdef MP-WEIXIN
item.header = this.$t(item.headerI18nCode);
//#endif
//#ifndef MP-WEIXIN
item.header = this.$t(item.headerI18nCode, item.header);
//#endif
}
}
if (config.jnpfKey === 'table') {
if (config.children && config.children.length) {
for (let i = 0; i < config.children.length; i++) {
this.initI18n(config.children[i])
}
}
}
},
handleTab() {
if (this.config.jnpfKey === 'steps') return this.stepCurrent = this.config.active
if (this.config.jnpfKey !== 'tab') return
for (var i = 0; i < this.config.children.length; i++) {
if (this.config.active == this.config.children[i].name) {
this.tabCurrent = i
break
}
}
},
getDataChange() {
if (this.config.jnpfKey === 'relationForm' && this.config.defaultValue) {
let query = {
id: this.formData[this.item.__vModel__ + '_id'],
};
if (this.item.propsValue) query = {
...query,
propsValue: this.item.propsValue
};
getRelationFormDetail(this.item.modelId, query).then(res => {
if ((!res.data || !res.data.data) || res.data.data === "undefined") return
let data = JSON.parse(res.data?.data)
this.extraObj = data
})
}
},
getDataInterfaceDataInfoByIds() {
if (this.config.jnpfKey === 'popupSelect' && this.config.defaultValue) {
let query = {
ids: [this.config.defaultValue],
interfaceId: this.item.interfaceId,
propsValue: this.item.propsValue,
relationField: this.item.relationField,
paramList: this.getParamList()
}
getDataInterfaceDataInfoByIds(this.item.interfaceId, query).then(res => {
const data = res.data && res.data.length ? res.data[0] : {};
this.extraObj = data
})
}
},
getParamList() {
let templateJson = this.item.templateJson
if (!this.formData) return templateJson
for (let i = 0; i < templateJson.length; i++) {
if (templateJson[i].relationField && templateJson[i].sourceType == 1) {
if (templateJson[i].relationField.includes('-')) {
let tableVModel = templateJson[i].relationField.split('-')[0]
let childVModel = templateJson[i].relationField.split('-')[1]
templateJson[i].defaultValue = this.formData[tableVModel] && this.formData[tableVModel][this
.rowIndex
] && this.formData[tableVModel][this.rowIndex][childVModel] || ''
} else {
templateJson[i].defaultValue = this.formData[templateJson[i].relationField] || ''
}
}
}
return templateJson
},
handleSummary() {
if (this.item.__config__.jnpfKey !== 'table') return
const val = this.item.__config__.defaultValue
let summaryField = this.item.summaryField || []
this.summaryField = []
this.tableData = this.item.__config__.children || []
for (let i = 0; i < summaryField.length; i++) {
for (let o = 0; o < this.tableData.length; o++) {
const item = this.tableData[o]
if (this.tableData[o].__vModel__ === summaryField[i] && !item.__config__.noShow) {
this.summaryField.push({
value: '',
...item
})
}
}
}
this.$nextTick(() => this.getTableSummaries(val, this.item))
},
toThousands(val, column) {
if (val) {
let valList = val.toString().split('.')
let num = Number(valList[0])
let newVal = column.thousands ? num.toLocaleString() : num
return valList[1] ? newVal + '.' + valList[1] : newVal
} else {
return val
}
},
getTableSummaries(newVal, config) {
for (let i = 0; i < this.summaryField.length; i++) {
let val = 0
for (let j = 0; j < newVal.length; j++) {
if (newVal[j][this.summaryField[i].__vModel__]) {
let data = isNaN(newVal[j][this.summaryField[i].__vModel__]) ? 0 :
Number(newVal[j][this.summaryField[i].__vModel__])
val += data
}
}
let realVal = val && !Number.isInteger(val) ? Number(val).toFixed(2) : val;
if (this.summaryField[i].thousands) realVal = Number(realVal).toLocaleString('zh')
this.summaryField[i].value = realVal
}
},
clickIcon(e) {
this.$emit('clickIcon', e)
},
onTabChange(index) {
if (this.tabCurrent === index) return
this.tabCurrent = index;
this.$emit('tab-change', this.item, index)
this.$nextTick(() => {
uni.$emit('initCollapse')
uni.$emit('updateCode')
})
},
doPreviewImage(current, imageList) {
const images = imageList.map(item => this.define.baseURL + item.url);
uni.previewImage({
urls: images,
current: current,
success: () => {},
fail: () => {
uni.showToast({
title: '预览图片失败',
icon: 'none'
});
}
});
},
toDetail(item) {
const data = {
...item,
...(item.__config__.jnpfKey === 'relationForm' ? {
sourceRelationForm: true,
propsValue: item.propsValue
} : {})
};
this.$emit('toDetail', data)
},
toTableDetail(item, value) {
item.__config__.defaultValue = value
this.$emit('toDetail', item)
},
getValue(item) {
if (Array.isArray(item.__config__.defaultValue)) {
if (['timeRange', 'dateRange'].includes(item.__config__.jnpfKey)) {
return item.__config__.defaultValue.join('')
}
return item.__config__.defaultValue.join()
}
return item.__config__.defaultValue
},
}
}
</script>
<style lang="scss">
.detail-text-box {
width: 100%;
}
</style>

View File

@@ -0,0 +1,68 @@
<template>
<u-form class="jnpf-wrap-form" :model="formData" ref="dataForm"
:label-position="formConf.labelPosition==='top'?'top':'left'"
:label-align="formConf.labelPosition==='right'?'right':'left'"
:label-width="formConf.labelWidth?formConf.labelWidth*1.5:150" :class='formConf.className'>
<template v-for="(item, index) in formConf.fields" :key="item.__config__.renderKey">
<Item :itemData="item" :formConf="formConf" :class="item.__config__.className" :formData="formData"
:ref="item.__vModel__?item.__vModel__: undefined" @toDetail="toDetail" @clickIcon='clickIcon' />
</template>
<u-modal v-model="show" :content="content" width='70%' border-radius="16" :content-style="contentStyle"
:titleStyle="titleStyle" :confirm-style="confirmStyle" :title="title" :confirm-text="$t('common.okText')">
</u-modal>
</u-form>
</template>
<script>
import Item from './Item'
export default {
components: {
Item
},
props: {
formConf: {
type: Object,
required: true
},
formData: {
type: Object,
},
loading: {
type: Boolean,
default: false
}
},
data() {
return {
show: false,
content: '',
contentStyle: {
fontSize: '28rpx',
padding: '20rpx',
lineHeight: '44rpx',
textAlign: 'left'
},
titleStyle: {
padding: '20rpx'
},
confirmStyle: {
height: '80rpx',
lineHeight: '80rpx',
},
title: this.$t('common.tipTitle'),
}
},
methods: {
clickIcon(e) {
if (!e.__config__.tipLabel && !e.helpMessage) return
this.content = e.helpMessage || e.__config__.tipLabel
this.title = e.__config__.label
if (e.__config__.jnpfKey === 'card') this.title = e.header
if (e.__config__.jnpfKey === 'groupTitle') this.title = e.content
this.show = true
},
toDetail(item) {
this.$emit('toDetail', item)
}
}
}
</script>

View File

@@ -0,0 +1,179 @@
<template>
<view class="jnpf-wrap jnpf-wrap-form">
<JnpfParser v-if="!loading" ref="dynamicForm" :formConf="formConf" :key="key" @submit="sumbitForm" />
<view class="buttom-actions" v-if="origin !='scan'">
<u-button class="buttom-btn" @click.stop="resetForm">{{$t('common.resetText')}}</u-button>
<u-button class="buttom-btn" type="primary" @click.stop="submit" :loading="btnLoading">
{{getOkText}}
</u-button>
</view>
</view>
</template>
<script>
import {
createModel,
getModelInfo
} from '@/api/apply/visualDev'
export default {
props: ['config', 'modelId', 'isPreview', 'origin', 'id'],
data() {
return {
dataForm: {
data: ''
},
formConf: {},
key: +new Date(),
btnLoading: false,
loading: true,
isAdd: false,
userInfo: {}
}
},
computed: {
getOkText() {
const text = this.formConf.confirmButtonTextI18nCode ?
this.$t(this.formConf.confirmButtonTextI18nCode, this.formConf.confirmButtonText) :
this.formConf.confirmButtonText;
return text || this.$t('common.okText');
},
},
created() {
this.init()
},
methods: {
init() {
this.userInfo = uni.getStorageSync('userInfo') || {}
this.formConf = JSON.parse(this.config.formData)
this.loading = true
this.initData()
},
initData() {
this.$nextTick(() => {
if (this.origin === 'scan') {
let extra = {
modelId: this.modelId,
id: this.id,
type: 2
}
uni.setStorageSync('dynamicModelExtra', extra)
getModelInfo(this.modelId, this.id).then(res => {
this.dataForm = res.data
if (!this.dataForm.data) return
this.formData = JSON.parse(this.dataForm.data)
this.fillFormData(this.formConf, this.formData)
this.$nextTick(() => {
this.loading = false
})
})
} else {
this.formData = {}
this.loading = false
this.isAdd = true
this.fillFormData(this.formConf, this.formData)
}
this.key = +new Date()
})
},
fillFormData(form, data) {
const loop = list => {
for (let i = 0; i < list.length; i++) {
let item = list[i]
let vModel = item.__vModel__
let config = item.__config__
if (vModel) {
let val = data.hasOwnProperty(vModel) ? data[vModel] : config.defaultValue
if (!config.isSubTable) config.defaultValue = val
if (this.isAdd || config.isSubTable) { //新增时候,默认当前
if (config.defaultCurrent) {
if (config.jnpfKey === 'datePicker') {
if (!data.hasOwnProperty(vModel)) {
let format = this.jnpf.handelFormat(item.format)
let dateStr = this.jnpf.toDate(new Date().getTime(), format)
let time = format === 'yyyy' ? '-01-01 00:00:00' : format === 'yyyy-MM' ?
'-01 00:00:00' : format === 'yyyy-MM-dd' ?
' 00:00:00' : ''
val = new Date(dateStr + time).getTime()
config.defaultValue = val
}
}
if (config.jnpfKey === 'timePicker') {
if (!data.hasOwnProperty(vModel)) {
config.defaultValue = this.jnpf.toDate(new Date(), item.format)
}
}
if (config.jnpfKey === 'organizeSelect' && this.userInfo.organizeIds?.length) {
config.defaultValue = item.multiple ? this.userInfo.organizeIds :
this.userInfo.organizeId
}
if (config.jnpfKey === 'posSelect' && this.userInfo.positionIds?.length) {
config.defaultValue = item.multiple ? this.userInfo.positionIds :
this.userInfo.positionId
}
const userId = this.userInfo.userId
if (config.jnpfKey === 'userSelect' && userId) {
config.defaultValue = item.multiple ? [userId] : userId;
}
if (config.jnpfKey === 'usersSelect' && userId) {
config.defaultValue = [userId + '--user'];
}
if (config.jnpfKey === 'sign' && this.userInfo.signImg) {
config.defaultValue = this.userInfo.signImg
}
}
}
if (this.origin === 'scan') this.$set(item, 'disabled', true)
let noShow = !config.noShow ? false : config.noShow
let isVisibility = false
if (!config.visibility || (Array.isArray(config.visibility) && config.visibility.includes(
'app'))) isVisibility = true
this.$set(config, 'isVisibility', isVisibility)
this.$set(config, 'noShow', noShow)
} else {
let noShow = false,
isVisibility = false
if (!config.visibility || (Array.isArray(config.visibility) && config.visibility.includes(
'app'))) isVisibility = true
this.$set(config, 'isVisibility', isVisibility)
this.$set(config, 'noShow', noShow)
}
if (config && config.children && Array.isArray(config.children)) loop(config.children)
}
}
loop(form.fields)
},
sumbitForm(data, callback) {
if (!data) return
this.btnLoading = true
this.dataForm.data = JSON.stringify(data)
if (callback && typeof callback === "function") callback()
createModel(this.modelId, this.dataForm).then(res => {
uni.showToast({
title: res.msg,
complete: () => {
setTimeout(() => {
this.btnLoading = false
uni.navigateBack()
}, 1500)
}
})
}).catch(() => {
this.btnLoading = false
})
},
submit() {
if (this.isPreview) return this.$u.toast('功能预览不支持数据保存')
this.$refs.dynamicForm && this.$refs.dynamicForm.submitForm()
},
resetForm() {
this.loading = true
this.$nextTick(() => {
this.loading = false
this.$refs.dynamicForm && this.$refs.dynamicForm.resetForm()
this.init()
this.key = +new Date()
})
}
}
}
</script>

View File

@@ -0,0 +1,937 @@
<template>
<view class="dynamicModel-list-v">
<!-- 批量删除顶部弹窗 -->
<view class="u-flex top-btn" :class="slide2" v-show="selectItems.length">
<view class="button-left" @click.stop="cancel">
<p class="u-m-t-10 u-font-28">{{$t('common.cancelText')}}</p>
</view>
<view class="button-center">
<p class="u-m-t-10 u-font-28">{{$t('component.jnpf.common.selected')}}({{selectItems.length}})</p>
</view>
<view class="button-right u-m-t-12" @click.stop="checkAll">
<p class="icon-ym icon-ym-app-checkAll " :style="{'color':this.checkedAll ? '#0293fc' : '#303133'}">
</p>
</view>
</view>
<!-- 排序 -->
<view class="head-warp com-dropdown">
<u-dropdown class="u-dropdown" ref="uDropdown" @open="showTop = true" @close="showTop = false">
<u-dropdown-item :title="$t('app.apply.sort')" :options="sortOptions">
<view class="screen-box">
<view class="screen-list" v-if="sortOptions.length">
<view class="u-p-l-20 u-p-r-20 list">
<scroll-view scroll-y="true" style="height: 100%;">
<u-cell-group :border="false">
<u-cell-item @click="cellClick(item)" :arrow="false" :title="item.label"
v-for="(item, index) in sortOptions" :key="index" :title-style="{
color: sortValue.includes(item.value) ? '#2979ff' : '#606266' }">
<u-icon v-if="sortValue.includes(item.value)" name="checkbox-mark"
color="#2979ff" size="32" />
</u-cell-item>
</u-cell-group>
</scroll-view>
</view>
</view>
<JnpfEmpty v-else></JnpfEmpty>
<view class="buttom-actions" v-if="sortOptions.length">
<u-button class="buttom-btn" @click="handleSortReset">{{$t('common.cleanText')}}</u-button>
<u-button class="buttom-btn" type="primary" @click="handleSortSearch">
{{$t('common.okText')}}
</u-button>
</view>
</view>
</u-dropdown-item>
<!-- 筛选 -->
<u-dropdown-item :title="$t('app.apply.screen')">
<view class="screen-box u-flex-col">
<view class="screen-list" v-if="showParser && searchFormConf.length">
<view class="u-p-l-20 u-p-r-20 list">
<scroll-view scroll-y="true" style="height: 100%;">
<Parser :formConf="searchFormConf" :searchFormData="searchFormData"
:webType="config.webType" ref="searchForm" @submit="sumbitSearchForm" />
</scroll-view>
</view>
<view class="u-flex screen-btn" v-if="showParser && searchFormConf.length">
<text @click="handleReset" class="btn btn1">{{$t('common.resetText')}}</text>
<text @click="handleSearch" class="btn btn2">{{$t('common.searchText')}}</text>
</view>
</view>
<JnpfEmpty v-else></JnpfEmpty>
</view>
</u-dropdown-item>
</u-dropdown>
</view>
<view class="u-m-b-20">
<u-tabs :list="tabList" v-model="tabActiveKey" font-size="28" @change="onTabChange" height="80"
name="fullName" v-show="showTabs">
</u-tabs>
</view>
<!-- 列表 -->
<view class="list-warp">
<mescroll-uni ref="mescrollRef" @init="mescrollInit" @down="downCallback" @up="upCallback"
:down="downOption" :up="upOption" :bottombar="false"
:top="(columnData.tabConfig && columnData.tabConfig.on && tabList.length) ? 190 : 100">
<list ref="list" :list="list" :columnList="columnList" :config="config" :actionOptions="actionOptions"
@relationFormClick="relationFormClick" @goDetail="goDetail" @handleMoreClick="handleMoreClick"
@handleClick="handleClick" :showSelect="isShowBatch.length" :checkedAll="checkedAll"
@selectCheckbox="selectCheckbox" :isMoreBtn="isMoreBtn" :customBtnsList="columnData.customBtnsList">
</list>
</mescroll-uni>
</view>
<view v-if="!showTop">
<!-- 新增按钮 -->
<view v-if="config.webType !=4">
<view class="com-addBtn"
v-if="isPreview||(permission.btnPermission && permission.btnPermission.includes('btn_add'))"
@click="addPage()">
<u-icon name="plus" size="48" color="#fff" />
</view>
</view>
</view>
<u-select :list="listInnerBtn" v-model="showMoreBtn" @confirm="selectBtnconfirm" />
<u-select :list="bottomCustomBtnsList[1]" v-model="showBottomMoreBtn" @confirm="bottomBtnConfirm" />
<!-- 批量操作底部弹窗 -->
<view class="u-flex bottom-btn" :class="isShowBatch?.length==1? 'bottom-btn-one ':'bottom-btn-multiple'"
v-if="(isShowBatch.length && list.length) || (bottomCustomBtnsList && bottomCustomBtnsList[0].length)">
<view class="button-preIcon" @click.stop="handleBottomMoreClick('down')"
v-if="bottomCustomBtnsList[1].length">
<u-icon name="more-dot-fill" class="u-m-b-8" size="34"></u-icon>
<p class="u-font-24">{{$t('common.moreText')}}</p>
</view>
<!-- 自定义按钮 -->
<view class="button-preIcon" v-for="(item,i) in bottomCustomBtnsList[0]" :key="i"
@click="bottomBtnConfirm(item)">
<p class="btn-icon u-m-b-8" :class="item.event.btnIcon">
</p>
<p class="u-m-t-8 u-font-22 u-line-1">{{item.label}}</p>
</view>
<!-- 批量删除 -->
<view class="button-preIcon" @click.stop="batchDelete" v-if="isBatchRemove && list.length">
<p class="icon-ym icon-ym-app-delete u-m-b-8"></p>
<p class="u-m-t-10 u-font-22">{{$t('common.batchDelText')}}</p>
</view>
</view>
</view>
</template>
<script>
import {
useBaseStore
} from '@/store/modules/base'
const baseStore = useBaseStore()
import list from './list.vue'
import resources from '@/libs/resources.js'
import MescrollMixin from "@/uni_modules/mescroll-uni/components/mescroll-uni/mescroll-mixins.js";
import bulkOperationMixin from "../../bulkOperationMixin.js";
import jnpf from "@/utils/jnpf";
import Parser from '../parser/index.vue'
import {
getModelList,
deteleModel,
getModelInfo,
launchFlow
} from '@/api/apply/visualDev'
import {
getDataInterfaceRes
} from '@/api/common'
import deepClone from '../../../../../uni_modules/vk-uview-ui/libs/function/deepClone';
import {
useDefineSetting
} from '@/utils/useDefineSetting';
export default {
mixins: [MescrollMixin, bulkOperationMixin],
props: ['config', 'modelId', 'isPreview', 'title', 'menuId'],
components: {
Parser,
list
},
data() {
return {
tabActiveKey: 0,
tabList: [],
tabQueryJson: {},
sortValue: [],
downOption: {
use: true,
auto: false
},
upOption: {
page: {
num: 0,
size: 10,
time: null
},
empty: {
use: true,
icon: resources.message.nodata,
tip: this.$t('common.noData'),
fixed: true
},
textNoMore: this.$t('app.apply.noMoreData'),
},
list: [],
listQuery: {
sidx: '',
keyword: '',
queryJson: ''
},
actionOptions: [],
showParser: false,
columnData: {},
columnList: [],
sortList: [],
sortOptions: [],
searchList: [],
searchFormConf: [],
permission: {},
selectListIndex: 0,
showBottomMoreBtn: false,
showMoreBtn: false,
properties: {},
flowId: '',
key: +new Date(),
userInfo: {},
searchFormData: {},
enableFunc: {},
selectItems: [],
listInnerBtn: [],
listTopBtn: [],
useDefine: useDefineSetting()
}
},
created() {
this.init()
},
computed: {
showBatchOperate() {
return this.list.length && (this.isBatchRemove || this.listTopBtn.length)
},
isBatchRemove() {
return this.columnData.btnsList.find(item => item.value === "batchRemove" && item.show)
},
showTabs() {
return this.columnData?.tabConfig?.on && this.tabList.length
},
/* 底部自定义按钮 */
bottomCustomBtnsList() {
if (this.listTopBtn.length <= 3) return [this.listTopBtn, []];
const firstArray = this.listTopBtn.slice(0, 3);
const secondArray = this.listTopBtn.slice(3);
return [firstArray, secondArray];
},
getRowKey() {
return this.config.webType == 4 && this.columnData.viewKey ? this.columnData.viewKey : 'id'
},
isMoreBtn() {
return this.columnData?.customBtnsList?.some(item => item.event?.btnType === 2);
},
isShowBatch() {
const list = this.filterEmpty([this.isBatchRemove, ...this.bottomCustomBtnsList])
return list.filter(i => i !== undefined)
},
customBtnsList() {
return this.columnData?.customBtnsList?.some(item => item.event?.btnType === 1);
}
},
methods: {
filterEmpty(arr) {
return arr.filter(item => {
// 处理数组情况
if (Array.isArray(item)) return item.length > 0;
// 处理对象情况
if (typeof item === 'object' && item !== null) return Object.keys(item).length > 0;
// 其他情况保留
return true;
});
},
selectCheckbox(data) {
this.selectItems = data
},
init() {
this.userInfo = uni.getStorageSync('userInfo') || {};
this.properties = this.config.flowTemplateJson ? JSON.parse(this.config.flowTemplateJson).properties : {};
let columnDataStr = this.config?.appColumnData || '[]';
try {
this.columnData = JSON.parse(columnDataStr);
} catch (e) {
this.columnData = [];
}
this.permission = this.$permission.getPermission(this.columnData, this.menuId, this.jnpf.getScriptFunc);
this.enableFunc = this.permission.enableFunc;
this.upOption.page.size = this.columnData.hasPage ? this.columnData.pageSize : 1000000;
this.setDefaultQuery();
this.columnList = this.permission.columnPermission || [];
this.columnData.customBtnsList = this.permission.customBtnsPermission || [];
this.columnData.customBtnsList.map((o) => {
if (o.labelI18nCode) o.label = this.$t(o.labelI18nCode)
})
this.setBtns()
this.columnList = this.transformColumnList(this.columnList)
this.columnList.map((o) => {
if (o.labelI18nCode) o.label = this.$t(o.labelI18nCode)
// if (o.jnpfKey != 'table' && o.label.length > 4) o.label = o.label.substring(0, 4)
})
this.sortList = this.columnList.filter(o => o.sortable)
this.getTabList();
this.handleSearchList()
this.handleSortList()
this.handleDeleteBtn()
this.key = +new Date()
},
setBtns() {
const buttons = {
inner: [],
top: []
};
this.columnData.customBtnsList.forEach(item => {
const key = item.event.position === 2 ? 'top' : 'inner';
buttons[key].push(item);
});
this.listInnerBtn = buttons.inner;
this.listTopBtn = buttons.top;
},
upCallback(page) {
if (this.isPreview == '1') return this.mescroll.endSuccess(0, false);
const query = {
currentPage: page.num,
pageSize: page.size,
menuId: this.menuId,
modelId: this.modelId,
...this.listQuery
}
getModelList(this.modelId, query, {
load: page.num == 1
}).then(res => {
this.selectItems = []
this.$nextTick(() => {
this.$refs.list.handleCheckAll()
})
this.showParser = true
if (page.num == 1) this.list = [];
this.mescroll.endSuccess(res.data.list.length);
const list = res.data.list.map((o, i) => ({
checked: false,
index: i,
...o
}));
this.list = this.list.concat(list);
this.$nextTick(() => {
if (this.columnData.funcs && this.columnData.funcs.afterOnload) this
.setTableLoadFunc()
})
if (!this.selectItems.length || !this.list.length) this.cancel()
}).catch((err) => {
this.mescroll.endByPage(0, 0);
this.mescroll.endErr();
})
},
//获取标签面板数据、设置标签面板默认值
async getTabList() {
this.tabList = [];
if (!this.columnData.tabConfig) return;
const list = this.columnData.columnOptions.filter(o => o.__vModel__ == this.columnData.tabConfig
.relationField) || [];
if (list?.length) {
this.columnData.tabConfig?.hasAllTab && this.tabList.push({
fullName: '全部',
id: undefined
});
if (list[0].__config__.dataType == 'dictionary' && list[0].__config__.dictionaryType) {
const data = await baseStore.getDicDataSelector(list[0].__config__.dictionaryType) || [];
const options = list[0].props.value == 'enCode' ? data.map(o => ({
...o,
id: o.enCode
})) : data;
this.tabList = [...this.tabList, ...options];
} else {
this.tabList = [...this.tabList, ...list[0].options];
}
}
this.tabActiveKey = 0;
this.onTabChange(this.tabActiveKey)
},
onTabChange(val) {
const {
hasAllTab,
relationField
} = this.columnData.tabConfig;
const currentTab = this.tabList[val];
// 合并条件判断
const shouldSetRelation = !hasAllTab || val !== 0;
this.tabActiveKey = val;
this.tabQueryJson = shouldSetRelation ? {
[relationField]: currentTab.id
} : {};
// 使用可选链操作符和空对象兜底
const search = this.$refs.searchForm?.allCondition() || {};
this.listQuery.queryJson = JSON.stringify({
...search,
...this.tabQueryJson
});
this.initData();
},
handleSearchForm(data) {
let newData = {};
for (let key in data) {
if (data.hasOwnProperty(key)) {
if (typeof data[key] === 'object' && data[key] !== null) {
for (let innerKey in data[key]) {
if (data[key].hasOwnProperty(innerKey)) {
let newKey = `${key}-${innerKey}`;
newData[newKey] = data[key][innerKey];
}
}
} else {
newData[key] = data[key];
}
}
}
return newData
},
sumbitSearchForm(data) {
let queryJson = data || {}
this.searchFormData = data
// 标签面板查询
if (this.columnData.tabConfig && this.columnData.tabConfig.on) {
this.tabQueryJson = {
[this.columnData.tabConfig.relationField]: this.tabList[this.tabActiveKey]?.id
};
queryJson = {
...queryJson,
...this.tabQueryJson
}
}
this.listQuery.queryJson = JSON.stringify(queryJson) !== '{}' ? JSON.stringify(queryJson) : ''
this.$refs.uDropdown.close();
this.$nextTick(() => {
this.list = [];
this.mescroll.resetUpScroll();
})
},
// 处理启用规则
customEnableRule(data, funcName) {
// #ifdef MP-WEIXIN
return true
// #endif
// #ifndef MP-WEIXIN
let func = this.enableFunc[funcName]
if (!func) return false
let res = func.call(this, {
row: data,
rowIndex: data.index,
onlineUtils: this.jnpf.onlineUtils,
})
return res
// #endif
},
handleDeleteBtn() {
if (this.config.webType == 4) return
const actionOptions = this.columnData.columnBtnsList.filter(o => o.value == 'remove' && o.show)
this.actionOptions = actionOptions.map(o => ({
...o,
//#ifdef MP-WEIXIN
text: o.labelI18nCode ? this.$t(o.labelI18nCode) : o.label,
//#endif
//#ifndef MP-WEIXIN
text: o.labelI18nCode ? this.$t(o.labelI18nCode, o.label) : o.label,
//#endif
style: {
backgroundColor: '#dd524d'
}
}))
},
handleSearchList() {
this.searchList = (this.$u.deepClone(this.columnData.searchList) || []).filter(o => !o.noShow)
for (let i = 0; i < this.searchList.length; i++) {
const item = this.searchList[i]
if (item.labelI18nCode) {
item.label = this.$t(item.labelI18nCode)
item.placeholder = this.$t(item.labelI18nCode)
}
const config = item.__config__
const now = new Date()
jnpf.setSearchDefaultValue(item, now)
if (item.value != null && item.value != '' && item.value != []) {
this.searchFormData[item.id] = item.value;
}
if (this.config.webType == 4) config.label = item.label
}
if (Object.keys(this.searchFormData).length) this.listQuery.queryJson = JSON.stringify(this.searchFormData)
if (this.searchList.some(o => o.isKeyword)) {
const keywordItem = {
id: 'jnpfKeyword',
fullName: '关键词',
prop: 'jnpfKeyword',
label: this.$t('common.keyword'),
jnpfKey: 'input',
clearable: true,
placeholder: '请输入',
value: undefined,
__config__: {
jnpfKey: 'input'
},
};
this.searchList.unshift(keywordItem);
}
if (this.config.enableFlow && this.searchList.length) {
const flowStateItem = {
id: 'jnpfFlowState',
fullName: '状态',
prop: 'jnpfFlowState',
label: '状态',
jnpfKey: 'select',
placeholder: '请选择状态',
value: undefined,
options: this.useDefine.flowStatusList,
__config__: {
jnpfKey: 'select',
},
};
this.searchList.push(flowStateItem);
}
this.searchFormConf = this.$u.deepClone(this.searchList)
},
handleSortList() {
this.sortOptions = [];
const sortList = this.sortList
for (let i = 0; i < sortList.length; i++) {
let ascItem = {
label: sortList[i].label + ' ' + this.$t('app.apply.ascendingOrder'),
value: sortList[i].prop,
sidx: sortList[i].prop,
sort: 'asc'
}
let descItem = {
label: sortList[i].label + ' ' + this.$t('app.apply.descendingOrder'),
value: '-' + sortList[i].prop,
sidx: sortList[i].prop,
sort: 'desc'
}
this.sortOptions.push(ascItem, descItem)
}
},
transformColumnList(columnList) {
let list = []
for (let i = 0; i < columnList.length; i++) {
const e = columnList[i];
if (!e.prop.includes('-')) {
e.option = null
list.push(e)
} else {
let prop = e.prop.split('-')[0]
let vModel = e.prop.split('-')[1]
let label = e.label.split('-')[0]
let childLabel = e.label.replace(label + '-', '');
if (e.fullNameI18nCode && Array.isArray(e.fullNameI18nCode) && e.fullNameI18nCode[0]) {
label = this.$t(e.fullNameI18nCode[0], label);
}
let newItem = {
align: "center",
jnpfKey: "table",
prop,
label,
children: []
}
e.vModel = vModel
e.childLabel = e.labelI18nCode ? this.$t(e.labelI18nCode) : childLabel;
if (!list.some(o => o.prop === prop)) list.push(newItem)
for (let i = 0; i < list.length; i++) {
if (list[i].prop === prop) {
e.option = null
list[i].children.push(e)
break
}
}
}
}
return list
},
setDefaultQuery() {
const defaultSortConfig = (this.columnData.defaultSortConfig || []).map(o =>
(o.sort === 'desc' ? '-' : '') + o.field);
this.listQuery.sidx = defaultSortConfig.join(',')
},
setTableLoadFunc() {
const JNPFTable = this.$refs.tableRef
const parameter = {
data: this.list,
tableRef: JNPFTable,
onlineUtils: this.jnpf.onlineUtils,
}
const func = this.jnpf.getScriptFunc.call(this, this.columnData.funcs.afterOnload)
if (!func) return
func.call(this, parameter)
},
//删除操作
handleClick(index) {
const item = this.list[index]
if (!this.permission.btnPermission.includes('btn_remove')) return this.$u.toast("未开启删除权限")
if (!this.customEnableRule(item, 'remove')) return this.$u.toast("没有删除权限")
let txt = '流程处于暂停状态,不可操作'
if ([1, 2, 3, 4, 6, 7, 8].includes(item.flowState)) txt = '流程已受理,无法删除'
uni.showModal({
title: '提示',
content: '删除后数据无法恢复',
success: (res) => {
if (res.confirm) {
if (this.config.enableFlow == 1 && ![0, 9].includes(item.flowState)) {
this.$u.toast(txt)
return
}
let data = {
flowId: this.config.flowId,
ids: [item.id]
}
deteleModel(data, this.modelId).then(res => {
this.$u.toast(res.msg)
this.list.splice(index, 1)
this.mescroll.resetUpScroll()
})
}
}
})
},
//底部更多按钮
handleBottomMoreClick(type) {
this.showBottomMoreBtn = true
},
//更多按钮弹窗
handleMoreClick(index) {
this.selectListIndex = index
this.showMoreBtn = true
},
//底部按钮操作
bottomBtnConfirm(e) {
if (Array.isArray(e) && e.length) {
const index = this.bottomCustomBtnsList[1].findIndex(item => item.value === e[0].value);
const item = this.bottomCustomBtnsList[1][index];
if (!this.selectItems.length && item.event.dataRequired) {
return this.$u.toast('请选择一条数据')
}
if (item.event && item.event.btnType === 3) this.handleBottomBtnInterface(item.event);
if (item.event.btnType == 2) this.handleScriptFunc(item.event, this.selectItems)
if (item.event.btnType == 4) this.handleLaunchFlow(item, this.selectItems)
} else {
if (!this.selectItems.length && e.event.dataRequired) {
return this.$u.toast('请选择一条数据')
}
// 当e是一个对象且包含event属性时
if (e.event.btnType == 2) this.handleScriptFunc(e.event, this.selectItems)
if (e.event.btnType === 3) this.handleBottomBtnInterface(e.event);
if (e.event.btnType == 4) this.handleLaunchFlow(e, this.selectItems)
}
},
//底部自定义按钮接口操作
handleBottomBtnInterface(item) {
const selectedItemsCopy = [...this.selectItems];
const webType = this.config.webType;
let data = {
items: selectedItemsCopy,
webType
};
const handlerInterface = (data) => {
let query = {
paramList: this.jnpf.getBatchParamList(item.templateJson, data) || [],
}
getDataInterfaceRes(item.interfaceId, query).then(res => {
uni.showToast({
title: res.msg,
icon: 'none'
})
})
}
if (!item.useConfirm) return handlerInterface(data)
uni.showModal({
title: this.$t('common.tipTitle'),
content: item.confirmTitle || '确认执行此操作?',
showCancel: true,
confirmText: '确定',
success: function(res) {
if (res.confirm) {
handlerInterface(data)
}
}
});
},
// 自定义按钮事件
selectBtnconfirm(e) {
var i = this.columnData.customBtnsList.findIndex((item) => {
return item.value == e[0].value
})
const item = this.columnData.customBtnsList[i]
const row = this.list[this.selectListIndex]
const index = this.selectListIndex
// 自定义启用规则判断
if (!this.customEnableRule(row, item.value)) return this.$u.toast('没有' + item.label + '权限')
if (item.event.btnType == 1) this.handlePopup(item.event, row)
if (item.event.btnType == 2) this.handleScriptFunc(item.event, row, index)
if (item.event.btnType == 3) this.handleInterface(item.event, row)
if (item.event.btnType == 4) this.handleLaunchFlow(item, [row])
},
//自定义按钮发起流程
handleLaunchFlow(item, records) {
const data = deepClone(item.event.launchFlow)
let dataList = [];
for (let i = 0; i < records.length; i++) {
dataList.push(this.jnpf.getLaunchFlowParamList(data.transferList, records[i], this.getRowKey));
}
const query = {
template: data.flowId,
btnCode: item.value,
currentUser: data.currentUser,
customUser: data.customUser,
initiator: data.initiator,
hasPermission: data.hasPermission,
dataList,
};
launchFlow(query, this.modelId).then(res => {
this.$u.toast(res.msg)
});
},
//自定义按钮弹窗操作
handlePopup(item, row) {
this.handleListen()
let data = {
config: item,
modelId: this.modelId,
id: this.config.webType == 4 ? '' : row[this.getRowKey],
isPreview: this.isPreview,
row: this.config.webType == 4 ? row : '',
}
data = encodeURIComponent(JSON.stringify(data))
uni.navigateTo({
url: '/pages/apply/customBtn/index?data=' + data
})
},
//自定义按钮JS操作
handleScriptFunc(item, row, index) {
const parameter = {
data: row,
index,
refresh: this.initData,
onlineUtils: this.jnpf.onlineUtils,
}
const func = this.jnpf.getScriptFunc.call(this, item.func)
if (!func) return
func.call(this, parameter)
},
//自定义按钮接口操作
handleInterface(item, row) {
const handlerData = () => {
getModelInfo(this.modelId, row[this.getModelInfo]).then(res => {
const dataForm = res.data || {};
if (!dataForm.data) return;
const data = {
...JSON.parse(dataForm.data),
id: row[this.getModelInfo]
};
handlerInterface(data);
})
}
const handlerInterface = (data) => {
let query = {
paramList: this.jnpf.getParamList(item.templateJson, {
...data,
id: row[this.getRowKey]
}, this.getRowKey) || [],
}
getDataInterfaceRes(item.interfaceId, query).then(res => {
uni.showToast({
title: res.msg,
icon: 'none'
})
if (item.isRefresh) this.initData();
})
}
const handleFun = () => {
this.config.webType == '4' ? handlerInterface(row) : handlerData();
};
if (!item.useConfirm) return handleFun()
uni.showModal({
title: '提示',
content: item.confirmTitle || '确认执行此操作',
success: (res) => {
if (!res.cancel) handleFun()
}
})
},
initData() {
this.list = [];
this.$nextTick(() => {
this.mescroll.resetUpScroll();
})
},
search() {
if (this.isPreview == '1') return
this.searchTimer && clearTimeout(this.searchTimer)
this.searchTimer = setTimeout(() => {
this.list = [];
this.mescroll.resetUpScroll();
}, 300)
},
handleListen() {
uni.$off('refresh')
uni.$on('refresh', () => {
this.list = [];
this.mescroll.resetUpScroll();
})
},
addPage() {
this.handleListen()
this.jumPage({}, '')
},
jumPage(item, btnType) {
if (!item.id && !item.flowState) btnType = 'btn_add'
if (this.config.enableFlow == 1) {
if (item.id) {
if (!this.permission.btnPermission.includes('btn_edit') && item.flowState == 3) return
if (!this.permission.btnPermission.includes('btn_detail') && ![0, 8, 9].includes(item
.flowState))
return
}
let opType = '-1'
if (![0, 8, 9].includes(item.flowState) && btnType != 'btn_add') opType = 0
const config = {
id: item.flowTaskId || item.id || '',
flowId: this.config.flowId,
opType,
status: item.flowState || '',
isPreview: this.isPreview,
taskId: item.flowTaskId || item.id,
isFlow: 0,
}
uni.navigateTo({
url: '/pages/workFlow/flowBefore/index?config=' +
this.jnpf.base64.encode(JSON.stringify(config))
})
} else {
const type = btnType == 'btn_detail' ? 'detail' : 'form'
const currentMenu = encodeURIComponent(JSON.stringify(this.permission.formPermission))
let btnType_ = this.permission.btnPermission.includes('btn_edit') ? 'btn_edit' : 'btn_add'
let enableEdit = this.customEnableRule(item, 'edit')
let labelS = {}
for (let i = 0; i < this.columnData.columnBtnsList.length; i++) {
const item = this.columnData.columnBtnsList[i]
if (item.value == 'edit') {
labelS[btnType_] = item.labelI18nCode ? this.$t(item.labelI18nCode) : item.label
}
}
const config = {
currentMenu,
btnType: btnType_,
list: this.list,
modelId: this.modelId,
menuId: this.menuId,
isPreview: this.isPreview,
id: item.id || '',
index: item.index,
enableEdit,
labelS
}
const url = '/pages/apply/dynamicModel/' + type + '?config=' +
this.jnpf.base64.encode(JSON.stringify(config))
uni.navigateTo({
url: url
})
}
},
goDetail(item) {
if (this.config.webType == 4) return
this.handleListen()
let hasDetail = this.permission.btnPermission.includes('btn_detail')
let hasEdit = this.permission.btnPermission.includes('btn_edit')
if (!hasDetail && !hasEdit) return
if (hasDetail) {
if (this.customEnableRule(item, 'detail')) {
return this.jumPage(item, 'btn_detail')
}
if (this.customEnableRule(item, 'edit')) {
return this.jumPage(item, 'btn_edit')
}
} else {
if (this.customEnableRule(item, 'edit')) {
return this.jumPage(item, 'btn_edit')
}
}
},
cellClick(item) {
if (this.isPreview == '1') return this.$u.toast('功能预览不支持排序')
const findIndex = this.sortValue.findIndex(o => o === item.value);
if (findIndex < 0) {
const findLikeIndex = this.sortValue.findIndex(o => o.indexOf(item.sidx) > -1);
if (findLikeIndex > -1) this.sortValue.splice(findLikeIndex, 1)
this.sortValue.push(item.value)
} else {
this.sortValue.splice(findIndex, 1)
}
},
handleReset() {
this.searchFormData = {}
const list = ['datePicker', 'timePicker', 'inputNumber', 'calculate', 'cascader', 'usersSelect']
for (let i = 0; i < this.searchList.length; i++) {
const item = this.searchList[i]
const config = item.__config__
let defaultValue = item.searchMultiple || list.includes(config.jnpfKey) ? [] : undefined
if (config.isFromParam) defaultValue = undefined
config.defaultValue = defaultValue
this.searchFormData[item.id] = item.value || defaultValue
}
this.searchFormConf = JSON.parse(JSON.stringify(this.searchList))
},
handleSearch() {
if (this.isPreview == '1') return this.$u.toast('功能预览不支持检索')
this.$refs.searchForm && this.$refs.searchForm.submitForm()
},
relationFormClick(item, column) {
let vModel = column.vModel ? column.vModel : column.__vModel__
let model_id = column.modelId
let config = {
modelId: model_id,
isPreview: true,
id: item[vModel + '_id'],
sourceRelationForm: true,
noShowBtn: 1,
noDataLog: 1,
propsValue: column.propsValue
}
const url =
'/pages/apply/dynamicModel/detail?config=' + this.jnpf.base64.encode(JSON.stringify(config))
uni.navigateTo({
url: url
})
},
handleSortReset() {
this.sortValue = []
},
handleSortSearch() {
if (this.sortValue.length) {
this.listQuery.sidx = this.sortValue.join(',')
} else {
this.setDefaultQuery()
}
this.$refs.uDropdown.close();
this.$nextTick(() => {
this.list = [];
this.mescroll.resetUpScroll();
})
}
}
}
</script>
<style lang="scss">
page {
background-color: #f0f2f6;
height: 100%;
/* #ifdef MP-ALIPAY */
position: absolute;
top: 0;
left: 0;
width: 100%;
/* #endif */
}
:deep(.u-cell) {
padding: 0rpx;
height: 112rpx;
}
</style>

View File

@@ -0,0 +1,219 @@
<template>
<view class="list u-p-b-20 u-p-l-20 u-p-r-20" ref="tableRef">
<view class="list-box">
<SwipeItem :list="list" :buttons="options" @action="actionClick" ref="swipeItem" :marginB="20">
<template v-slot="{ item }">
<view class="item" @tap.stop="goDetail(item)" style="border: 1px solid #fff;">
<view class="u-m-b-10 checkbox_box" v-if="showCheckbox">
<u-checkbox @change="checkboxChange($event,item)" v-model="item.checked" class="checkbox"
@tap.stop shape="circle"></u-checkbox>
</view>
<view class="item-cell" v-for="(column,i) in columnList" :key="i">
<template v-if="column.jnpfKey != 'table'">
<text class="item-cell-label">{{column.label}}:</text>
<text class="item-cell-content"
v-if="['calculate','inputNumber'].includes(column.jnpfKey)">
{{toThousands(item[column.prop],column)}}
</text>
<text class="item-cell-content text-primary"
v-else-if="column.jnpfKey == 'relationForm'"
@click.stop="relationFormClick(item,column)">
{{item[column.prop]}}
</text>
<view class="item-cell-content" v-else-if="column.jnpfKey == 'sign'">
<JnpfSign v-model="item[column.prop]" align="left" detailed />
</view>
<view class="item-cell-content" v-else-if="column.jnpfKey == 'signature'">
<JnpfSignature v-model="item[column.prop]" align="left" detailed />
</view>
<view class="item-cell-content" v-else-if="column.jnpfKey == 'uploadImg'" @click.stop>
<JnpfUploadImg v-model="item[column.prop]" detailed simple
v-if="item[column.prop]&&item[column.prop].length" />
</view>
<!-- #ifndef APP-HARMONY -->
<view class="item-cell-content" v-else-if="column.jnpfKey == 'uploadFile'" @click.stop>
<JnpfUploadFile v-model="item[column.prop]" detailed
v-if="item[column.prop]&&item[column.prop].length" align="left" />
</view>
<!-- #endif -->
<!-- #ifdef APP-HARMONY -->
<view class="item-cell-content" v-else-if="column.jnpfKey == 'uploadFile'" @click.stop>
<JnpfUploadFileH v-model="item[column.prop]" detailed
v-if="item[column.prop]&&item[column.prop].length" align="left" />
</view>
<!-- #endif -->
<view class="item-cell-content" v-else-if="column.jnpfKey == 'rate'">
<JnpfRate v-model="item[column.prop]" :max="column.count"
:allowHalf="column.allowHalf" disabled />
</view>
<view class="item-cell-content item-cell-slider" v-else-if="column.jnpfKey == 'slider'">
<JnpfSlider v-model="item[column.prop]" :min="column.min" :max="column.max"
:step="column.step" disabled />
</view>
<view class="item-cell-content" v-else-if="column.jnpfKey == 'input'">
<JnpfInput v-model="item[column.prop]" detailed showOverflow
:useMask="column.useMask" :maskConfig="column.maskConfig" align='left' />
</view>
<text class="item-cell-content" v-else>{{item[column.prop]}}</text>
</template>
<tableCell v-else @click.stop class="tableCell" ref="tableCell" :label="column.label"
:childList="item[column.prop]" :children="column.children" :pageLen="3"
@cRelationForm="relationFormClick" :key="item.id+i">
</tableCell>
</view>
<view class="item-cell" v-if="config.enableFlow==1">
<text class="item-cell-label">审批状态:</text>
<text :style="{color:useDefine.getFlowStatusColor(item.flowState)}">
{{useDefine.getFlowStatusContent(item.flowState)}}
</text>
</view>
</view>
</template>
</SwipeItem>
</view>
</view>
</template>
<script>
import {
useDefineSetting
} from '@/utils/useDefineSetting';
import tableCell from '../tableCell.vue'
import SwipeItem from "@/components/SwipeItem/index"
export default {
emits: ['selectCheckbox', 'handleClick', 'handleMoreClick', 'goDetail', 'relationFormClick', 'update:modelValue'],
components: {
tableCell,
SwipeItem
},
props: ['config', 'list', 'columnList', 'actionOptions', 'showSelect', 'checkedAll', 'modelValue', 'isMoreBtn',
'customBtnsList'
],
data() {
return {
selectData: [],
useDefine: useDefineSetting()
}
},
watch: {
checkedAll: {
handler(val) {
this.handleCheckAll()
},
immediate: true
}
},
computed: {
options() {
if (!this.customBtnsList?.length) return this.actionOptions;
return [{
text: this.$t('common.moreText'),
value: 'more',
style: {
backgroundColor: '#007aff'
}
},
...this.actionOptions,
];
},
showCheckbox() {
return this.showSelect
}
},
methods: {
/* 关联表单操作 */
relationFormClick(item, column) {
this.$emit('relationFormClick', item, column)
},
/* 跳转详情 */
goDetail(item) {
this.$emit('goDetail', item)
},
actionClick(data) {
const {
index,
value
} = data
if (value === 'remove') return this.$emit('handleClick', index)
if (value === 'more') return this.$emit('handleMoreClick', index)
},
/* 列表选择框 */
checkboxChange(e, item) {
const isSelected = e.value;
const selectedItemsSet = new Set(this.selectData.map(selectedItem => {
return selectedItem.id;
}));
if (isSelected) {
selectedItemsSet.add(item.id);
} else {
selectedItemsSet.delete(item.id);
}
this.selectData = [...selectedItemsSet.values()].map(id => {
return this.list.find(listItem => listItem.id === id);
});
this.$emit('selectCheckbox', this.selectData);
},
/* 全部选中 */
handleCheckAll() {
this.selectData = []
if (this.checkedAll) this.selectData = this.list.filter(o => o.checked)
this.$emit('selectCheckbox', this.selectData)
},
/* 千分位操作 */
toThousands(val, column) {
if (val) {
let valList = val.toString().split('.')
let num = Number(valList[0])
let newVal = column.thousands ? num.toLocaleString() : num
return valList[1] ? newVal + '.' + valList[1] : newVal
} else {
return val
}
}
}
}
</script>
<style lang="scss">
.list {
.list_box {
.item {
padding: 0;
.checkbox_box {
width: 60rpx;
height: 46rpx;
position: relative;
.checkbox {
position: absolute;
top: 6rpx;
left: 8rpx;
z-index: 9999;
}
}
}
}
}
.right-option-box {
display: flex;
width: max-content;
.right-option {
width: 144rpx;
height: 100%;
font-size: 16px;
color: #fff;
background-color: #dd524d;
display: flex;
align-items: center;
justify-content: center;
}
.more-option {
background-color: #1890ff;
}
}
</style>

View File

@@ -0,0 +1,164 @@
<template>
<u-form :model="formData" ref="dataForm" :errorType="['toast']" label-position="left" label-width="150">
<u-form-item :label="item.label" :prop="item.id" v-for="(item, i) in formConfCopy" :key="i">
<JnpfInput v-if="useInputList.includes(item.__config__.jnpfKey)" input-align='right'
v-model="formData[item.id]" :placeholder="textPrefix+item.label" clearable />
<template v-if="['inputNumber','calculate'].includes(item.__config__.jnpfKey)">
<JnpfInputNumber v-model="formData[item.id]" :precision="item.precision"
:placeholder="textPrefix+item.__config__.label" v-if="item.__config__.isFromParam" />
<JnpfNumberRange v-model="formData[item.id]"
:precision="!item.precision && item.__config__.jnpfKey=='calculate'?0:item.precision" v-else />
</template>
<template v-if="['rate', 'slider'].includes(item.__config__.jnpfKey)">
<JnpfNumberRange v-model="formData[item.id]" :precision="item.allowHalf ? 1 : 0" />
</template>
<JnpfSelect v-if="useSelectList.includes(item.__config__.jnpfKey)" v-model="formData[item.id]"
:placeholder="selectPrefix+item.label" :options="item.options" :props="item.props"
:multiple="item.searchMultiple" :key="key" filterable />
<JnpfCascader v-if="item.__config__.jnpfKey==='cascader'" v-model="formData[item.id]"
:placeholder="selectPrefix+item.label" :options="item.options" :props="item.props" filterable
:showAllLevels="item.showAllLevels" :multiple="item.searchMultiple" />
<JnpfAutoComplete v-if="item.__config__.jnpfKey==='autoComplete'" v-model="formData[item.id]"
:interfaceName="item.interfaceName" :placeholder="selectPrefix+item.label"
:interfaceId="item.interfaceId" :total="item.total" :templateJson="item.templateJson"
:formData='formData' :relationField="item.relationField" :propsValue="item.propsValue"
:clearable='item.clearable' />
<JnpfGroupSelect v-if="item.__config__.jnpfKey==='groupSelect'" v-model="formData[item.id]"
:vModel='item.id' :multiple="item.searchMultiple" :disabled="item.disabled"
:placeholder="selectPrefix+item.label" :ableIds="item.ableIds" :selectType="item.selectType" />
<JnpfRoleSelect v-if="item.__config__.jnpfKey==='roleSelect'" v-model="formData[item.id]"
:multiple="item.searchMultiple" :disabled="item.disabled" :placeholder="selectPrefix+item.label"
:ableIds="item.ableIds" :selectType="item.selectType" />
<JnpfOrganizeSelect v-if="['organizeSelect','currOrganize'].includes(item.__config__.jnpfKey)"
v-model="formData[item.id]" :placeholder="selectPrefix+item.label"
:multiple="item.__config__.jnpfKey === 'currOrganize' ? true : item.searchMultiple"
:ableIds="item.ableIds" :selectType="item.selectType" />
<JnpfPosSelect v-if="['posSelect','currPosition'].includes(item.__config__.jnpfKey)"
v-model="formData[item.id]" :placeholder="selectPrefix+item.label" :ableIds="item.ableIds"
:selectType="item.selectType"
:multiple="item.__config__.jnpfKey === 'currPosition' ? true : item.searchMultiple" />
<JnpfUserSelect v-if="['userSelect','createUser', 'modifyUser'].includes(item.__config__.jnpfKey)"
v-model="formData[item.id]" :placeholder="selectPrefix+item.label" :ableDepIds="item.ableDepIds"
:ableIds="item.ableIds" :selectType="item.selectType!='custom'?'all':'custom'"
:multiple="item.searchMultiple" />
<JnpfUsersSelect v-if="item.__config__.jnpfKey==='usersSelect'" v-model="formData[item.id]"
:placeholder="selectPrefix+item.label" :clearable="item.clearable" />
<JnpfTreeSelect v-if="item.__config__.jnpfKey==='treeSelect'" v-model="formData[item.id]"
:options="item.options" :props="item.props" :placeholder="selectPrefix+item.label" filterable
:multiple="item.searchMultiple" />
<JnpfAreaSelect v-if="item.__config__.jnpfKey==='areaSelect'" v-model="formData[item.id]"
:placeholder="selectPrefix+item.label" :level="item.level" :multiple="item.searchMultiple" />
<template v-if="useDateList.includes(item.__config__.jnpfKey)">
<JnpfDatePicker v-model="formData[item.id]" :format='item.format' v-if="item.__config__.isFromParam" />
<JnpfDateRange v-model="formData[item.id]" :format='item.format' v-else />
</template>
<JnpfTimeRange v-if="item.__config__.jnpfKey==='timePicker'" v-model="formData[item.id]"
:format='item.format' />
</u-form-item>
</u-form>
</template>
<script>
import {
getDictionaryDataSelector,
getDataInterfaceRes
} from '@/api/common'
const dyOptionsList = ['radio', 'checkbox', 'select', 'cascader', 'treeSelect'];
const useSelectList = ['radio', 'checkbox', 'select'];
const useInputList = ['input', 'textarea', 'text', 'link', 'billRule', 'location'];
const useDateList = ['createTime', 'modifyTime', 'datePicker', 'dateCalculate'];
const useArrList = ['cascader', 'address', 'numInput', 'calculate', ...useDateList]
export default {
props: ['formConf', 'webType', 'searchFormData'],
data() {
const data = {
useInputList,
useDateList,
useSelectList,
formConfCopy: this.$u.deepClone(this.formConf),
formData: this.$u.deepClone(this.searchFormData),
key: +new Date(),
textPrefix: this.$t('common.inputTextPrefix') + ' ',
selectPrefix: this.$t('common.chooseTextPrefix') + ' ',
}
this.initRelationForm(data.formConfCopy)
this.initFormData(data.formConfCopy, data.formData)
return data
},
watch: {
searchFormData(val) {
this.formData = val
}
},
methods: {
initFormData(componentList, formData) {
componentList.forEach(cur => {
const config = cur.__config__
if (dyOptionsList.indexOf(config.jnpfKey) > -1) {
if (config.dataType === 'dictionary' && config.dictionaryType) {
getDictionaryDataSelector(config.dictionaryType).then(res => {
cur.options = res.data.list || []
this.key = +new Date()
this.resetForm()
})
}
if (config.dataType === 'dynamic' && config.propsUrl) {
const query = {
paramList: this.jnpf.getParamList(config.templateJson) || []
};
getDataInterfaceRes(config.propsUrl, query).then(res => {
let list = res.data || []
cur.options = Array.isArray(list) ? list : [];
this.key = +new Date()
this.resetForm()
})
}
}
})
},
initRelationForm(componentList) {
componentList.forEach(cur => {
const config = cur.__config__
if (config.jnpfKey == 'relationFormAttr' || config.jnpfKey == 'popupAttr') {
const relationKey = cur.relationField.split("_jnpfTable_")[0]
componentList.forEach(item => {
const noVisibility = Array.isArray(item.__config__.visibility) && !item
.__config__.visibility.includes('app')
if ((relationKey == item.id) && (noVisibility || !!item.__config__
.noShow)) {
cur.__config__.noShow = true
}
})
}
if (cur.__config__.children && cur.__config__.children.length) this.initRelationForm(cur
.__config__.children)
})
},
allCondition() {
for (let key in this.formData) {
if (this.formData[key] !== 0 && !this.formData[key]) this.formData[key] = undefined;
if (this.formData[key] && Array.isArray(this.formData[key]) && !this.formData[key]
.length) {
this.formData[key] = undefined
}
}
return this.formData
},
submitForm() {
this.$refs.dataForm.validate(valid => {
if (!valid) return
for (let key in this.formData) {
if (this.formData[key] !== 0 && !this.formData[key]) this.formData[key] = undefined;
if (this.formData[key] && Array.isArray(this.formData[key]) && !this.formData[key]
.length) {
this.formData[key] = undefined
}
}
this.$emit('submit', this.formData)
})
},
resetForm() {
this.$refs.dataForm.resetFields()
}
}
}
</script>

View File

@@ -0,0 +1,125 @@
<template>
<uni-collapse class='collapse' accordion ref="collapse" @change="collapseChange" @click.stop>
<uni-collapse-item :key="key">
<template v-slot:title>
<view class="u-font-24 u-flex">
<view style="width: 124rpx;text-align: right;">
<text>{{label+':'}}</text>
</view>
<text style="color: #606266;" class="u-m-l-28">{{$t('app.apply.expandData')}}</text>
</view>
</template>
<view class="collapse-item" v-for="(item,d) in dataList" :key="d">
<view v-if="d<allPageLen" class="item-cell-children">
<view class="item-cell" v-for="(cld,c) in children" :key="c">
<text
class="item-cell-label">{{cld.labelI18nCode ? $t(cld.labelI18nCode, cld.label) : cld.label}}:</text>
<text class="item-cell-content"
v-if="['calculate','inputNumber'].includes(cld.__config__.jnpfKey)">
{{toThousands(item[cld.vModel],cld) }}
</text>
<text class="item-cell-content text-primary"
v-else-if="cld.__config__.jnpfKey === 'relationForm'"
@click.stop="relationFormClick(item,cld)">
{{item[cld.vModel]}}
</text>
<view class="item-cell-content" v-else-if="cld.jnpfKey == 'sign'">
<JnpfSign v-model="item[cld.vModel]" align="left" detailed />
</view>
<view class="item-cell-content" v-else-if="cld.jnpfKey == 'signature'">
<JnpfSignature v-model="item[cld.vModel]" align="left" detailed />
</view>
<view class="item-cell-content" v-else-if="cld.jnpfKey == 'uploadImg'" @click.stop>
<JnpfUploadImg v-model="item[cld.vModel]" detailed simple
v-if="item[cld.vModel]&&item[cld.vModel].length" />
</view>
<!-- #ifndef APP-HARMONY -->
<view class="item-cell-content" v-else-if="cld.jnpfKey == 'uploadFile'" @click.stop>
<JnpfUploadFile v-model="item[cld.vModel]" detailed
v-if="item[cld.vModel]&&item[cld.vModel].length" align="left" />
</view>
<!-- #endif -->
<!-- #ifdef APP-HARMONY -->
<view class="item-cell-content" v-else-if="cld.jnpfKey == 'uploadFile'" @click.stop>
<JnpfUploadFileH v-model="item[cld.vModel]" detailed
v-if="item[cld.vModel]&&item[cld.vModel].length" align="left" />
</view>
<!-- #endif -->
<view class="item-cell-content" v-else-if="cld.jnpfKey == 'rate'">
<JnpfRate v-model="item[cld.vModel]" :max="cld.count" :allowHalf="cld.allowHalf" disabled />
</view>
<view class="item-cell-content item-cell-slider" v-else-if="cld.jnpfKey == 'slider'">
<JnpfSlider v-model="item[cld.vModel]" :min="cld.min" :max="cld.max" :step="cld.step"
disabled />
</view>
<view class="item-cell-content" v-else-if="cld.jnpfKey == 'input'">
<JnpfInput v-model="item[cld.vModel]" detailed showOverflow :useMask="cld.useMask"
:maskConfig="cld.maskConfig" align='left' />
</view>
<text class="item-cell-content" v-else>{{item[cld.vModel]}}</text>
</view>
</view>
</view>
<view class="loadMore" @click.stop="loadMore" v-if="!isAllData&&this.dataList.length>allPageLen">
加载更多
</view>
</uni-collapse-item>
</uni-collapse>
</template>
<script>
export default {
props: ['childList', 'label', 'children', 'pageLen', 'thousands', 'thousandsField'],
data() {
return {
dataList: [],
isAllData: false,
key: +new Date(),
allPageLen: 3
}
},
watch: {
childList: {
handler(val) {
this.dataList = val || []
this.allPageLen = this.pageLen
this.children.map(o => {
if (o.childLabel.length > 4) o.childLabel = o.childLabel.substring(0, 4)
})
},
immediate: true,
}
},
methods: {
toThousands(val, column) {
if (val) {
let valList = val.toString().split('.')
let num = Number(valList[0])
let newVal = column.thousands ? num.toLocaleString() : num
return valList[1] ? newVal + '.' + valList[1] : newVal
}
},
relationFormClick(item, cld) {
this.$emit('cRelationForm', item, cld)
},
loadMore() {
this.allPageLen = this.childList.length
this.isAllData = true
this.resizeCollapse()
},
collapseChange(e) {
if (!e) {
this.isAllData = false
setTimeout(() => {
this.allPageLen = this.pageLen
}, 500)
}
this.resizeCollapse()
},
resizeCollapse() {
setTimeout(() => {
this.$refs.collapse && this.$refs.collapse.resize()
}, 50)
}
}
}
</script>

View File

@@ -0,0 +1,449 @@
<template>
<view class="dynamicModel-form-v jnpf-wrap jnpf-wrap-form" v-if="showPage">
<Parser :formConf="formConf" :formData="formData" ref="dynamicForm" v-if="!loading" :key="key"
@toDetail="toDetail" />
<view class="u-m-t-20 dataLog-box u-flex-col u-m-b-20" v-if="formConf.dataLog && !setting.noDataLog">
<view class="title u-flex">
<u-icon name=" icon-ym-generator-menu" custom-prefix="icon-ym"></u-icon>
<text class="u-m-l-10">修改记录</text>
</view>
<view class="dataLog-v" v-if="dataLogList.length">
<dataLog :dataLogList="dataLogList"></dataLog>
</view>
<JnpfEmpty v-else />
</view>
<view class="buttom-actions">
<CustomButton class="u-flex buttom-btn-left-inner" v-if="showMoreBtn" btnText="更多" btnType="more"
iconName="more-dot-fill" size="28" @handleBtn="showAction = $event" :btnLoading="loading" />
<template v-if="showEditBtn">
<CustomButton class="u-flex buttom-btn-left-inner" :btnText="$t('common.cancelText')"
btnIcon="icon-ym icon-ym-add-cancel" customIcon :btnLoading="loading" />
<u-button class="buttom-btn" type="primary" @click.stop="handleEdit" :loading="loading">
{{labelS.btn_edit}}
</u-button>
</template>
<u-button class="cancel" @click.stop="jnpf.goBack()"
v-if="!showEditBtn && !showMoreBtn">{{$t('common.cancelText')}}</u-button>
</view>
<u-select :list="actionList" v-model="showAction" @confirm="selectBtnconfirm" />
</view>
</template>
<script>
import CustomButton from '@/components/CustomButton'
import {
getConfigData,
getOnlineLog,
getModelInfo,
getDataChange,
launchFlow
} from "@/api/apply/visualDev";
import {
getRelationFormDetail,
getDataInterfaceRes
} from "@/api/common.js";
import Parser from "./components/detail/Parser";
import dataLog from '@/components/dataLog'
import deepClone from '../../../uni_modules/vk-uview-ui/libs/function/deepClone';
export default {
components: {
Parser,
dataLog,
CustomButton
},
data() {
return {
dataLogList: [],
actionList: [],
showAction: false,
showPage: false,
loading: true,
isPreview: "0",
modelId: "",
formConf: {},
formData: {},
dataForm: {
id: "",
data: "",
},
btnType: "",
formPermissionList: {},
formList: [],
labelS: {}
};
},
onLoad(option) {
this.init(option)
},
computed: {
showMoreBtn() {
if (this.actionList.length && !this.setting?.noShowBtn || 0 && this.setting?.noDataLog) return true
return false
},
showEditBtn() {
if (this.btnType === 'btn_edit' && !this.setting.noShowBtn && this.setting.enableEdit) return true
return false
}
},
onShow() {
setTimeout(() => {
uni.$emit('initCollapse')
}, 100)
},
onUnload() {
uni.$off("refresh");
},
methods: {
init(option) {
// 提取公共解析方法
const parseConfig = (rawConfig) => {
try {
return JSON.parse(this.jnpf.base64.decode(rawConfig)) || {}
} catch (error) {
return {}
}
}
// 使用解构赋值提取配置
const config = parseConfig(option.config)
const {
currentMenu,
btnType = "",
labelS: rawLabelS = {},
modelId,
isPreview = "0",
id = ""
} = config
// 缓存解析结果
const formPermissionList = currentMenu ? JSON.parse(decodeURIComponent(currentMenu)) : [];
// 批量属性赋值
Object.assign(this, {
formPermissionList,
formList: formPermissionList.formList || [],
btnType,
labelS: {
btn_edit: this.$t('common.editText'),
...rawLabelS
},
modelId,
isPreview,
dataForm: {
id
},
setting: config
})
// 设置导航栏标题
uni.setNavigationBarTitle({
title: this.$t('common.detailText')
})
this.getConfigData();
uni.$on("refresh", () => {
this.getConfigData();
});
},
// 自定义按钮事件
selectBtnconfirm(e) {
var i = this.actionList.findIndex((item) => {
return item.value == e[0].value
})
const item = this.actionList[i].actionConfig
const row = this.formData
// 自定义启用规则判断
if (item.btnType == 1) this.handlePopup(item, row)
if (item.btnType == 2) this.handleScriptFunc(item, row)
if (item.btnType == 3) this.handleInterface(item, row)
if (item.btnType == 4) this.handleLaunchFlow(item, [row])
},
//自定义按钮发起流程
handleLaunchFlow(item, records) {
const data = deepClone(item.launchFlow)
let dataList = [];
for (let i = 0; i < records.length; i++) {
dataList.push(this.jnpf.getLaunchFlowParamList(data.transferList, records[i], this.getRowKey));
}
const query = {
template: data.flowId,
btnCode: item.value,
currentUser: data.currentUser,
customUser: data.customUser,
initiator: data.initiator,
hasPermission: data.hasPermission,
dataList
};
launchFlow(query, this.modelId).then(res => {
this.$u.toast(res.msg)
});
},
//自定义按钮弹窗操作
handlePopup(item, row) {
let data = {
config: item,
modelId: this.modelId,
id: row.id,
row,
}
data = encodeURIComponent(JSON.stringify(data))
uni.navigateTo({
url: '/pages/apply/customBtn/index?data=' + data
})
},
//自定义按钮JS操作
handleScriptFunc(item, row) {
const parameter = {
data: row,
refresh: this.initData,
onlineUtils: this.jnpf.onlineUtils,
}
const func = this.jnpf.getScriptFunc.call(this, item.func)
if (!func) return
func.call(this, parameter)
},
//自定义按钮接口操作
handleInterface(item, row, index) {
const handlerData = () => {
getModelInfo(this.modelId, row.id).then(res => {
const dataForm = res.data || {};
if (!dataForm.data) return;
const data = {
...JSON.parse(dataForm.data),
id: row.id
};
handlerInterface(data);
})
}
const handlerInterface = (data) => {
let query = {
paramList: this.jnpf.getParamList(item.templateJson, data) || [],
}
getDataInterfaceRes(item.interfaceId, query).then(res => {
uni.showToast({
title: res.msg,
icon: 'none'
})
if (item.isRefresh) this.initData();
})
}
const handleFun = () => {
handlerData();
};
if (!item.useConfirm) return handleFun()
uni.showModal({
title: '提示',
content: item.confirmTitle || '确认执行此操作',
success: (res) => {
if (!res.cancel) handleFun()
}
})
},
getOnlineLog() {
getOnlineLog(this.setting.modelId, this.setting.id).then(res => {
this.dataLogList = res.data.list || []
})
},
getConfigData() {
this.loading = true;
getConfigData(this.modelId).then((res) => {
if (res.code !== 200 || !res.data) {
uni.showToast({
title: "暂无此页面",
icon: "none",
complete: () => {
setTimeout(() => {
uni.navigateBack();
}, 1500);
},
});
return;
}
this.formConf = res.data.formData ? JSON.parse(res.data.formData) : {};
this.actionList = this.formConf?.appCustomBtns || []
this.actionList.map((o) => {
if (o.labelI18nCode) o.label = this.$t(o.labelI18nCode, o.label)
})
this.beforeInit(this.formConf.fields || []);
this.showPage = true;
this.key = +new Date();
this.initData();
});
},
beforeInit(fields) {
const loop = (list) => {
for (var index = 0; index < list.length; index++) {
const config = list[index].__config__;
if (config.children && config.children.length) loop(config.children);
if (config.jnpfKey == "tableGrid") {
let newList = [];
for (var i = 0; i < config.children.length; i++) {
let element = config.children[i];
for (var j = 0; j < element.__config__.children.length; j++) {
let item = element.__config__.children[j];
newList.push(...item.__config__.children);
}
}
list.splice(index, 1, ...newList);
}
}
};
loop(fields);
},
initData() {
this.$nextTick(() => {
if (this.dataForm.id) {
let extra = {
modelId: this.modelId,
id: this.dataForm.id,
type: 2,
};
uni.setStorageSync('dynamicModelExtra', extra)
this.getRelationFormDetail()
} else {
this.loading = false;
}
this.$nextTick(() => {
this.getOnlineLog()
})
this.key = +new Date();
});
},
getRelationFormDetail() {
const processResponse = (res) => {
this.dataForm = res.data;
this.loading = false;
if (!this.dataForm.data) return;
this.formData = {
...JSON.parse(this.dataForm.data),
id: this.dataForm.id,
};
this.fillFormData(this.formConf, this.formData);
this.initRelationForm(this.formConf.fields);
};
let requestParams = {
id: this.dataForm.id,
menuId: this.setting.menuId
};
if (this.setting?.sourceRelationForm) {
if (this.setting.propsValue) requestParams.propsValue = this.setting.propsValue;
}
getDataChange(requestParams, this.modelId).then(res => {
processResponse(res)
}).catch(err => {
this.loading = false;
})
},
fillFormData(form, data) {
const loop = (list, parent) => {
for (let i = 0; i < list.length; i++) {
let item = list[i];
if (item.__vModel__) {
if (
item.__config__.jnpfKey === "relationForm" ||
item.__config__.jnpfKey === "popupSelect"
) {
item.__config__.defaultValue = data[item.__vModel__ + "_id"];
this.$set(item, "name", item.__config__.defaultValue || "");
} else {
let val = data.hasOwnProperty(item.__vModel__) ?
data[item.__vModel__] :
item.__config__.defaultValue;
item.__config__.defaultValue = val;
}
if (this.formPermissionList.useFormPermission) {
let id = item.__config__.isSubTable ?
parent.__vModel__ + "-" + item.__vModel__ :
item.__vModel__;
let noShow = true;
if (this.formList && this.formList.length) {
noShow = !this.formList.some((o) => o.enCode === id);
}
noShow = item.__config__.noShow ? item.__config__.noShow : noShow;
this.$set(item.__config__, "noShow", noShow);
}
} else {
if (['relationFormAttr', 'popupAttr'].includes(item.__config__.jnpfKey)) {
item.__config__.defaultValue =
data[item.relationField.split('_jnpfTable_')[0] + '_' + item.showField];
}
}
if (
item.__config__ &&
item.__config__.children &&
Array.isArray(item.__config__.children)
) {
loop(item.__config__.children, item);
}
}
};
loop(form.fields);
this.loading = false;
},
initRelationForm(componentList) {
componentList.forEach((cur) => {
const config = cur.__config__;
if (
config.jnpfKey == "relationFormAttr" ||
config.jnpfKey == "popupAttr"
) {
const relationKey = cur.relationField.split("_jnpfTable_")[0];
componentList.forEach((item) => {
const noVisibility =
Array.isArray(item.__config__.visibility) &&
!item.__config__.visibility.includes("app");
if (
relationKey == item.__vModel__ &&
(noVisibility || !!item.__config__.noShow) && !cur.__vModel__
) {
cur.__config__.noShow = true;
}
});
}
if (cur.__config__.children && cur.__config__.children.length)
this.initRelationForm(cur.__config__.children);
});
},
toDetail(item) {
const id = item.__config__.defaultValue;
if (!id) return;
let config = {
modelId: item.modelId,
id: id,
formTitle: "详情",
noShowBtn: 1,
noDataLog: 1,
sourceRelationForm: item?.sourceRelationForm || false,
propsValue: item?.propsValue || ''
};
this.$nextTick(() => {
const url =
"/pages/apply/dynamicModel/detail?config=" +
this.jnpf.base64.encode(JSON.stringify(config));
uni.navigateTo({
url: url,
});
});
},
handleEdit() {
if (this.setting.disableEdit) return;
const currentMenu = encodeURIComponent(JSON.stringify(this.formPermissionList));
let config = {
modelId: this.modelId,
isPreview: this.isPreview,
id: this.setting.id,
btnType: "btn_edit",
currentMenu,
list: this.setting.list,
index: this.setting.index,
menuId: this.setting.menuId
};
const url =
"/pages/apply/dynamicModel/form?config=" +
this.jnpf.base64.encode(JSON.stringify(config));
uni.navigateTo({
url: url,
});
},
},
};
</script>
<style lang="scss" scoped>
page {
background-color: #f0f2f6;
}
</style>

View File

@@ -0,0 +1,295 @@
<template>
<view class="dynamicModel-form-v jnpf-wrap jnpf-wrap-form" v-if="showPage">
<JnpfParser :formConf="formConf" ref="dynamicForm" @submit="sumbitForm" :key="key" v-if="!loading" />
<view class="buttom-actions" v-if="btnType === 'btn_edit' || btnType === 'btn_add'">
<CustomButton class="u-flex buttom-btn-left-inner" :btnText="getCancelText"
btnIcon="icon-ym icon-ym-add-cancel" customIcon :btnLoading="btnLoading" />
<u-button class="buttom-btn" type="primary" @click.stop="submit" :loading="btnLoading">
{{getOkText}}
</u-button>
</view>
</view>
</template>
<script>
import CustomButton from '@/components/CustomButton'
import {
getConfigData,
createModel,
updateModel,
getModelInfo
} from '@/api/apply/visualDev'
export default {
components: {
CustomButton
},
data() {
return {
webType: '',
showPage: false,
btnLoading: false,
loading: true,
isPreview: '0',
modelId: '',
formConf: {},
formData: {},
dataForm: {
id: '',
data: ''
},
btnType: '',
formPermissionList: {},
formList: [],
key: +new Date(),
config: {},
clickType: 'submit',
prevDis: false,
nextDis: false,
index: 0,
userInfo: {},
isAdd: false
}
},
computed: {
getOkText() {
const text = this.formConf.confirmButtonTextI18nCode ?
this.$t(this.formConf.confirmButtonTextI18nCode, this.formConf.confirmButtonText) :
this.formConf.confirmButtonText;
return text || this.$t('common.okText');
},
getCancelText() {
const text = this.formConf.cancelButtonTextI18nCode ?
this.$t(this.formConf.cancelButtonTextI18nCode, this.formConf.cancelButtonText) :
this.formConf.cancelButtonText;
return text || this.$t('common.cancelText');
}
},
onLoad(option) {
this.init(option)
},
methods: {
init(option) {
// 使用解构赋值提取配置项
const parseConfig = (rawConfig) => {
try {
return JSON.parse(this.jnpf.base64.decode(rawConfig)) || {}
} catch (error) {
return {}
}
}
const config = parseConfig(option.config)
const {
index,
currentMenu,
btnType = '',
modelId,
isPreview = '0',
id = ''
} = config
const formPermissionList = currentMenu ? JSON.parse(decodeURIComponent(currentMenu)) : []
Object.assign(this, {
userInfo: uni.getStorageSync('userInfo') || {},
config,
index,
formPermissionList,
formList: formPermissionList?.formList || [], // 添加安全访问
btnType,
modelId,
isPreview,
dataForm: {
id
}
})
const getNavigationTitle = () => this.dataForm.id ? this.$t('common.editText') : this.$t('common.addText')
uni.setNavigationBarTitle({
title: getNavigationTitle()
})
this.getConfigData()
},
getConfigData() {
getConfigData(this.modelId, this.config.menuId).then(res => {
if (res.code !== 200 || !res.data) {
uni.showToast({
title: '暂无此页面',
icon: 'none',
complete: () => {
setTimeout(() => {
uni.navigateBack()
}, 1500)
}
})
return
}
this.formConf = res.data.formData ? JSON.parse(res.data.formData) : {};
this.showPage = true
this.initData()
})
},
initData() {
this.$nextTick(() => {
if (this.dataForm.id) {
let extra = {
modelId: this.modelId,
id: this.dataForm.id,
type: 1
}
uni.setStorageSync('dynamicModelExtra', extra)
getModelInfo(this.modelId, this.dataForm.id, this.config.menuId).then(res => {
this.dataForm = res.data
if (!this.dataForm.data) return
this.formData = {
...JSON.parse(this.dataForm.data),
id: this.dataForm.id
}
this.fillFormData(this.formConf, this.formData)
this.$nextTick(() => {
this.loading = false
})
})
} else {
this.isAdd = true
this.formData = {}
this.loading = false
this.fillFormData(this.formConf, this.formData)
}
this.key = +new Date()
})
},
fillFormData(form, data) {
this.key = +new Date()
const loop = (list, parent) => {
for (let i = 0; i < list.length; i++) {
let item = list[i]
let vModel = item.__vModel__
let config = item.__config__
if (vModel) {
let val = data.hasOwnProperty(vModel) ? data[vModel] : config.defaultValue
if (!config.isSubTable) config.defaultValue = val
if (this.isAdd || config.isSubTable) { //新增时候,默认当前
if (config.defaultCurrent) {
if (config.jnpfKey === 'datePicker') {
if (!data.hasOwnProperty(vModel)) {
let format = this.jnpf.handelFormat(item.format)
let dateStr = this.jnpf.toDate(new Date().getTime(), format)
let time = format === 'yyyy' ? '-01-01 00:00:00' : format === 'yyyy-MM' ?
'-01 00:00:00' : format === 'yyyy-MM-dd' ?
' 00:00:00' : ''
val = new Date(dateStr + time).getTime()
config.defaultValue = val
}
}
if (config.jnpfKey === 'timePicker') {
if (!data.hasOwnProperty(vModel)) {
config.defaultValue = this.jnpf.toDate(new Date(), item.format)
}
}
if (config.jnpfKey === 'organizeSelect' && this.userInfo.organizeIds?.length) {
config.defaultValue = item.multiple ? this.userInfo.organizeIds :
this.userInfo.organizeId
}
if (config.jnpfKey === 'posSelect' && this.userInfo.positionIds?.length) {
config.defaultValue = item.multiple ? this.userInfo.positionIds :
this.userInfo.positionId
}
const userId = this.userInfo.userId
if (config.jnpfKey === 'userSelect' && userId) {
config.defaultValue = item.multiple ? [userId] : userId;
}
if (config.jnpfKey === 'usersSelect' && userId) {
config.defaultValue = [userId + '--user'];
}
if (config.jnpfKey === 'sign' && this.userInfo.signImg) {
config.defaultValue = this.userInfo.signImg
}
}
}
const btn_detail = this.$permission.hasBtnP('btn_detail', this.formPermissionList
.menuId)
const btn_edit = this.$permission.hasBtnP('btn_edit', this.formPermissionList
.menuId)
if (!!this.dataForm.id && !btn_edit && btn_detail) item.disabled = btn_detail
let noShow = !config.noShow ? false : config.noShow
let isVisibility = false
if (!config.visibility || (Array.isArray(config.visibility) && config.visibility.includes(
'app'))) isVisibility = true
this.$set(config, 'isVisibility', isVisibility)
if (this.formPermissionList.useFormPermission) {
let id = config.isSubTable ? parent.__vModel__ + '-' + vModel : vModel
noShow = true
if (this.formList && this.formList.length) {
noShow = !this.formList.some(o => o.enCode === id)
}
noShow = config.noShow ? config.noShow : noShow
this.$set(config, 'noShow', noShow)
}
} else {
let noShow = config.noShow ? config.noShow : false,
isVisibility = false
if (!config.visibility || (Array.isArray(config.visibility) && config.visibility.includes(
'app'))) isVisibility = true
this.$set(config, 'isVisibility', isVisibility)
this.$set(config, 'noShow', noShow)
}
if (config && config.children && Array.isArray(config.children)) {
loop(config.children, item)
}
}
}
loop(form.fields)
form.formData = data
this.key = +new Date()
},
sumbitForm(data, callback) {
if (!data) return
this.btnLoading = true
const formData = {
...this.formData,
...data
}
this.dataForm.data = JSON.stringify(formData)
this.dataForm.menuId = this.config.menuId
if (callback && typeof callback === "function") callback()
const formMethod = this.dataForm.id ? updateModel : createModel
formMethod(this.modelId, this.dataForm).then(res => {
uni.showToast({
title: res.msg,
complete: () => {
setTimeout(() => {
if (this.clickType == 'save_add') {
this.key = +new Date()
this.$nextTick(() => {
this.$refs.dynamicForm && this.$refs
.dynamicForm.resetForm()
})
}
this.btnLoading = false
this.initData()
if (this.clickType != 'save_proceed' && this.clickType !=
'save_add') {
uni.$emit('refresh')
uni.navigateBack()
}
}, 1500)
}
})
}).catch(() => {
this.btnLoading = false
})
},
commonSubmit(type) {
this.clickType = type
this.submit(type)
},
submit(type) {
this.clickType = type
if (this.isPreview == '1') return this.$u.toast('功能预览不支持数据保存')
this.$refs.dynamicForm && this.$refs.dynamicForm.submitForm()
}
}
}
</script>
<style lang="scss">
page {
background-color: #f0f2f6;
}
</style>

View File

@@ -0,0 +1,120 @@
<template>
<view class="dynamicModel-v">
<Form v-if="webType == 1" :config="config" :modelId="modelId" :isPreview="isPreview" />
<List v-if="webType == 2 || webType == 4" :config="config" :modelId="modelId" :isPreview="isPreview"
:title="title" :menuId="menuId" ref="List" />
</view>
</template>
<script>
import Form from "./components/form/index.vue";
import List from "./components/list/index.vue";
import {
getFlowStartFormId
} from "@/api/workFlow/flowEngine";
import {
getConfigData
} from "@/api/apply/visualDev";
import {
useBaseStore
} from '@/store/modules/base'
const baseStore = useBaseStore()
export default {
name: "dynamicModel",
components: {
Form,
List,
},
data() {
return {
webType: "",
showPage: false,
isPreview: false,
modelId: "",
menuId: "",
title: "",
config: {},
preview: false,
flowId: '',
enableFlow: 0,
};
},
onLoad(obj) {
baseStore.getDictionaryDataAll()
this.config = JSON.parse(this.jnpf.base64.decode(obj.config)) || {};
this.isPreview = this.config.isPreview || false;
this.enableFlow = this.config.type === 9 ? 1 : 0;
this.title = this.config.fullName || "";
this.menuId = this.config.id || "";
uni.setNavigationBarTitle({
title: this.title,
});
if (!this.enableFlow) return this.getConfigData();
this.flowId = this.config.moduleId
this.getModelId()
},
methods: {
// 获取流程版本ID和发起节点表单ID
getModelId() {
getFlowStartFormId(this.flowId).then(res => {
if (!res.data || !res.data.formId) return;
this.config.moduleId = res.data.formId
this.getConfigData();
})
},
getConfigData() {
getConfigData(this.config.moduleId, this.menuId).then((res) => {
if (res.code !== 200 || !res.data) return this.handleError('暂无此页面')
if (this.enableFlow && res.data.webType == 1) return this.jump();
this.config = {
...res.data,
...this.config,
enableFlow: this.enableFlow,
flowId: this.flowId
};
this.showPage = true;
this.isPreview = !!this.config.isPreview;
this.modelId = this.config.moduleId;
this.menuId = this.config.id || "";
this.webType = this.config.webType || 2;
this.title = this.config.fullName || "";
uni.setNavigationBarTitle({
title: this.title
});
});
},
jump() {
const config = {
id: "",
flowId: this.flowId,
opType: "-1",
hideCancelBtn: true,
hideSaveBtn: true
};
uni.redirectTo({
url: "/pages/workFlow/flowBefore/index?config=" +
this.jnpf.base64.encode(JSON.stringify(config)),
fail: () => {
this.$u.toast("暂无此页面");
},
});
},
handleError(msg) {
this.$u.toast(msg);
setTimeout(() => {
uni.navigateBack();
}, 1500);
}
},
};
</script>
<style lang="scss">
page {
background-color: #f0f2f6;
}
.dynamicModel-v {
height: 100%;
}
</style>

View File

@@ -0,0 +1,180 @@
<template>
<view class="dynamicModel-v">
<template v-if="showPage">
<view class="jnpf-wrap jnpf-wrap-form" v-if="config.mt == 2">
<JnpfParser :formConf="formConf" ref="dynamicForm" @submit="sumbitForm" :key="key" />
</view>
<template v-else>
<FlowForm ref="flowForm" />
</template>
</template>
</view>
</template>
<script>
import FlowForm from '@/pages/workFlow/flowBefore/flowForm'
import {
getConfigData,
getModelInfo
} from '@/api/apply/visualDev'
export default {
name: 'scanForm',
components: {
FlowForm
},
data() {
return {
webType: '',
showPage: false,
origin: '',
id: '',
config: {},
formConf: {},
key: +new Date(),
isAdd: false,
userInfo: {}
}
},
onLoad(option) {
this.userInfo = uni.getStorageSync('userInfo') || {}
this.config = JSON.parse(option.config)
this.initData()
},
methods: {
initData() {
this.showPage = false
if (this.config.mt == 2) {
this.getConfigData()
} else {
this.isAdd = true
let data = {
flowId: this.config.fid,
id: this.config.pid,
formType: 2,
opType: this.config.opt,
taskId: this.config.ftid
}
this.showPage = true
this.$nextTick(() => {
this.$refs.flowForm.init(data)
})
}
},
getConfigData() {
getConfigData(this.config.mid).then(res => {
if (res.code !== 200 || !res.data) {
uni.showToast({
title: '暂无此页面',
icon: 'none',
complete: () => {
setTimeout(() => {
uni.navigateBack()
}, 1500)
}
})
return
}
this.formConf = JSON.parse(res.data.formData)
uni.setNavigationBarTitle({
title: res.data.fullName
})
let extra = {
modelId: this.config.mid,
id: this.config.id,
type: this.config.mt
}
uni.setStorageSync('dynamicModelExtra', extra)
getModelInfo(this.config.mid, this.config.id).then(res => {
if (!res.data.data) return
let formData = JSON.parse(res.data.data)
this.fillFormData(this.formConf, formData)
this.$nextTick(() => {
this.showPage = true
this.key = +new Date()
})
})
})
},
fillFormData(form, data) {
const loop = list => {
for (let i = 0; i < list.length; i++) {
let item = list[i]
let vModel = item.__vModel__
let config = item.__config__
if (vModel) {
let val = data.hasOwnProperty(vModel) ? data[vModel] : config.defaultValue
if (!config.isSubTable) config.defaultValue = val
if (this.isAdd || config.isSubTable) { //新增时候,默认当前
if (config.defaultCurrent) {
if (config.jnpfKey === 'datePicker') {
if (!data.hasOwnProperty(vModel)) {
let format = this.jnpf.handelFormat(item.format)
let dateStr = this.jnpf.toDate(new Date().getTime(), format)
let time = format === 'yyyy' ? '-01-01 00:00:00' : format === 'yyyy-MM' ?
'-01 00:00:00' : format === 'yyyy-MM-dd' ?
' 00:00:00' : ''
val = new Date(dateStr + time).getTime()
config.defaultValue = val
}
}
if (config.jnpfKey === 'timePicker') {
if (!data.hasOwnProperty(vModel)) {
config.defaultValue = this.jnpf.toDate(new Date(), item.format)
}
}
if (config.jnpfKey === 'organizeSelect' && this.userInfo.organizeIds?.length) {
config.defaultValue = item.multiple ? this.userInfo.organizeIds :
this.userInfo.organizeId
}
if (config.jnpfKey === 'posSelect' && this.userInfo.positionIds?.length) {
config.defaultValue = item.multiple ? this.userInfo.positionIds :
this.userInfo.positionId
}
const userId = this.userInfo.userId
if (config.jnpfKey === 'userSelect' && userId) {
config.defaultValue = item.multiple ? [userId] : userId;
}
if (config.jnpfKey === 'usersSelect' && userId) {
config.defaultValue = [userId + '--user'];
}
if (config.jnpfKey === 'sign' && this.userInfo.signImg) {
config.defaultValue = this.userInfo.signImg
}
}
}
this.$set(item, 'disabled', true)
let noShow = !item.__config__.noShow ? false : item.__config__.noShow
let isVisibility = false
if (!item.__config__.visibility || (Array.isArray(item.__config__.visibility) && item
.__config__.visibility.includes('app'))) isVisibility = true
this.$set(item.__config__, 'isVisibility', isVisibility)
this.$set(item.__config__, 'noShow', noShow)
} else {
let noShow = false,
isVisibility = false
if (!item.__config__.visibility || (Array.isArray(item.__config__.visibility) && item
.__config__.visibility.includes('app'))) isVisibility = true
this.$set(item.__config__, 'isVisibility', isVisibility)
this.$set(item.__config__, 'noShow', noShow)
}
if (item.__config__ && item.__config__.jnpfKey !== 'table' && item.__config__.children && Array
.isArray(item.__config__.children)) {
loop(item.__config__.children)
}
}
}
loop(form.fields)
},
}
}
</script>
<style lang="scss">
page {
background-color: #f0f2f6;
}
.dynamicModel-v {
height: 100%;
}
</style>

View File

@@ -0,0 +1,23 @@
<template>
<view>
<web-view :src="url"></web-view>
</view>
</template>
<script>
export default {
data() {
return {
url: ''
}
},
onLoad(option) {
this.url = decodeURIComponent(option.url)
const title = option.fullName || ''
if (option.type == 5 || !title) return
uni.setNavigationBarTitle({
title
})
}
}
</script>

View File

@@ -0,0 +1,181 @@
<template>
<view class="">
<JnpfEmpty v-if="!signListInvoke.length" />
<view class="page_v u-flex-col" v-else>
<view v-for="(item,index) in signListInvoke" :key="index" :class="item.isDefault ? 'active' : '' "
class="lists_box" @click="setMainSignInvoke(item,index)">
<view class="signImgBox">
<image :src="item.signImg" mode="scaleToFill" class="signImg"></image>
</view>
<view class="icon-checked-box" v-if="item.isDefault==1">
<view class="icon-checked">
<u-icon name="checkbox-mark" color="#fff" size="28"></u-icon>
</view>
</view>
</view>
</view>
<!-- 底部按钮 -->
<view class="flowBefore-actions">
<u-button class="buttom-btn" @click.stop="eventLauncher('cancel')">{{$t('common.cancelText')}}</u-button>
<u-button class="buttom-btn" type="primary"
@click.stop="eventLauncher('confirm')">{{$t('common.okText')}}</u-button>
</view>
</view>
</template>
<script>
import {
getSignImgList
} from "@/api/common";
export default {
data() {
return {
show: false,
signListInvoke: [],
};
},
async onLoad(config) {
this.signListInvoke = await this.getSignData()
this.clearChoose()
let val = decodeURIComponent(config.signVal)
if (val) {
this.setMainSignInvokeWithValue(val)
}
uni.setStorageSync('sign-fieldKey', config.fieldKey)
},
methods: {
getSignData() {
return new Promise((resolve, reject) => {
if (!this.signListInvoke.length) {
getSignImgList().then(res => {
resolve(res.data || [])
})
} else {
resolve(this.signListInvoke)
}
})
},
clearChoose() {
for (let i = 0; i < this.signListInvoke.length; i++) {
let item = this.signListInvoke[i]
item.isDefault = 0
this.$set(this.signListInvoke, i, item)
}
},
setMainSignInvokeWithValue(val) {
for (let i = 0; i < this.signListInvoke.length; i++) {
let item = this.signListInvoke[i]
if (item.signImg === val) {
this.setMainSignInvoke(item, i)
break;
}
}
},
eventLauncher(type) {
if (type === 'cancel') uni.navigateBack();
if (type === 'confirm') {
let choose = this.signListInvoke.filter(item => item.isDefault === 1)
if (!choose || !choose.length) return this.$u.toast(`请选择签名`)
this.$nextTick(() => uni.$emit('setSignValue', choose[0].signImg))
uni.navigateBack()
}
},
setMainSignInvoke(item, index) {
this.clearChoose()
item.isDefault = 1
this.$set(this.signListInvoke, index, item)
},
}
}
</script>
<style lang="scss">
page {
height: 100%;
background-color: #f0f2f6;
}
.page_v {
height: 100%;
padding: 0 10px 60px;
.active {
border: 1rpx solid #2979FF;
color: #2979FF;
.icon-ym-organization {
&::before {
color: #2979FF !important;
}
}
}
.sign-mask {
width: 100%;
height: 200rpx;
background: rgba(0, 0, 0, .3);
position: absolute;
top: 0;
border-radius: 8rpx;
display: flex;
align-items: center;
flex-direction: column;
justify-content: center;
.sign-mask-btn {
width: 60%;
display: flex;
}
}
.lists_box {
width: 100%;
height: 200rpx;
border-radius: 8rpx;
position: relative;
display: flex;
flex-direction: column;
justify-content: center;
background-color: #FFFFFF;
margin-top: 20rpx;
.signImgBox {
width: 100%;
height: 100%;
text-align: center;
border-radius: 8rpx;
.signImg {
width: 100%;
height: 100%;
border-radius: 8rpx;
}
}
.icon-checked-box {
display: flex;
width: 140rpx;
height: 80rpx;
position: absolute;
transform: scale(0.9);
right: -4rpx;
bottom: -2rpx;
flex-direction: row;
align-items: center;
.icon-checked {
width: 44rpx;
height: 44rpx;
border: 40rpx solid #1890ff;
border-left: 40rpx solid transparent;
border-top: 40rpx solid transparent;
border-bottom-right-radius: 12rpx;
position: absolute;
transform: scale(0.95);
right: -8rpx;
bottom: -6rpx;
}
}
}
}
</style>

View File

@@ -0,0 +1,558 @@
<template>
<view class="jnpf-location-map">
<u-top-tips ref="uTips" />
<view class="content">
<view class="user-select u-flex-col">
<view class="user-select-search">
<u-search :placeholder="$t('common.searchText')" v-model="keyword" height="72" :show-action="false"
bg-color="#f0f2f6" shape="square" @change='search'>
</u-search>
</view>
</view>
</view>
<view class="header">
<view class="map-container">
<map class='map' id="maps" :latitude="location.latitude" :longitude="location.longitude"
:circles="circles" :polygons="polygons" :scale='15' @regionchange="regionChange">
<!-- #ifdef H5 -->
<cover-image class="map-marker h5-map-marker" src="/static/image/mark.png" />
<!-- #endif -->
<!-- #ifndef H5-->
<cover-image class="map-marker" src="/static/image/mark.png" />
<!-- #endif -->
<cover-view class="map-locate" @click="handleLocate">
<cover-image v-if="!locateLoading" src="/static/image/locate.png" />
<cover-image v-else class="map-locate-img" src="/static/image/waite.png" />
</cover-view>
</map>
</view>
</view>
<view class="around-contain">
<scroll-view style="height:100%" id="scroll-view-h" class="scroll-view2" :refresher-enabled="false"
:refresher-threshold="50" :scroll-with-animation='true' @scrolltolower="handleScrollToLower"
:scroll-y="true">
<radio-group class="around-contain-item" v-for="(item,index) in list" :key="index" v-if="list.length"
@change="onSelectValueChange(item,index)">
<label class="u-radio-label">
<radio class="u-radio" :value="item.id" :checked="item.id === selectId" />
<view class="around-item-title-box">
<view class="around-item-title u-line-1"> {{ item.name }}</view>
<view class="around-item-sub-title u-line-1"> {{ item.address }}</view>
</view>
</label>
</radio-group>
<u-loading class="loading" mode="circle" size="44" v-if="loading" />
<JnpfEmpty v-if="!loading&&!list.length"></JnpfEmpty>
</scroll-view>
</view>
<view class="jnpf-bottom-actions">
<u-button class="buttom-btn" @click="close()">{{$t('common.cancelText')}}</u-button>
<u-button class="buttom-btn" type="primary" @click.stop="handleConfirm()">{{$t('common.okText')}}</u-button>
</view>
</view>
</template>
<script>
import {
getAroundList,
getTextList
} from '@/api/common.js'
export default {
data() {
return {
loading: false,
tabWidth: 150,
tabIndex: 0,
keyword: '',
location: {
longitude: 116.404, // 经度
latitude: 39.915, // 纬度
},
circles: [],
list: [],
pagination: {
currentPage: 1,
pageSize: 50
},
total: 0,
currentLocation: {},
selectId: '',
selectItem: {},
enableLocation: '',
showPopup: false,
locateLoading: false,
polygons: [],
enableLocationScope: false,
adjustmentScope: 500,
enableDesktopLocation: false,
locationScope: [],
emitKey: '',
// #ifdef APP
dragLoading: false
// #endif
};
},
onLoad(e) {
const data = e.data ? JSON.parse(e.data) : {}
this.enableLocationScope = data.enableLocationScope || false
this.adjustmentScope = data.adjustmentScope || 500
this.enableDesktopLocation = data.enableDesktopLocation || false
this.locationScope = data.locationScope || []
this.emitKey = data.emitKey
this.init()
},
methods: {
init() {
this.circles = []
this.polygons = []
this.selectId = ''
this.list = []
this.locateLoading = false
// #ifdef APP
this.dragLoading = false
// #endif
this.getLocation()
},
getLocation() {
this.loading = true;
uni.getLocation({
type: 'gcj02',
isHighAccuracy: true,
success: (res) => {
this.location.longitude = res.longitude // 经度
this.location.latitude = res.latitude // 纬度
//查询附近位置
this.getList()
//添加可选区域圆形
this.handelCircle();
//添加微调区域圆形
this.handleScopeCircle();
},
fail: (err) => {
//查询附近位置
this.getList()
//添加可选区域圆形
this.handelCircle();
//添加微调区域圆形
this.handleScopeCircle();
}
});
},
handleGetCenter() {
this.mapContext = uni.createMapContext("maps", this);
this.mapContext.getCenterLocation({
type: 'gcj02',
geocode: true,
isHighAccuracy: true,
altitude: true,
success: (res) => {
this.location.longitude = res.longitude
this.location.latitude = res.latitude
if (this.enableLocationScope) {
const discount = this.jnpf.getDistance(this.currentLocation.latitude, this
.currentLocation.longitude, this.location.latitude, this.location.longitude
) || 0;
if (discount > (this.adjustmentScope || 500)) return this.$refs.uTips.show({
title: '超出微调范围',
type: 'warning',
});
}
this.getList()
}
})
},
handelCircle() {
if (!this.enableDesktopLocation || !this.locationScope.length) return;
for (let i = 0; i < this.locationScope.length; i++) {
const o = this.locationScope[i];
if (!o.lng || !o.lat || !o.radius) continue;
o.longitude = o.lng
o.latitude = o.lat
this.addCircle({
...o,
color: '#54d65e99',
fillColor: '#54d65e66',
});
}
},
handleScopeCircle() {
if (!this.enableLocationScope) return;
this.currentLocation = this.$u.deepClone(this.location);
this.addCircle({
...this.location,
radius: this.adjustmentScope || 500,
color: '#1890ff99',
fillColor: '#1890ff66'
});
},
addCircle(o) {
// #ifdef H5
this.polygons.push({
points: this.CreateSimpleCircle(o.latitude, o.longitude, o.radius, 100),
strokeColor: o.color,
fillColor: o.fillColor,
strokeWidth: 1
})
// #endif
// #ifndef H5
this.circles.push({
...o,
strokeWidth: 1,
})
// #endif
},
// #ifdef H5
CreateSimpleCircle(lat, lng, radius, pointCount) {
var km = radius / 1000;
var a = km < 5 ? 0.01 : km < 50 ? 0.1 : km < 500 ? 1 : 10;
var b = this.getCircleDistance(lng, lat, lng + a, lat);
var c = this.getCircleDistance(lng, lat, lng, lat + a);
var rb = radius / b * a;
var rc = radius / c * a;
var arr = [];
var n = 0,
step = 360.0 / pointCount,
N = 360 - step / 2; //注意浮点数±0.000000001的差异
for (var i = 0; n < N; i++, n += step) {
var x = lng + rb * Math.cos(n * Math.PI / 180);
var y = lat + rc * Math.sin(n * Math.PI / 180);
arr[i] = {
latitude: y,
longitude: x
}
}
arr.push({
latitude: arr[0].latitude,
longitude: arr[0].longitude
});
return arr;
},
getCircleDistance(lng1, lat1, lng2, lat2) {
var d = Math.PI / 180;
var f = lat1 * d,
h = lat2 * d;
var i = lng2 * d - lng1 * d;
var e = (1 - Math.cos(h - f) + (1 - Math.cos(i)) * Math.cos(f) * Math.cos(h)) / 2;
return 2 * 6378137 * Math.asin(Math.sqrt(e));
},
// #endif
regionChange(e) {
// #ifdef APP
if (this.dragLoading) return (this.dragLoading = false);
this.list = [];
this.handleGetCenter()
// #endif
// #ifndef APP
if (e.detail.causedBy == 'drag' && e.type == 'end') {
this.list = [];
this.handleGetCenter()
}
// #endif
},
handleScrollToLower() {
if (this.pagination.pageSize * this.pagination.currentPage < this.total) {
this.pagination.currentPage = this.pagination.currentPage + 1;
this.getList()
} else {
this.$u.toast('没有更多信息啦!')
}
},
getList() {
this.loading = true;
const query = {
key: this.define.aMapWebKey,
location: this.location.longitude + ',' + this.location.latitude,
radius: -1,
offset: this.pagination.pageSize,
page: this.pagination.currentPage,
};
getAroundList(query).then(res => {
this.handleResult(res)
}).catch(() => {
this.loading = false;
})
},
handleResult(res) {
this.loading = false;
if (res.data.status == '1') {
this.list = [...this.list, ...res.data.pois || []];
this.total = Number(res.data.count || 0)
} else {
this.$u.toast(res.data.info)
}
},
onSelectValueChange(item, index) {
// #ifdef APP
this.dragLoading = true
// #endif
this.selectStatus = true
this.selectId = item.id
this.selectItem = item
const [longitude, latitude] = (item.location || '').split(',');
this.location = {
longitude,
latitude
};
// #ifdef APP
setTimeout(() => {
this.dragLoading = false
}, 800)
// #endif
},
handleConfirm() {
if (!this.selectId) return this.$u.toast('请选择地址')
const data = this.selectItem
const [lng, lat] = data.location.split(',');
if (this.enableLocationScope) {
const discount = this.jnpf.getDistance(this.currentLocation.latitude, this.currentLocation
.longitude, lat,
lng) || 0;
if (discount > (this.adjustmentScope || 500)) return this.$refs.uTips.show({
title: '超出微调范围',
type: 'warning',
});
}
//判断可选范围
if (this.enableDesktopLocation && this.locationScope.length) {
let list = [];
for (let i = 0; i < this.locationScope.length; i++) {
const o = this.locationScope[i];
const discount = this.jnpf.getDistance(o.lat, o.lng, lat, lng) || 0;
list.push(discount > o.radius);
}
if (list.every(o => o === true)) return this.$refs.uTips.show({
title: '超出规定范围',
type: 'warning',
});
}
const address = data.address && data.address.length ? data.address : '';
//台湾、北京、上海、重庆、深圳地址特殊处理
let fullAddress = data.pname + data.cityname + data.adname + address + data.name;
if (data.pname == data.cityname) fullAddress = data.pname + data.adname + address + data.name;
if (data.pname == data.cityname && data.pname == data.adname) fullAddress = data.pname + address +
data.name;
this.innerValue = {
pName: data.pname,
cName: data.cityname,
adName: data.adname,
address,
name: data.name,
lng,
lat,
fullAddress,
};
uni.$emit(this.emitKey, JSON.stringify(this.innerValue))
this.close();
},
close() {
uni.navigateBack({
delta: 1
});
},
getDistance(lat1, lon1, lat2, lon2) {
const toRadians = (degrees) => {
return degrees * (Math.PI / 180);
}
const R = 6371;
const dLat = toRadians(lat2 - lat1);
const dLon = toRadians(lon2 - lon1);
const a = Math.sin(dLat / 2) * Math.sin(dLat / 2) +
Math.cos(toRadians(lat1)) * Math.cos(toRadians(lat2)) *
Math.sin(dLon / 2) * Math.sin(dLon / 2);
const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
const distance = R * c;
return distance * 1000;
},
search() {
// 节流,避免输入过快多次请求
this.searchTimer && clearTimeout(this.searchTimer)
this.searchTimer = setTimeout(() => {
this.list = [];
this.pagination.currentPage = 1
this.keyword ? this.handleSearch() : this.getList();
}, 300)
},
handleSearch() {
this.loading = true;
const query = {
key: this.define.aMapWebKey,
keywords: this.keyword,
radius: this.enableLocationScope ? this.adjustmentScope || 500 : -1,
offset: this.pagination.pageSize,
page: this.pagination.currentPage,
};
getTextList(query).then(res => {
this.handleResult(res);
});
},
handleLocate() {
if (this.locateLoading) return
this.locateLoading = true
uni.getLocation({
type: 'gcj02',
isHighAccuracy: true,
success: (res) => {
this.locateLoading = false
if (!res.longitude || !res.latitude) return
this.mapContext = uni.createMapContext("maps", this);
this.mapContext.moveToLocation({
longitude: res.longitude,
latitude: res.latitude,
})
},
fail: (res) => {
this.locateLoading = false
this.$u.toast('获取定位失败')
}
})
},
}
};
</script>
<style scoped lang="scss">
.jnpf-location-map {
/* #ifdef H5 */
height: calc(100vh - 44px);
/* #endif */
/* #ifndef H5 */
height: 100vh;
/* #endif */
display: flex;
flex-direction: column;
.header {
.map-container {
position: relative;
padding: 0rpx 20rpx;
.map {
width: 100%;
height: 600rpx;
}
.map-marker {
width: 38rpx;
height: 64rpx;
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, calc(-50% - 20rpx));
z-index: 9999;
}
.h5-map-marker {
transform: translate(-50%, calc(-50% - 30rpx));
}
.map-locate {
position: absolute;
bottom: 10px;
right: 10px;
height: 24px;
width: 24px;
padding: 4px;
background-color: #fff;
border-radius: 50%;
box-shadow: 0 0 5px silver;
z-index: 999;
.map-locate-img {
-webkit-animation: rotate 2s linear infinite;
}
@keyframes rotate {
0% {
-webkit-transform: rotate(0deg);
}
25% {
-webkit-transform: rotate(90deg);
}
50% {
-webkit-transform: rotate(180deg);
}
75% {
-webkit-transform: rotate(270deg);
}
100% {
-webkit-transform: rotate(1turn);
}
}
}
}
}
.content {
width: 100%;
.user-select {
.user-select-search {
padding: 0rpx 20rpx;
margin: 20rpx 0;
}
}
}
.around-contain {
flex: 1;
width: 100%;
overflow: hidden;
.loading {
display: flex;
justify-content: center;
margin: 250rpx auto 0;
}
.around-contain-item {
display: flex;
align-items: center;
padding: 10rpx 0;
height: 60px;
line-height: 22px;
border-bottom: 1px solid #f2f2f6;
.u-radio-label {
width: 100%;
display: flex;
align-items: center;
// #ifdef MP
:deep(.u-radio) {
margin: 0 16rpx 0 20rpx;
}
// #endif
// #ifndef MP
:deep(.uni-radio-input) {
margin: 0 16rpx 0 20rpx;
}
// #endif
.around-item-title-box {
flex: 1;
min-width: 0;
padding-right: 16rpx;
.around-item-title {
font-size: 30rpx;
color: #171a1d;
}
.around-item-sub-title {
font-size: 28rpx;
color: #b9babb;
padding-top: 8rpx;
}
}
}
}
}
}
</style>

341
pages/apply/menu/index.vue Normal file
View File

@@ -0,0 +1,341 @@
<template>
<view class="menu-v">
<view class="search-box u-m-b-20">
<u-search :placeholder="$t('app.apply.pleaseKeyword')" v-model="keyword" height="72" :show-action="false"
@change="search" bg-color="#f0f2f6" shape="square" style="width: 100%;">
</u-search>
</view>
<mescroll-body ref="mescrollRef" @down="downCallback" :down="downOption" :sticky="false" @up="upCallback"
:up="upOption" :bottombar="false" @init="mescrollInit" :top="mescrollTop">
<view class="workFlow-list">
<view class="part" v-for="(item, i) in menuList" :key="i">
<view class="caption u-line-1" v-if="item?.children?.length">
{{ item.fullName }}
</view>
<view class="u-flex u-flex-wrap">
<view class="item u-flex-col u-col-center" v-for="(child, ii) in item.children" :key="ii"
@click="handelClick(child)">
<text class="u-font-40 item-icon" :class="child.icon"
:style="{ background: child.iconBackground || '#008cff' }" />
<text class="u-font-24 u-line-1 item-text">{{child.fullName}}</text>
</view>
</view>
</view>
</view>
</mescroll-body>
</view>
</template>
<script>
import {
getMenuList,
getChildList
} from "@/api/apply/apply.js";
import resources from "@/libs/resources.js";
import MescrollMixin from "@/uni_modules/mescroll-uni/components/mescroll-uni/mescroll-mixins.js";
import {
useUserStore
} from '@/store/modules/user'
export default {
mixins: [MescrollMixin],
data() {
return {
mescrollTop: 0,
menuList: [],
downOption: {
use: true,
auto: true,
},
upOption: {
page: {
num: 0,
size: 50,
time: null,
},
empty: {
use: true,
icon: resources.message.nodata,
tip: this.$t('common.noData'),
fixed: false,
top: "560rpx",
},
textNoMore: this.$t('app.apply.noMoreData'),
},
keyword: "",
fullName: "",
key: +new Date(),
listChild: [],
};
},
computed: {
token() {
return uni.getStorageSync('token')
},
report() {
return this.define.report;
},
pcURL() {
return this.define.pcURL;
},
},
onShow() {
this.keyword = "";
uni.$on('refresh', () => {
this.menuList = [];
this.$nextTick(() => {
this.mescroll.resetUpScroll();
})
});
},
onUnload() {
uni.$off("updateUsualList");
},
methods: {
handelClick(item) {
if (item.type == 1) {
getChildList(item.id).then(res => {
this.listChild = res.data || []
this.handleProperty(this.listChild)
this.$nextTick(() => {
uni.navigateTo({
url: "/pages/apply/catalog/index?config=" +
this.jnpf.base64.encode(JSON.stringify(this.listChild[0])),
fail: (err) => {
this.$u.toast("暂无此页面");
},
});
})
})
return;
}
let url = ''
// 2-页面 11-回传表单
if (item.type == 2 || item.type == 11) {
if (!item.pageAddress) {
this.$u.toast("暂无此页面");
return;
}
url = item.pageAddress + "?menuId=" + item.id + "&fullName=" + item.fullName
}
// 3-在线表单 9-流程
if (item.type == 3 || item.type == 9) {
if (!item.moduleId) {
this.$u.toast("暂无此页面");
return;
}
url = "/pages/apply/dynamicModel/index?config=" + this.jnpf.base64.encode(JSON.stringify(item))
}
// 外链
if (item.type == 7) {
if (!item.pageAddress) {
this.$u.toast("暂无此页面");
return;
}
url = "/pages/apply/externalLink/index?url=" + encodeURIComponent(item.pageAddress) + "&fullName=" +
item.fullName + "&type=" + item.type
}
// 报表(原)
if (item.type == 5) {
if (!item.moduleId) {
this.$u.toast("暂无此页面");
return;
}
userInfo = uni.getStorageSync('userInfo') || {}
const appCode = userInfo.systemCode
const urlPre = encodeURIComponent(
`${this.report}/preview.html?id=${item.moduleId}&token=${this.token}}&appCode=${appCode}&page=1&from=menu`
)
url = "/pages/apply/externalLink/index?url=" + urlPre + "&fullName=" + item.fullName + "&type=" +
item.type
}
// 报表
if (item.type == 10) {
if (!item.moduleId) {
this.$u.toast("暂无此页面");
return;
}
const urlPre = encodeURIComponent(
`${this.pcURL}/reportPreview?id=${item.moduleId}&token=${this.token}&from=app`
);
url = "/pages/apply/externalLink/index?url=" + urlPre + "&fullName=" + item.fullName + "&type=" +
item.type
}
// 门户
if (item.type == 8) {
if (!item.moduleId) {
this.$u.toast("暂无此页面");
return;
}
url = "/pages/portal/scanPortal/index?id=" + item.moduleId + "&portalType=1&fullName=" +
item.fullName
}
if (!url) return;
uni.navigateTo({
url,
fail: () => {
this.$u.toast("暂无此页面");
},
});
},
upCallback(keyword) {
let query = {
keyword: this.keyword,
};
uni.showLoading({
title: '正在加载',
mask: true
})
getMenuList(query)
.then((res) => {
let list = res.data.list || [];
this.mescroll.endSuccess(list.length);
this.list = list.filter(o => o.children && o.children.length)
this.menuList = this.list;
this.handleProperty(this.list)
uni.hideLoading()
this.key = +new Date();
this.mescroll.endSuccess(this.menuList.length, false);
}).catch(() => {
this.mescroll.endSuccess(0);
this.mescroll.endErr();
});
},
handleProperty(list) {
const loop = (par) => {
par.map(o => {
if (o?.propertyJson) {
let propertyJson = JSON.parse(o.propertyJson);
this.$set(o, "iconBackground", propertyJson.iconBackgroundColor || "");
this.$set(o, "moduleId", propertyJson.moduleId || "");
}
if (o?.children && o?.children?.length) loop(o.children)
})
}
loop(list)
},
search() {
this.searchTimer && clearTimeout(this.searchTimer);
this.searchTimer = setTimeout(() => {
this.list = [];
this.menuList = [];
this.mescroll.resetUpScroll();
}, 300);
}
},
};
</script>
<style lang="scss">
page {
background-color: #f0f2f6;
}
.menu-v {
.search-box {
height: 120rpx;
padding: 0rpx 20rpx;
display: flex;
align-items: center;
background-color: #fff;
}
.common-block {
background-color: #fff;
margin: 20rpx 0;
.caption {
padding: 0 32rpx;
line-height: 100rpx;
justify-content: space-between;
.caption-left {
font-size: 36rpx;
font-weight: bold;
}
.caption-right {}
}
.item {
margin-bottom: 32rpx;
width: 25%;
.item-icon {
width: 88rpx;
height: 88rpx;
margin-bottom: 8rpx;
line-height: 82rpx;
text-align: center;
border-radius: 30rpx;
color: #fff;
font-size: 40rpx;
&.more {
background: #ececec;
color: #666666;
font-size: 50rpx;
}
}
.item-text {
width: 100%;
text-align: center;
padding: 0 16rpx;
}
}
}
.select-box {
max-height: 600rpx;
:deep(.u-drawer-content) {
height: 100% !important;
}
}
.popupItem {
height: 400rpx;
overflow-y: scroll;
/* #ifdef APP-HARMONY || MP */
padding-top: 40rpx;
/* #endif */
}
.item {
.currentItem {
color: #2979ff;
}
.select-item {
height: 100rpx;
display: flex;
align-items: center;
padding: 0 20rpx;
font-size: 30rpx;
color: #303133;
text-align: left;
position: relative;
&::after {
content: " ";
position: absolute;
left: 2%;
top: 0;
box-sizing: border-box;
width: 96%;
height: 1px;
transform: scale(1, 0.3);
border: 0 solid #e4e7ed;
z-index: 2;
border-bottom-width: 1px;
}
.sysName {
flex: 1;
overflow: auto;
min-width: 0;
}
}
}
}
</style>

358
pages/apply/order/index.vue Normal file
View File

@@ -0,0 +1,358 @@
<template>
<view class="order-v">
<view class="head-warp com-dropdown">
<u-dropdown class="u-dropdown" ref="uDropdown">
<u-dropdown-item :title="$t('app.apply.sort')" :options="sortOptions">
<view class="screen-box">
<view class="screen-list">
<view class="u-p-l-20 u-p-r-20 list">
<scroll-view scroll-y="true" style="height: 100%;">
<u-cell-group>
<u-cell-item @click="cellClick(item)" :arrow="false" :title="item.label"
v-for="(item, index) in sortOptions" :key="index" :title-style="{
color: sortValue.includes(item.value)? '#2979ff' : '#606266' }">
<u-icon v-if="sortValue.includes(item.value)" name="checkbox-mark"
color="#2979ff" size="32"></u-icon>
</u-cell-item>
</u-cell-group>
</scroll-view>
</view>
<view class="u-flex screen-btn">
<text @click="handleSortReset" class="btn btn1">{{$t('common.cleanText')}}</text>
<text @click="handleSortSearch" class="btn btn2">{{$t('common.okText')}}</text>
</view>
</view>
</view>
</u-dropdown-item>
<u-dropdown-item :title="$t('app.apply.screen')">
<view class="screen-box u-flex-col">
<view class="screen-list">
<view class="u-p-l-20 u-p-r-20 list">
<scroll-view scroll-y="true" style="height: 100%;">
<u-form label-position="left" label-width="150" label-align="left">
<u-form-item :label="$t('component.jnpf.dateRange.startPlaceholder')"
prop="startTime">
<JnpfDatePicker v-model="listQuery.startTime" />
</u-form-item>
<u-form-item :label="$t('component.jnpf.dateRange.endPlaceholder')"
prop="endTime">
<JnpfDatePicker v-model="listQuery.endTime" />
</u-form-item>
</u-form>
</scroll-view>
</view>
<view class="u-flex screen-btn">
<text @click="reset" class="btn btn1">{{$t('component.cropper.btn_reset')}}</text>
<text @click="closeDropdown" class="btn btn2">{{$t('common.queryText')}}</text>
</view>
</view>
</view>
</u-dropdown-item>
</u-dropdown>
</view>
<view class="list-warp">
<mescroll-uni ref="mescrollRef" @init="mescrollInit" @down="downCallback" @up="upCallback" top="100"
:up="upOption">
<view class="flow-list">
<uni-swipe-action ref="swipeAction">
<uni-swipe-action-item v-for="(item, index) in list" :key="item.id" :right-options="options"
@click="handleClick(index)">
<view class="order-item" @click="goDetail(item.id,item.currentState,item.flowId)"
:id="'item'+index">
<view class="order-item-title u-border-bottom">
<text class="order-title u-line-1">{{item.customerName}}</text>
</view>
<view class="order-item-down">
<view class="order-item-cell u-flex">
<text class="time">{{item.orderCode}}</text>
<text :class="'status '+getFlowStatus(item.currentState).statusCss">
{{getFlowStatus(item.currentState).text}}
</text>
</view>
<view class="order-item-cell u-flex">
<text class="time">{{item.salesmanName}}</text>
<text class="time">{{$u.timeFormat(item.orderDate,'yyyy-mm-dd')}}</text>
</view>
</view>
</view>
</uni-swipe-action-item>
</uni-swipe-action>
</view>
</mescroll-uni>
</view>
<view class="com-addBtn" @click="addPage()" v-if="showAddBtn">
<u-icon name="plus" size="48" color="#fff" />
</view>
<u-picker mode="selector" v-model="show" :default-selector="[0]" title="请选择流程" :range="selector"
range-key="fullName" @confirm="confirm"></u-picker>
</view>
</template>
<script>
import resources from '@/libs/resources.js'
import MescrollMixin from "@/uni_modules/mescroll-uni/components/mescroll-uni/mescroll-mixins.js";
import {
getOrderList,
Delete
} from '@/api/apply/order'
import {
getFlowStartFormId
} from '@/api/workFlow/flowEngine'
export default {
mixins: [MescrollMixin],
data() {
return {
templateId: '',
selector: [],
show: false,
sortValue: [],
sortOptions: [{
label: '单据升序',
value: 1,
},
{
label: '单据降序',
value: 2,
},
{
label: '日期升序',
value: 3,
},
{
label: '日期降序',
value: 4,
}
],
upOption: {
page: {
num: 0,
size: 20,
time: null
},
empty: {
icon: resources.message.nodata,
tip: this.$t('common.noData'),
top: "300rpx"
},
textNoMore: this.$t('app.apply.noMoreData'),
toTop: {
bottom: 250
}
},
list: [],
listQuery: {
sort: 'desc',
sidx: '',
keyword: '',
startTime: '',
endTime: ''
},
options: [{
text: '删除',
style: {
backgroundColor: '#dd524d'
}
}],
menuId: '',
flowId: '585361795057715206',
key: +new Date()
}
},
computed: {
showAddBtn() {
return this.$permission.hasBtnP('btn_add', this.menuId)
}
},
onLoad(e) {
this.menuId = e.menuId
},
onShow() {
this.$nextTick(() => {
this.list = [];
this.mescroll.resetUpScroll();
})
},
onUnload() {
uni.$off('refresh')
},
methods: {
confirm(e) {
this.jumPage()
},
upCallback(page) {
let query = {
currentPage: page.num,
pageSize: page.size,
flowId: this.flowId,
...this.listQuery
}
getOrderList(query, {
load: page.num == 1
}).then(res => {
if (page.num == 1) this.list = [];
this.mescroll.endSuccess(res.data.list.length);
const list = res.data.list.map(o => ({
show: false,
...o
}));
this.list = this.list.concat(list);
this.$nextTick(() => {
this.key = +new Date()
})
}).catch(() => {
this.mescroll.endErr();
})
},
handleClick(index, index1) {
const item = this.list[index]
if ([1, 2, 3, 5].includes(item.currentState)) {
this.$u.toast("流程正在审核,请勿删除")
this.list[index].show = false
return
}
if (!this.$permission.hasBtnP('btn_remove', this.menuId)) return this.$u.toast("未开启删除权限")
Delete(item.id).then(res => {
this.$u.toast(res.msg)
this.list.splice(index, 1)
if (!this.list.length) this.mescroll.resetUpScroll()
})
this.$nextTick(() => {
this.key = +new Date()
})
},
open(index) {
this.list[index].show = true;
this.list.map((val, idx) => {
if (index != idx) this.list[idx].show = false;
})
},
search() {
this.searchTimer && clearTimeout(this.searchTimer)
this.searchTimer = setTimeout(() => {
this.list = [];
this.mescroll.resetUpScroll();
}, 300)
},
addPage() {
this.jumPage()
},
jumPage(id, status) {
let opType = '-1'
if ([1, 2, 4, 5, 6].includes(status)) opType = 0
const config = {
id: id,
flowId: this.flowId,
opType: opType,
status: status,
}
uni.navigateTo({
url: '/pages/workFlow/flowBefore/index?config=' +
this.jnpf.base64.encode(JSON.stringify(config))
})
},
goDetail(id, status, flowId) {
if (!this.$permission.hasBtnP('btn_edit', this.menuId) && status == 3) return
if (!this.$permission.hasBtnP('btn_detail', this.menuId) && [1, 2, 4, 5, 6].includes(status)) return
this.jumPage(id, status)
},
getFlowStatus(val) {
let status
switch (val) {
case 0:
status = {
text: '等待提交',
statusCss: 'u-type-info'
}
break;
case 1:
status = {
text: '等待审核',
statusCss: 'u-type-primary'
}
break;
case 2:
status = {
text: '审核通过',
statusCss: 'u-type-success'
}
break;
case 3:
status = {
text: '审核退回',
statusCss: 'u-type-error'
}
break;
case 4:
case 7:
status = {
text: '流程撤回',
statusCss: 'u-type-warning'
}
break;
case 5:
status = {
text: '审核终止',
statusCss: 'u-type-info'
}
break;
default:
status = {
text: '等待提交',
statusCss: 'u-type-info'
}
break;
}
return status
},
handleSortReset() {
this.sortValue = []
},
handleSortSearch() {
if (this.sortValue.length) {
this.listQuery.sidx = this.sortValue.join(',')
} else {
this.setDefaultQuery()
}
this.$refs.uDropdown.close();
this.$nextTick(() => {
this.list = [];
this.mescroll.resetUpScroll();
})
},
cellClick(item) {
const findIndex = this.sortValue.findIndex(o => o === item.value);
if (findIndex < 0) {
this.listQuery.sort = item.value == 1 || item.value == 3 ? 'asc' : 'desc'
this.listQuery.sidx = item.value == 1 || item.value == 2 ? 'orderCode' : 'orderDate'
this.sortValue.push(item.value)
} else {
this.sortValue.splice(findIndex, 1)
}
},
reset() {
this.listQuery.startTime = ''
this.listQuery.endTime = ''
},
closeDropdown() {
this.$refs.uDropdown.close();
this.$nextTick(() => {
this.list = [];
this.mescroll.resetUpScroll();
})
}
}
}
</script>
<style lang="scss">
page {
background-color: #f0f2f6;
height: 100%;
/* #ifdef MP-ALIPAY */
position: absolute;
top: 0;
left: 0;
width: 100%;
/* #endif */
}
</style>

View File

@@ -0,0 +1,285 @@
<template>
<view class="jnpf-pop-select">
<mescroll-body ref="mescrollRef" @init="mescrollInit" @down="downCallback" @up="upCallback" :sticky="true"
:down="downOption" :up="upOption">
<view class="search-box search-box_sticky">
<u-search :placeholder="$t('app.apply.pleaseKeyword')" v-model="keyword" height="72"
:show-action="false" @change="search" bg-color="#f0f2f6" shape="square">
</u-search>
</view>
<view class="u-flex-col tableList">
<view class="u-flex list-card" v-for="(item,index) in list" :key="index">
<u-radio-group v-model="selectId[0]" v-if="!onLoadData.multiple">
<u-radio :name="item[publicField]" @change="radioChange(item)">
<view class="u-flex-col fieldContent u-m-l-10">
<view v-for="(column,c) in onLoadData.columnOptions" :key="c"
class="fieldList u-line-1 u-flex">
<view class="val">{{column.label+':'}} {{item[column.value]}}</view>
</view>
</view>
</u-radio>
</u-radio-group>
<u-checkbox-group wrap v-if="onLoadData.multiple">
<u-checkbox v-model="item.checked" @change="checkboxChange($event,item)"
:name="item[publicField]">
<view class="u-flex-col fieldContent u-m-l-10">
<view class="fieldList u-line-1 u-flex" v-for="(column,c) in onLoadData.columnOptions"
:key="c">
<view class="val">{{column.label+':'}} {{item[column.value]}}</view>
</view>
</view>
</u-checkbox>
</u-checkbox-group>
</view>
</view>
</mescroll-body>
<!-- 底部按钮 -->
<view class="flowBefore-actions">
<u-button class="buttom-btn" @click.stop="handleClose()">{{$t('common.cancelText')}}</u-button>
<u-button class="buttom-btn" type="primary" @click.stop="handleConfirm()">{{$t('common.okText')}}</u-button>
</view>
</view>
</template>
<script>
import {
getRelationSelect,
getPopSelect
} from '@/api/common.js'
import resources from '@/libs/resources.js'
import MescrollMixin from "@/uni_modules/mescroll-uni/components/mescroll-uni/mescroll-mixins.js";
export default {
mixins: [MescrollMixin],
data() {
return {
downOption: {
use: true,
auto: true
},
upOption: {
page: {
num: 0,
size: 20,
time: null
},
empty: {
use: true,
icon: resources.message.nodata,
tip: this.$t('common.noData'),
fixed: true,
top: "300rpx",
},
textNoMore: this.$t('app.apply.noMoreData'),
},
list: [],
type: '',
onLoadData: {},
keyword: '',
innerValue: '',
listQuery: {
keyword: ''
},
modelId: '',
cur: null,
firstVal: '',
firstId: 0,
selectId: [],
publicField: '',
selectRow: [],
columnOptions: [],
newSelctData: []
}
},
onLoad(e) {
this.onLoadData = JSON.parse(decodeURIComponent(e.data));
for (let i = 0; i < this.onLoadData.columnOptions.length; i++) {
this.columnOptions.push(this.onLoadData.columnOptions[i].value)
}
this.innerValue = this.onLoadData.innerValue
this.type = this.onLoadData.type;
if (this.type === 'relation') {
this.publicField = 'id'
if (this.onLoadData.id) this.selectId = [this.onLoadData.id]
} else {
this.publicField = this.onLoadData.propsValue
if (this.onLoadData.id) this.selectId = this.onLoadData.id
}
this.modelId = this.onLoadData.modelId
uni.setNavigationBarTitle({
title: this.onLoadData.popupTitle
})
},
methods: {
upCallback(page) {
const method = this.type === 'popup' ? getPopSelect : getRelationSelect
const paramList = this.onLoadData.paramList
let query = {
...this.listQuery,
currentPage: page.num,
pageSize: this.onLoadData.hasPage ? this.onLoadData.pageSize : 10000,
interfaceId: this.onLoadData.modelId,
propsValue: this.onLoadData.propsValue,
relationField: this.onLoadData.relationField,
columnOptions: this.columnOptions.join(','),
paramList
}
if (this.type === 'relation') query = {
...query,
queryType: this.onLoadData.queryType
}
method(this.modelId, query, {
load: page.num == 1
}).then(res => {
if (!this.onLoadData.hasPage) {
this.mescroll.endBySize(res.data.list.length, res.data.pagination.total)
} else {
this.mescroll.endSuccess(res.data.list.length);
}
if (page.num == 1) this.list = [];
this.list = this.list.concat(res.data.list);
if (this.onLoadData.multiple) {
this.list = this.list.map((o, i) => ({
...o,
checked: false
}))
if (this.selectId.length) this.setSelectValue()
} else {
var index = this.list.findIndex((item) => {
return item[this.publicField] == this.selectId
})
if (index >= 0) this.selectRow = [this.list[index]]
}
}).catch(() => {
this.mescroll.endErr();
})
},
setSelectValue() {
outer: for (let i = 0; i < this.selectId.length; i++) {
inner: for (let j = 0; j < this.list.length; j++) {
if (this.selectId[i] === this.list[j][this.publicField]) {
this.list[j].checked = true
break inner
}
}
}
},
interfaceDataHandler(data) {
if (!data.dataProcessing) return data.list
const dataHandler = this.jnpf.getScriptFunc(data.dataProcessing)
if (!dataHandler) return data.list
return dataHandler(data.list)
},
radioChange(item) {
this.selectId = []
this.selectRow = []
this.selectId.push(item[this.publicField]);
this.selectRow.push(item)
},
checkboxChange(e, item) {
if (e.value) {
this.selectId.push(e.name)
this.newSelctData.push(item)
} else {
this.newSelctData = this.newSelctData.filter(o => o[this.publicField] != e.name && !e.value)
this.selectId = this.selectId.filter(o => o != e.name)
this.selectRow = this.selectRow.filter(o => o[this.publicField] != e.name)
}
},
handleConfirm() {
if (this.onLoadData.multiple) {
this.selectRow = this.selectRow.concat(this.newSelctData)
uni.$emit('confirm', this.selectId, this.innerValue, this.onLoadData.vModel, this.selectRow)
uni.navigateBack();
} else {
this.list.map((o, i) => {
if (this.selectId == o[this.publicField]) {
this.firstId = o[this.publicField];
const val = this.type == 'popup' ? o[this.onLoadData.propsValue] : o[this.publicField];
const emit = this.type == 'popup' ? 'confirm' : 'relationConfirm'
uni.$emit(emit, val, this.innerValue, this.onLoadData.vModel, this.selectRow[0])
uni.navigateBack();
}
})
}
},
handleClose() {
this.selectId = ""
uni.navigateBack();
},
search() {
// 节流,避免输入过快多次请求
this.searchTimer && clearTimeout(this.searchTimer)
this.searchTimer = setTimeout(() => {
this.list = [];
this.listQuery.keyword = this.keyword
this.listQuery.currentPage = 1
this.mescroll.resetUpScroll();
}, 300)
},
}
}
</script>
<style scoped lang="scss">
page {
background-color: #f0f2f6;
}
.jnpf-pop-select {
width: 100%;
height: 100%;
padding-bottom: 106rpx;
.tableList {
overflow: hidden auto;
padding: 0 20rpx;
.list-card {
display: flex;
flex-direction: row;
align-items: center;
background-color: #fff;
width: 100%;
border-radius: 8rpx;
margin-top: 20rpx;
padding: 0rpx 20rpx;
min-height: 88rpx;
.fieldContent {
width: 100%;
.fieldList {
width: 752rpx;
.key {
width: 136rpx;
margin-right: 10rpx;
text-align: right;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
line-height: 60rpx;
}
.val {
flex: 0.85;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}
}
}
}
}
.nodata {
margin-top: 258rpx;
justify-content: center;
align-items: center;
image {
width: 280rpx;
height: 215rpx;
}
}
}
</style>

View File

@@ -0,0 +1,133 @@
<template>
<view class="logForm-v jnpf-wrap">
<u-form :model="dataForm" :rules="rules" ref="dataForm" :errorType="['toast']" label-position="left"
label-width="150" label-align="left">
<view class="u-p-l-20 u-p-r-20 form-item-box">
<u-form-item label="日志标题" prop="title" required>
<u-input v-model="dataForm.title" placeholder="请输入日志标题" :disabled="disabled" />
</u-form-item>
<u-form-item label="今日内容" prop="todayContent" required>
<u-input v-model="dataForm.todayContent" type="textarea" placeholder="请输入今日内容"
:disabled="disabled" />
</u-form-item>
<u-form-item label="明日内容" prop="tomorrowContent" required>
<u-input v-model="dataForm.tomorrowContent" type="textarea" placeholder="请输入明日内容"
:disabled="disabled" />
</u-form-item>
<u-form-item label="遇到问题" prop="question" required>
<u-input v-model="dataForm.question" type="textarea" placeholder="请输入遇到问题" :disabled="disabled" />
</u-form-item>
<u-form-item label="发送给谁" prop="userIds" required>
<JnpfUserSelect v-model="dataForm.userIds" multiple :disabled="disabled" />
</u-form-item>
</view>
</u-form>
<view class="com-saveBox" v-if="!disabled">
<u-button type="primary" @click="save">保存</u-button>
</view>
</view>
</template>
<script>
import {
getLogInfo,
createLog,
updateLog
} from '@/api/apply/reportLog.js'
export default {
data() {
return {
dataForm: {
title: '',
todayContent: '',
tomorrowContent: '',
question: '',
userIds: ''
},
rules: {
title: [{
required: true,
message: '日志标题不能为空',
trigger: ['change', 'blur']
}],
todayContent: [{
required: true,
message: '今日内容不能为空',
trigger: ['change', 'blur']
}],
tomorrowContent: [{
required: true,
message: '明日内容不能为空',
trigger: ['change', 'blur']
}],
question: [{
required: true,
message: '问题不能为空',
trigger: ['change', 'blur']
}],
userIds: [{
required: true,
message: '用户不能为空',
trigger: ['change', 'blur'],
type: 'array'
}],
},
type: '0',
disabled: false
}
},
onReady() {
this.$refs.dataForm.setRules(this.rules);
},
onLoad(option) {
this.type = option.type
if (!option.id) {
uni.setNavigationBarTitle({
title: '新增日志'
});
let userInfo = uni.getStorageSync('userInfo') || {}
if (!userInfo.userName) return
this.dataForm.title = userInfo.userName + '的日志'
} else {
if (this.type == '1') this.disabled = true
getLogInfo(option.id).then(res => {
this.dataForm = res.data;
this.dataForm.userIds = this.dataForm.userIds.split(',')
uni.setNavigationBarTitle({
title: this.dataForm.title
});
})
}
},
methods: {
save() {
this.$refs.dataForm.validate((valid) => {
this.dataForm.toUserId = this.dataForm.userIds.join(',')
if (valid) {
const method = this.dataForm.id ? updateLog : createLog
method(this.dataForm).then(res => {
uni.showToast({
title: res.msg,
complete: () => {
setTimeout(() => {
uni.$emit('refresh')
uni.navigateBack()
}, 1500)
}
})
})
}
})
}
}
}
</script>
<style lang="scss">
page {
background-color: #f0f2f6;
}
.logForm-v {
padding-bottom: 140rpx;
}
</style>

View File

@@ -0,0 +1,177 @@
<template>
<view class="reportLog-v">
<mescroll-body ref="mescrollRef" @init="mescrollInit" @down="downCallback" @up="upCallback" :sticky="true"
:down="downOption" :up="upOption" :bottombar="false">
<view class="search-box_sticky">
<u-tabs :list="tabsList" :current="current" @change="change" :is-scroll='false'>
</u-tabs>
<view class="search-box">
<u-search :placeholder="$t('app.apply.pleaseKeyword')" v-model="keyword" height="72"
:show-action="false" @change="search" bg-color="#f0f2f6" shape="square">
</u-search>
</view>
</view>
<view class="log-list" v-for="(item, index) in list" :key="index">
<u-swipe-action :index="index" :show="item.show" @click="handleClick" @open="open" :options="options"
@content-click="goDetail(item.id)">
<view class="log-list-txt u-flex-col">
<view class="u-font-30 u-flex u-m-b-10 log-title">
<text class="title u-line-1">{{item.title}}</text>
<text>{{jnpf.toDate(item.creatorTime ,'MM-dd')}}</text>
</view>
<text class="u-m-t-10">{{userInfo.userName}}/{{userInfo.userAccount}}</text>
</view>
</u-swipe-action>
</view>
</mescroll-body>
<view class="com-addBtn" @click="goDetail()">
<u-icon name="plus" size="48" color="#fff" />
</view>
</view>
</template>
<script>
import {
getSendList,
getReceiveList,
delLog
} from '@/api/apply/reportLog.js'
import resources from '@/libs/resources.js'
import MescrollMixin from "@/uni_modules/mescroll-uni/components/mescroll-uni/mescroll-mixins.js";
export default {
mixins: [MescrollMixin],
data() {
return {
downOption: {
use: true,
auto: true
},
upOption: {
page: {
num: 0,
size: 20,
time: null
},
empty: {
use: true,
icon: resources.message.nodata,
tip: this.$t('common.noData'),
fixed: true,
top: "300rpx",
},
textNoMore: this.$t('app.apply.noMoreData'),
},
current: 0,
tabsList: [{
name: '我发出的'
},
{
name: '我收到的'
}
],
keyword: '',
list: [],
userInfo: {},
options: [{
text: '删除',
style: {
backgroundColor: '#dd524d'
}
}]
}
},
onLoad() {
this.userInfo = uni.getStorageSync('userInfo') || {}
uni.$on('refresh', () => {
this.list = [];
this.current = 0
this.mescroll.resetUpScroll();
})
},
onUnload() {
uni.$off('refresh')
},
methods: {
upCallback(page) {
let query = {
currentPage: page.num,
pageSize: page.size,
keyword: this.keyword
}
const method = this.current ? getReceiveList : getSendList
method(query, {
load: page.num == 1
}).then(res => {
this.mescroll.endSuccess(res.data.list.length);
if (page.num == 1) this.list = [];
const list = res.data.list.map(o => ({
show: false,
...o
}));
this.list = this.list.concat(list);
}).catch(() => {
this.mescroll.endErr();
})
},
open(index) {
this.list[index].show = true;
this.list.map((val, idx) => {
if (index != idx) this.list[idx].show = false;
})
},
handleClick(index, index1) {
const item = this.list[index]
delLog(item.id).then(res => {
this.$u.toast(res.msg)
this.list.splice(index, 1)
if (!this.list.length) this.mescroll.resetUpScroll()
})
},
goDetail(id) {
const url = './form?type=' + this.current + (id ? '&id=' + id : '')
uni.navigateTo({
url: url
})
},
change(index) {
this.current = index;
this.mescroll.resetUpScroll()
},
search() {
this.searchTimer && clearTimeout(this.searchTimer)
this.searchTimer = setTimeout(() => {
this.list = [];
this.mescroll.resetUpScroll();
}, 300)
}
}
}
</script>
<style lang="scss">
page {
background-color: #f0f2f6;
}
.reportLog-v {
.log-list {
width: 100%;
margin-bottom: 20rpx;
color: #9a9a9a;
.log-list-txt {
padding: 16rpx 32rpx;
.log-title {
justify-content: space-between;
.title {
color: #333333;
width: 500rpx;
}
}
}
}
}
</style>

View File

@@ -0,0 +1,262 @@
<template>
<view class="jnpf-pop-select">
<mescroll-body ref="mescrollRef" @init="mescrollInit" @down="downCallback" @up="upCallback" :sticky="true"
:down="downOption" :up="upOption">
<view class="search-box search-box_sticky">
<u-search :placeholder="$t('app.apply.pleaseKeyword')" v-model="keyword" height="72"
:show-action="false" @change="search" bg-color="#f0f2f6" shape="square">
</u-search>
</view>
<view class="u-flex-col tableList">
<view class="u-flex list-card" v-for="(item,index) in list" :key="index">
<u-checkbox-group wrap @change="checkboxGroupChange(item,index)">
<u-checkbox v-model="item.checked">
<view class="u-flex-col fieldContent u-m-l-10">
<view class="fieldList u-line-1 u-flex" v-for="(column,c) in realColumnOptions"
:key="c">
<view class="val">{{column.label+':'}} {{item[column.value]}}</view>
</view>
</view>
</u-checkbox>
</u-checkbox-group>
</view>
</view>
</mescroll-body>
<!-- 底部按钮 -->
<view class="flowBefore-actions">
<u-button class="buttom-btn" @click.stop="handleClose">{{$t('common.cancelText')}}</u-button>
<u-button class="buttom-btn" type="primary" @click.stop="handleConfirm">{{$t('common.okText')}}</u-button>
</view>
</view>
</template>
<script>
import {
getPopSelect,
getRelationSelect
} from '@/api/common.js'
import resources from '@/libs/resources.js'
import MescrollMixin from "@/uni_modules/mescroll-uni/components/mescroll-uni/mescroll-mixins.js";
export default {
mixins: [MescrollMixin],
data() {
return {
downOption: {
use: true,
auto: true
},
upOption: {
page: {
num: 0,
size: 20,
time: null
},
empty: {
use: true,
icon: resources.message.nodata,
tip: this.$t('common.noData'),
fixed: true,
top: "300rpx",
},
textNoMore: this.$t('app.apply.noMoreData'),
},
list: [],
type: '',
onLoadData: {},
keyword: '',
innerValue: '',
listQuery: {
keyword: '',
pageSize: 20
},
cur: null,
selectItem: [],
actionConfig: {},
formData: {},
userInfo: {},
subVal: [],
columnOptions: [],
realColumnOptions: [],
isDynamic: true,
}
},
onLoad(e) {
this.userInfo = uni.getStorageSync('userInfo') || {}
this.onLoadData = JSON.parse(e.data);
this.actionConfig = this.onLoadData.actionConfig
this.isDynamic = this.actionConfig.dataSource == 'dynamic'
this.realColumnOptions = this.actionConfig.columnOptions.filter(o => o.ifShow || o.ifShow === undefined)
this.columnOptions = this.actionConfig.columnOptions.map(o => o.value)
uni.setNavigationBarTitle({
title: this.actionConfig.popupTitle || '选择数据'
})
this.formData = this.onLoadData.formData
this.listQuery.pageSize = this.actionConfig.hasPage && this.isDynamic ? this.actionConfig.pageSize : 10000
uni.$on('refresh', () => {
this.list = [];
this.mescroll.resetUpScroll();
})
},
computed: {
paramList() {
return this.getParamList
}
},
methods: {
upCallback(page) {
const interfaceId = this.actionConfig.interfaceId
const modelId = this.actionConfig.modelId
if (this.isDynamic && !interfaceId) return this.handleEmpty()
if (!this.isDynamic && !modelId) return this.handleEmpty()
let query = {
...this.listQuery,
currentPage: page.num,
keyword: this.keyword,
columnOptions: this.columnOptions.join(',')
}
if (this.isDynamic) {
query.interfaceId = interfaceId
query.paramList = this.paramList()
} else {
query.modelId = this.actionConfig.modelId
query.relationField = this.actionConfig.relationField
}
const id = this.isDynamic ? interfaceId : modelId
const method = this.isDynamic ? getPopSelect : getRelationSelect
method(id, query, {
load: page.num == 1
}).then(res => {
this.mescroll.endSuccess(res.data.list.length);
if (page.num == 1) this.list = [];
this.list = this.list.concat(res.data.list);
this.list = this.list.map((o, i) => ({
...o,
checked: false
}))
}).catch(() => {
this.mescroll.endErr();
})
},
handleEmpty() {
this.mescroll.endSuccess(0);
this.mescroll.endErr()
},
getParamList() {
let templateJson = this.actionConfig.templateJson
for (let i = 0; i < templateJson.length; i++) {
templateJson[i].defaultValue = this.formData[templateJson[i].relationField] || ''
if (templateJson[i].jnpfKey === 'createUser') {
templateJson[i].defaultValue = this.userInfo.userId
}
if (templateJson[i].jnpfKey === 'createTime') {
templateJson[i].defaultValue = new Date().getTime()
}
if (templateJson[i].jnpfKey === 'currOrganize') {
templateJson[i].defaultValue = this.userInfo.organizeId || ''
}
if (templateJson[i].jnpfKey === 'currPosition') {
templateJson[i].defaultValue = this.userInfo.positionId || ''
}
}
return templateJson
},
checkboxGroupChange(e, index) {
this.selectItem = this.list.filter(o => o.checked)
let subVal = []
for (let i = 0; i < this.selectItem.length; i++) {
const e = this.selectItem[i]
let item = {}
for (let j = 0; j < this.actionConfig.relationOptions.length; j++) {
let row = this.actionConfig.relationOptions[j]
item[row.field] = row.type == 1 ? e[!this.isDynamic ? row.value + '_jnpfId' : row.value] : row
.value
}
subVal.push(item)
}
this.subVal = subVal
},
interfaceDataHandler(data) {
if (!data.dataProcessing) return data.list
const dataHandler = this.jnpf.getScriptFunc(data.dataProcessing)
if (!dataHandler) return data.list
return dataHandler(data.list)
},
radioChange(item) {
this.innerValue = item[this.onLoadData.relationField];
},
handleConfirm() {
uni.$emit('linkPageConfirm', this.subVal, this.onLoadData.tableVmodel)
this.handleClose()
},
handleClose() {
uni.navigateBack();
},
search() {
this.searchTimer && clearTimeout(this.searchTimer)
this.searchTimer = setTimeout(() => {
this.list = [];
this.listQuery.keyword = this.keyword
this.listQuery.currentPage = 1
this.listQuery.pageSize = this.hasPage ? this.pageSize : 10000
this.mescroll.resetUpScroll();
}, 300)
},
}
}
</script>
<style scoped lang="scss">
page {
background-color: #f0f2f6;
}
.jnpf-pop-select {
background-color: #f0f2f6;
width: 100%;
padding-bottom: 90rpx;
.tableList {
overflow: hidden auto;
padding: 0 20rpx;
.list-card {
background-color: #fff;
width: 100%;
border-radius: 8rpx;
margin-top: 20rpx;
padding: 20rpx 20rpx;
align-items: flex-start;
.u-checkbox-group {
width: 100%;
.u-checkbox__label {
.fieldContent {
width: 100%;
.fieldList {
width: 752rpx;
.key {
width: 136rpx;
margin-right: 10rpx;
text-align: right;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}
.val {
flex: 0.85;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}
}
}
}
}
}
}
}
</style>