初始提交
242
pages/apply/allAppApply/index.vue
Normal 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>
|
||||
305
pages/apply/catalog/index.vue
Normal 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>
|
||||
228
pages/apply/customBtn/index.vue
Normal 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>
|
||||
75
pages/apply/dynamicModel/bulkOperationMixin.js
Normal 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()
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
596
pages/apply/dynamicModel/components/detail/Item.vue
Normal 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>
|
||||
68
pages/apply/dynamicModel/components/detail/Parser.vue
Normal 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>
|
||||
179
pages/apply/dynamicModel/components/form/index.vue
Normal 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>
|
||||
937
pages/apply/dynamicModel/components/list/index.vue
Normal 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>
|
||||
219
pages/apply/dynamicModel/components/list/list.vue
Normal 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>
|
||||
164
pages/apply/dynamicModel/components/parser/index.vue
Normal 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>
|
||||
125
pages/apply/dynamicModel/components/tableCell.vue
Normal 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>
|
||||
449
pages/apply/dynamicModel/detail.vue
Normal 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>
|
||||
295
pages/apply/dynamicModel/form.vue
Normal 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>
|
||||
120
pages/apply/dynamicModel/index.vue
Normal 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>
|
||||
180
pages/apply/dynamicModel/scanForm.vue
Normal 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>
|
||||
23
pages/apply/externalLink/index.vue
Normal 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>
|
||||
181
pages/apply/interPage/signInvokeList.vue
Normal 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>
|
||||
558
pages/apply/location/index.vue
Normal 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
@@ -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
@@ -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>
|
||||
285
pages/apply/popSelect/index.vue
Normal 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>
|
||||
133
pages/apply/reportLog/form.vue
Normal 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>
|
||||
177
pages/apply/reportLog/index.vue
Normal 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>
|
||||
262
pages/apply/tableLinkage/index.vue
Normal 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>
|
||||
134
pages/commonPage/morePage/allCommonFlow.vue
Normal file
@@ -0,0 +1,134 @@
|
||||
<template>
|
||||
<view class="workFlow-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" @clear="clear" />
|
||||
</view>
|
||||
<view class="commonTabs-box">
|
||||
<CommonTabs :list="categoryTree" @change="change" :current="current" ref="CommonTabs"
|
||||
:isScroll="categoryTree.length >= 4 ? true : false">
|
||||
</CommonTabs>
|
||||
</view>
|
||||
</view>
|
||||
<view class="workFlow-list" style="">
|
||||
<view class="part" v-if="list.length">
|
||||
<view class="caption u-line-1">
|
||||
{{fullName }}
|
||||
</view>
|
||||
<view class="u-flex u-flex-wrap">
|
||||
<view class="item u-flex-col u-col-center" v-for="(child, ii) in list" :key="ii"
|
||||
@click="Jump(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>
|
||||
</view>
|
||||
</template>
|
||||
<script>
|
||||
import CommonTabs from '@/components/CommonTabs'
|
||||
import {
|
||||
getCommonFlowTree
|
||||
} from "@/api/apply/apply.js";
|
||||
export default {
|
||||
components: {
|
||||
CommonTabs
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
keyword: "",
|
||||
category: "",
|
||||
current: 0,
|
||||
categoryTree: [],
|
||||
fullName: '',
|
||||
list: [],
|
||||
searchCategoryTree: []
|
||||
};
|
||||
},
|
||||
created() {
|
||||
uni.showLoading()
|
||||
this.getFlowUsualList();
|
||||
},
|
||||
methods: {
|
||||
getFlowUsualList() {
|
||||
this.keyword = ''
|
||||
getCommonFlowTree().then((res) => {
|
||||
this.categoryTree = res?.data?.list || [];
|
||||
this.searchCategoryTree = JSON.parse(JSON.stringify(this.categoryTree))
|
||||
this.list = []
|
||||
this.$nextTick(() => {
|
||||
this.list = this.categoryTree[this.current]?.children || []
|
||||
this.fullName = this.categoryTree[this.current]?.fullName;
|
||||
})
|
||||
uni.hideLoading()
|
||||
}).catch(() => {
|
||||
this.categoryTree = []
|
||||
this.list = []
|
||||
})
|
||||
},
|
||||
search() {
|
||||
this.searchTimer && clearTimeout(this.searchTimer);
|
||||
this.searchTimer = setTimeout(() => {
|
||||
if (!this.keyword) return this.clear()
|
||||
let children = this.searchCategoryTree[this.current].children.filter(o => o.fullName.includes(
|
||||
this.keyword))
|
||||
this.$set(this.categoryTree[this.current], 'children', children)
|
||||
this.list = this.categoryTree[this.current].children
|
||||
}, 300);
|
||||
},
|
||||
clear() {
|
||||
this.getFlowUsualList();
|
||||
},
|
||||
change(i) {
|
||||
this.list = this.categoryTree[i].children
|
||||
this.fullName = this.categoryTree[i].fullName;
|
||||
this.keyword = ''
|
||||
this.current = i
|
||||
},
|
||||
Jump(item) {
|
||||
const config = {
|
||||
id: "",
|
||||
flowId: item.id,
|
||||
opType: "-1",
|
||||
};
|
||||
this.current = 0
|
||||
this.category = ""
|
||||
uni.navigateTo({
|
||||
url: "/pages/workFlow/flowBefore/index?config=" +
|
||||
this.jnpf.base64.encode(JSON.stringify(config))
|
||||
});
|
||||
}
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
page {
|
||||
background-color: #f0f2f6;
|
||||
}
|
||||
|
||||
.workFlow-v {
|
||||
height: 100%;
|
||||
|
||||
.workFlow-list {
|
||||
margin-top: 120px;
|
||||
}
|
||||
|
||||
.notice-warp {
|
||||
height: 115rpx !important;
|
||||
|
||||
.search-box {
|
||||
padding: 20rpx;
|
||||
}
|
||||
}
|
||||
|
||||
.commonTabs-box {
|
||||
height: 2.8rem;
|
||||
}
|
||||
|
||||
}
|
||||
</style>
|
||||
286
pages/commonPage/morePage/allCommonMenus.vue
Normal file
@@ -0,0 +1,286 @@
|
||||
<template>
|
||||
<view class="all-apply-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" />
|
||||
</view>
|
||||
<view>
|
||||
<CommonTabs :list="tabsMenuList" @change="change" :current="current" ref="CommonTabs">
|
||||
</CommonTabs>
|
||||
</view>
|
||||
</view>
|
||||
<mescroll-uni @init="mescrollInit" @down="downCallback" @up="upCallback" :down="downOption" :up="upOption"
|
||||
top='220'>
|
||||
<view class="workFlow-list">
|
||||
<view class="part" v-for="(item, i) in menuList" :key="i" v-if=" menuList.length && hasChildren">
|
||||
<view class="caption u-line-1">
|
||||
{{ 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="handleClick(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>
|
||||
</mescroll-uni>
|
||||
</view>
|
||||
</template>
|
||||
<script>
|
||||
import {
|
||||
getAppDataList
|
||||
} from "@/api/apply/apply.js";
|
||||
import resources from "@/libs/resources.js";
|
||||
import CommonTabs from '@/components/CommonTabs'
|
||||
import MescrollMixin from "@/uni_modules/mescroll-uni/components/mescroll-uni/mescroll-mixins.js";
|
||||
export default {
|
||||
mixins: [MescrollMixin],
|
||||
components: {
|
||||
CommonTabs
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
current: 0,
|
||||
tabsMenuList: [],
|
||||
menuList: [],
|
||||
downOption: {
|
||||
use: true,
|
||||
auto: true,
|
||||
},
|
||||
upOption: {
|
||||
page: {
|
||||
num: 0,
|
||||
size: 50,
|
||||
time: null,
|
||||
},
|
||||
empty: {
|
||||
use: false,
|
||||
icon: resources.message.nodata,
|
||||
tip: "暂无数据",
|
||||
fixed: true,
|
||||
top: "560rpx",
|
||||
},
|
||||
textNoMore: "",
|
||||
},
|
||||
keyword: "",
|
||||
userInfo: {
|
||||
systemIds: [],
|
||||
}, //CurrentUser接口中的userInfo数据
|
||||
key: +new Date()
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
baseURL() {
|
||||
return this.define.baseURL;
|
||||
},
|
||||
token() {
|
||||
return uni.getStorageSync('token')
|
||||
},
|
||||
report() {
|
||||
return this.define.report;
|
||||
},
|
||||
pcURL() {
|
||||
return this.define.pcURL;
|
||||
},
|
||||
hasChildren() {
|
||||
let hasChildren = false
|
||||
for (let i = 0; i < this.menuList.length; i++) {
|
||||
if (this.menuList[i].children && this.menuList[i].children.length) {
|
||||
hasChildren = true
|
||||
break
|
||||
}
|
||||
}
|
||||
return hasChildren
|
||||
}
|
||||
},
|
||||
created() {
|
||||
uni.$on('refresh', () => {
|
||||
this.menuList = [];
|
||||
this.current = 0;
|
||||
this.mescroll.resetUpScroll();
|
||||
});
|
||||
},
|
||||
methods: {
|
||||
classifyItem(index) {
|
||||
this.change(index)
|
||||
},
|
||||
upCallback(keyword) {
|
||||
let query = {
|
||||
keyword: this.keyword,
|
||||
type: 2
|
||||
};
|
||||
uni.showLoading({
|
||||
title: '正在加载',
|
||||
mask: true
|
||||
})
|
||||
getAppDataList(query).then(res => {
|
||||
let list = res.data.list || [];
|
||||
if (!list.length) this.current = 0
|
||||
this.tabsMenuList = [{
|
||||
fullName: "全部功能"
|
||||
}];
|
||||
this.mescroll.endSuccess(list.length);
|
||||
for (let i = 0; i < list.length; i++) {
|
||||
let children = list[i].children;
|
||||
let tabsMenuList = {
|
||||
fullName: list[i].fullName,
|
||||
};
|
||||
this.tabsMenuList.push(tabsMenuList);
|
||||
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.list = JSON.parse(JSON.stringify(list));
|
||||
if (this.current === 0) {
|
||||
let allApp = [{
|
||||
fullName: '全部功能',
|
||||
children: this.jnpf.treeToArray(this.list).filter(o => !o.hasChildren),
|
||||
id: 0
|
||||
}]
|
||||
this.menuList = allApp
|
||||
} else {
|
||||
this.menuList = this.list
|
||||
}
|
||||
uni.hideLoading()
|
||||
this.key = +new Date();
|
||||
this.mescroll.endSuccess(this.menuList.length, false);
|
||||
}).catch(() => {
|
||||
this.mescroll.endSuccess(0);
|
||||
this.mescroll.endErr();
|
||||
});
|
||||
},
|
||||
change(index) {
|
||||
this.current = index;
|
||||
this.menuList = this.list;
|
||||
if (this.current === 0) {
|
||||
let allApp = [{
|
||||
fullName: '全部功能',
|
||||
children: this.jnpf.treeToArray(this.list).filter(o => !o.hasChildren),
|
||||
id: 0
|
||||
}]
|
||||
this.menuList = allApp
|
||||
} else {
|
||||
this.menuList = [this.list[index - 1]] || [];
|
||||
}
|
||||
},
|
||||
search() {
|
||||
this.searchTimer && clearTimeout(this.searchTimer);
|
||||
this.searchTimer = setTimeout(() => {
|
||||
this.list = [];
|
||||
this.menuList = [];
|
||||
this.tabsMenuList = [];
|
||||
this.current = 0
|
||||
this.mescroll.resetUpScroll();
|
||||
}, 300);
|
||||
},
|
||||
handleClick(item) {
|
||||
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" scoped>
|
||||
page {
|
||||
background-color: #f0f2f6;
|
||||
}
|
||||
|
||||
.all-apply-v {
|
||||
height: 100%;
|
||||
|
||||
.notice-warp {
|
||||
height: 3.59rem !important;
|
||||
text-align: left;
|
||||
|
||||
.search-box {
|
||||
padding: 20rpx;
|
||||
}
|
||||
}
|
||||
|
||||
.commonTabs-box {
|
||||
height: 2.8rem;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
35
pages/commonPage/morePage/index.vue
Normal file
@@ -0,0 +1,35 @@
|
||||
<template>
|
||||
<view class="morePage-v">
|
||||
<allCommonFlow ref="allCommonFlow" v-if="type == 1"></allCommonFlow>
|
||||
<allCommonMenus ref="allCommonMenus" v-if="type == 2"></allCommonMenus>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import allCommonFlow from './allCommonFlow.vue'
|
||||
import allCommonMenus from './allCommonMenus.vue'
|
||||
export default {
|
||||
components: {
|
||||
allCommonFlow,
|
||||
allCommonMenus
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
type: '1'
|
||||
}
|
||||
},
|
||||
onLoad(e) {
|
||||
this.type = e?.type || '1'
|
||||
uni.setNavigationBarTitle({
|
||||
title: this.type == '1' ? '收藏审批' : '收藏功能'
|
||||
})
|
||||
},
|
||||
methods: {}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
page {
|
||||
background-color: #f0f2f6;
|
||||
}
|
||||
</style>
|
||||
296
pages/formShortLink/detail.vue
Normal file
@@ -0,0 +1,296 @@
|
||||
<template>
|
||||
<view class="dynamicModel-form-v jnpf-wrap jnpf-wrap-form" v-if="showPage">
|
||||
<uni-nav-bar class='nav' :fixed="true" :statusBar="true" :border="false" height="44">
|
||||
<view class="nav-left">
|
||||
<view class="nav-left-text">详情</view>
|
||||
</view>
|
||||
</uni-nav-bar>
|
||||
<Parser :formConf="formConf" :formValue="formData" ref="dynamicForm" v-if="!loading" :key="key"
|
||||
@toDetail="toDetail" />
|
||||
<view class="buttom-actions">
|
||||
<u-button class="buttom-btn" @click.stop="jnpf.goBack">取消</u-button>
|
||||
<u-button class="buttom-btn" type="primary" @click.stop="handleEdit"
|
||||
v-if="btnType === 'btn_edit'&&!this.setting.noShowBtn">编辑
|
||||
</u-button>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {
|
||||
getConfig,
|
||||
createModel,
|
||||
getDataChange
|
||||
} from '@/api/apply/webDesign'
|
||||
import Parser from '@/pages/apply/dynamicModel/components/detail/Parser'
|
||||
const getFormDataFields = item => {
|
||||
const config = item.__config__
|
||||
if (!config || !config.jnpfKey) return true
|
||||
const jnpfKey = config.jnpfKey
|
||||
const list = ["input", "textarea", "inputNumber", "switch", "datePicker", "timePicker", "colorPicker", "rate",
|
||||
"slider", "editor", "link", "text", "alert", 'table', "collapse", 'collapseItem', 'tabItem',
|
||||
"tab", "row", "card", "groupTitle", "divider", 'location', 'stepItem', 'steps'
|
||||
]
|
||||
const fieldsSelectList = ["radio", "checkbox", "select", "cascader", "treeSelect"]
|
||||
if (list.includes(jnpfKey) || (fieldsSelectList.includes(jnpfKey) && config.dataType === 'static')) return true
|
||||
return false
|
||||
}
|
||||
export default {
|
||||
components: {
|
||||
Parser
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
showPage: false,
|
||||
loading: true,
|
||||
isPreview: '0',
|
||||
modelId: '',
|
||||
formConf: {},
|
||||
formData: {},
|
||||
dataForm: {
|
||||
id: '',
|
||||
data: ''
|
||||
},
|
||||
btnType: '',
|
||||
formPermissionList: {},
|
||||
formList: [],
|
||||
encryption: ''
|
||||
}
|
||||
},
|
||||
onLoad(option) {
|
||||
let config = JSON.parse(this.jnpf.base64.decode(option.config))
|
||||
this.formPermissionList = !config.currentMenu ? [] : JSON.parse(decodeURIComponent(config.currentMenu))
|
||||
this.formList = this.formPermissionList.formList
|
||||
this.btnType = config.jurisdictionType || ''
|
||||
this.modelId = config.modelId;
|
||||
this.encryption = config.encryption;
|
||||
this.isPreview = config.isPreview || '0';
|
||||
this.dataForm.id = config.id || ''
|
||||
this.setting = config
|
||||
this.getConfigData()
|
||||
uni.$on('refresh', () => {
|
||||
this.getConfigData()
|
||||
})
|
||||
},
|
||||
beforeDestroy() {
|
||||
uni.$off('refresh')
|
||||
},
|
||||
methods: {
|
||||
// 递归过滤
|
||||
recursivefilter(arr, value) {
|
||||
let newColumn = arr.filter(item => getFormDataFields(item))
|
||||
newColumn.forEach(x =>
|
||||
x.__config__ && x.__config__.children && Array.isArray(x.__config__.children) && (x
|
||||
.__config__.children = this.recursivefilter(x.__config__.children))
|
||||
)
|
||||
return newColumn
|
||||
},
|
||||
getConfigData() {
|
||||
this.loading = true
|
||||
getConfig(this.modelId, this.encryption).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.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
|
||||
}
|
||||
getDataChange(this.modelId, this.dataForm.id, this.encryption).then(res => {
|
||||
this.dataForm = res.data
|
||||
if (!this.dataForm.data) return
|
||||
this.formData = {
|
||||
...JSON.parse(this.dataForm.data),
|
||||
id: this.dataForm.id
|
||||
}
|
||||
let fields = this.recursivefilter(this.formConf.fields)
|
||||
this.formConf.fields = fields
|
||||
this.fillFormData(fields, this.formData)
|
||||
this.initRelationForm(fields)
|
||||
})
|
||||
} else {
|
||||
this.loading = false
|
||||
}
|
||||
this.key = +new Date()
|
||||
})
|
||||
},
|
||||
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', data[item.__vModel__] || '')
|
||||
} else {
|
||||
let val = data.hasOwnProperty(item.__vModel__) ? data[item.__vModel__] : item
|
||||
.__config__.defaultValue
|
||||
if (!item.__config__.custom && item.__config__.defaultCurrent && item.__config__
|
||||
.jnpfKey === 'time') val = this.jnpf.toDate(new Date(), item.format)
|
||||
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)
|
||||
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.__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
|
||||
}
|
||||
this.$nextTick(() => {
|
||||
const url =
|
||||
'/pages/apply/dynamicModel/detail?config=' + this.base64.encode(JSON.stringify(config),
|
||||
"UTF-8")
|
||||
uni.navigateTo({
|
||||
url: url
|
||||
})
|
||||
})
|
||||
},
|
||||
handleEdit() {
|
||||
const currentMenu = encodeURIComponent(JSON.stringify(this.formPermissionList))
|
||||
let config = {
|
||||
modelId: this.modelId,
|
||||
isPreview: this.isPreview,
|
||||
id: this.setting.id,
|
||||
jurisdictionType: 'btn_edit',
|
||||
currentMenu,
|
||||
list: this.setting.list,
|
||||
index: this.setting.index
|
||||
}
|
||||
const url = '/pages/apply/dynamicModel/form?config=' + this.base64.encode(JSON.stringify(config), "UTF-8")
|
||||
uni.navigateTo({
|
||||
url: url
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
page {
|
||||
background-color: #f0f2f6;
|
||||
}
|
||||
|
||||
.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: 32rpx;
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
.right-icons {
|
||||
font-weight: 700;
|
||||
margin-top: 2px;
|
||||
margin-left: 4px;
|
||||
transition-duration: 0.3s;
|
||||
}
|
||||
|
||||
.select-right-icons {
|
||||
transform: rotate(-180deg);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
326
pages/formShortLink/index.vue
Normal file
@@ -0,0 +1,326 @@
|
||||
<template>
|
||||
<view>
|
||||
<uni-nav-bar :fixed="true" :statusBar="true" :border="false" height="44">
|
||||
<view class="nav-left">
|
||||
<view class="nav-left-text">{{config.fullName}}</view>
|
||||
</view>
|
||||
</uni-nav-bar>
|
||||
<view v-if="!showPsd">
|
||||
<template v-if="type==='form' || type==='list' || type === 'detail'">
|
||||
<view v-if="type==='form' || type === 'detail'">
|
||||
<view class="jnpf-wrap jnpf-wrap-form" v-if="!loading && (type==='form' || type === 'detail')">
|
||||
<JnpfParser :formConf="formConf" :isShortLink="true" ref="dynamicForm" @submit="sumbitForm"
|
||||
:key="newDate" />
|
||||
<view class="buttom-actions" v-if="type==='form'">
|
||||
<u-button class="buttom-btn" @click.stop="resetForm">重置</u-button>
|
||||
<u-button class="buttom-btn" type="primary" @click.stop="submit" :loading="btnLoading">
|
||||
{{formConf.confirmButtonText||'确定'}}
|
||||
</u-button>
|
||||
</view>
|
||||
<view class="buttom-actions" v-if="type==='detail'">
|
||||
<u-button class="buttom-btn" @click.stop="resetForm">取消</u-button>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view v-if="type==='list' && flg">
|
||||
<List ref="List" :config="config" :modelId="modelId" :columnText="columnText"
|
||||
:columnCondition="columnCondition" :encryption='encryption' />
|
||||
</view>
|
||||
</template>
|
||||
</view>
|
||||
<view v-show="!showPsd"></view>
|
||||
<u-modal v-model="showPsd" :title-style="titleStyle" title="密码" @confirm="confirm" v-if="showPsd">
|
||||
<view class="slot-content u-p-l-32 u-p-r-22 u-p-t-20 u-p-b-20">
|
||||
<u-input type="password" placeholder="请输入密码" :border="true" v-model="password" />
|
||||
</view>
|
||||
</u-modal>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {
|
||||
getConfig,
|
||||
createModel,
|
||||
getShortLink,
|
||||
checkPwd
|
||||
} from '@/api/apply/webDesign'
|
||||
import md5Libs from "/uni_modules/vk-uview-ui/libs/function/md5";
|
||||
import List from './list.vue'
|
||||
const getFormDataFields = item => {
|
||||
const config = item.__config__
|
||||
if (!config || !config.jnpfKey) return true
|
||||
const jnpfKey = config.jnpfKey
|
||||
const list = ["input", "textarea", "inputNumber", "switch", "datePicker", "timePicker", "colorPicker", "rate",
|
||||
"slider", "editor", "link", "text", "alert", 'table', "collapse", 'collapseItem', 'tabItem',
|
||||
"tab", "row", "card", "groupTitle", "divider", 'location', 'stepItem', 'steps'
|
||||
]
|
||||
const fieldsSelectList = ["radio", "checkbox", "select", "cascader", "treeSelect"]
|
||||
if (list.includes(jnpfKey) || (fieldsSelectList.includes(jnpfKey) && config.dataType === 'static')) return true
|
||||
return false
|
||||
}
|
||||
export default {
|
||||
components: {
|
||||
List
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
columnCondition: [],
|
||||
columnText: [],
|
||||
flg: false,
|
||||
password: '',
|
||||
titleStyle: {
|
||||
paddingTop: '24rpx'
|
||||
},
|
||||
showPsd: false,
|
||||
dataForm: {
|
||||
data: ''
|
||||
},
|
||||
formConf: {},
|
||||
newDate: +new Date(),
|
||||
btnLoading: false,
|
||||
loading: true,
|
||||
modelId: '',
|
||||
config: {},
|
||||
type: 'form',
|
||||
shortLinkData: {},
|
||||
formData: {},
|
||||
encryption: ''
|
||||
}
|
||||
},
|
||||
onLoad(e) {
|
||||
this.formData = e.formData ? JSON.parse(e.formData) : {};
|
||||
const decryptedData = this.jnpf.aesEncryption.decrypt(e.encryption)
|
||||
if (!decryptedData) return
|
||||
const decrypt = JSON.parse(decryptedData)
|
||||
this.encryption = e.encryption
|
||||
this.modelId = decrypt.modelId
|
||||
this.type = decrypt.type
|
||||
this.getShortLink()
|
||||
this.getConfig()
|
||||
},
|
||||
methods: {
|
||||
// 递归过滤
|
||||
recursivefilter(arr, value) {
|
||||
let newColumn = arr.filter(item => getFormDataFields(item))
|
||||
newColumn.forEach(x =>
|
||||
x.__config__ && x.__config__.children && Array.isArray(x.__config__.children) && (x
|
||||
.__config__.children = this.recursivefilter(x.__config__.children))
|
||||
)
|
||||
return newColumn
|
||||
},
|
||||
getConfig() {
|
||||
getConfig(this.modelId, this.encryption).then(res => {
|
||||
this.config = res.data || {}
|
||||
this.formConf = JSON.parse(this.config.formData) || {}
|
||||
this.beforeInit(this.formConf.fields)
|
||||
let fields = this.recursivefilter(this.formConf.fields)
|
||||
this.formConf.fields = fields
|
||||
this.fillFormData(fields, this.formData)
|
||||
this.$nextTick(() => {
|
||||
this.flg = true
|
||||
this.newDate = +new Date()
|
||||
this.loading = false
|
||||
})
|
||||
})
|
||||
},
|
||||
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)
|
||||
},
|
||||
getShortLink() {
|
||||
getShortLink(this.modelId, this.encryption).then(res => {
|
||||
this.shortLinkData = res.data || {}
|
||||
this.columnCondition = JSON.parse(this.shortLinkData.columnCondition)
|
||||
this.columnText = JSON.parse(this.shortLinkData.columnText)
|
||||
if (this.type == 'list' && this.shortLinkData.columnPassUse == 1) this.showPsd = true
|
||||
if (this.type == 'form' && this.shortLinkData.formPassUse == 1) this.showPsd = true
|
||||
this.newDate = +new Date()
|
||||
})
|
||||
},
|
||||
confirm() {
|
||||
let data = {
|
||||
id: this.modelId,
|
||||
password: md5Libs.md5(this.password),
|
||||
type: this.type == 'form' ? 0 : 1,
|
||||
encryption: this.encryption
|
||||
}
|
||||
checkPwd(data).then(res => {
|
||||
this.showPsd = false
|
||||
this.newDate = +new Date()
|
||||
}).catch(err => {
|
||||
this.showPsd = true
|
||||
this.password = ''
|
||||
this.newDate = +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.custom && config.defaultCurrent) {
|
||||
if (config.jnpfKey === 'timePicker') {
|
||||
config.defaultValue = this.jnpf.toDate(new Date(), this.jnpf.handelFormat(item
|
||||
.format))
|
||||
}
|
||||
if (config.jnpfKey === 'datePicker') {
|
||||
config.defaultValue = new Date().getTime()
|
||||
}
|
||||
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
|
||||
}
|
||||
if (config.jnpfKey === 'userSelect' && this.userInfo.userId) {
|
||||
config.defaultValue = item.multiple ? [this.userInfo.userId] :
|
||||
this.userInfo.userId;
|
||||
}
|
||||
if (config.jnpfKey === 'usersSelect' && this.userInfo.userId) {
|
||||
config.defaultValue = [this.userInfo.userId + '--user']
|
||||
}
|
||||
}
|
||||
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) && item
|
||||
.__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)
|
||||
},
|
||||
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, this.encryption).then(res => {
|
||||
uni.showToast({
|
||||
title: res.msg,
|
||||
complete: () => {
|
||||
setTimeout(() => {
|
||||
this.btnLoading = false
|
||||
this.resetForm()
|
||||
}, 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.newDate = +new Date()
|
||||
this.$nextTick(() => {
|
||||
this.loading = false
|
||||
this.$refs.dynamicForm && this.$refs.dynamicForm.resetForm()
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style lang="scss">
|
||||
page {
|
||||
background-color: #f0f2f6;
|
||||
}
|
||||
|
||||
.nav {
|
||||
z-index: 99999;
|
||||
|
||||
.uni-navbar__content {
|
||||
z-index: 99999;
|
||||
}
|
||||
|
||||
.uni-navbar__header-container {
|
||||
justify-content: center;
|
||||
}
|
||||
}
|
||||
|
||||
.nav-left {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
width: 100%;
|
||||
text-align: center;
|
||||
|
||||
.nav-left-text {
|
||||
font-weight: 700;
|
||||
font-size: 32rpx;
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
.right-icons {
|
||||
font-weight: 700;
|
||||
margin-top: 2px;
|
||||
margin-left: 4px;
|
||||
transition-duration: 0.3s;
|
||||
}
|
||||
|
||||
.select-right-icons {
|
||||
transform: rotate(-180deg);
|
||||
}
|
||||
}
|
||||
|
||||
.pasd_box {
|
||||
width: 100%;
|
||||
padding: 60% 0;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
box-sizing: border-box;
|
||||
|
||||
.pasd_box_input {
|
||||
box-sizing: border-box;
|
||||
|
||||
.ipt {
|
||||
border-radius: 8rpx 0 0 8rpx;
|
||||
border: 1px solid red;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
333
pages/formShortLink/list.vue
Normal file
@@ -0,0 +1,333 @@
|
||||
<template>
|
||||
<view class="dynamicModel-list-v">
|
||||
<view class="head-warp com-dropdown">
|
||||
<u-dropdown class="u-dropdown" ref="uDropdown">
|
||||
<u-dropdown-item title="筛选">
|
||||
<view class="screen-box">
|
||||
<view class="screen-list" v-if="showParser && columnCondition.length">
|
||||
<view class="u-p-l-20 u-p-r-20 list">
|
||||
<scroll-view scroll-y="true" style="height: 100%;">
|
||||
<Parser :formConf="columnCondition" :searchFormData="searchFormData"
|
||||
:webType="config.webType" ref="searchForm" @submit="sumbitSearchForm" />
|
||||
</scroll-view>
|
||||
</view>
|
||||
</view>
|
||||
<JnpfEmpty v-else />
|
||||
<view class="buttom-actions" v-if="showParser && columnCondition.length" style="z-index: 1;">
|
||||
<u-button class="buttom-btn" @click="reset">{{$t('common.resetText')}}</u-button>
|
||||
<u-button class="buttom-btn" type="primary"
|
||||
@click="closeDropdown">{{$t('common.queryText')}}</u-button>
|
||||
</view>
|
||||
</view>
|
||||
</u-dropdown-item>
|
||||
</u-dropdown>
|
||||
</view>
|
||||
<view class="list-warp">
|
||||
<mescroll-uni ref="mescrollRef" @init="mescrollInit" @down="downCallback" @up="upCallback" :up="upOption"
|
||||
top="164">
|
||||
<view class="list u-p-b-20 u-p-l-20 u-p-r-20" ref="tableRef">
|
||||
<view class="list-box">
|
||||
<uni-swipe-action ref="swipeAction">
|
||||
<uni-swipe-action-item v-for="(item, index) in list" :key="item.id" :threshold="0"
|
||||
:disabled="true">
|
||||
<view class="item" @click="goDetail(item)">
|
||||
<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>
|
||||
<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 == 'rate'">
|
||||
<JnpfRate v-model="item[column.prop]" :count="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">
|
||||
</tableCell>
|
||||
</view>
|
||||
</view>
|
||||
</uni-swipe-action-item>
|
||||
</uni-swipe-action>
|
||||
</view>
|
||||
</view>
|
||||
</mescroll-uni>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import tableCell from '@/pages/apply/dynamicModel/components/tableCell.vue'
|
||||
import resources from '@/libs/resources.js'
|
||||
import MescrollMixin from "@/uni_modules/mescroll-uni/components/mescroll-uni/mescroll-mixins.js";
|
||||
import Parser from '@/pages/apply/dynamicModel/components/parser/index.vue'
|
||||
import {
|
||||
listLink
|
||||
} from '@/api/apply/webDesign'
|
||||
export default {
|
||||
mixins: [MescrollMixin],
|
||||
props: ['config', 'modelId', 'columnCondition', 'columnText', 'encryption'],
|
||||
components: {
|
||||
Parser,
|
||||
tableCell
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
show: false,
|
||||
upOption: {
|
||||
page: {
|
||||
num: 0,
|
||||
size: 10,
|
||||
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: {
|
||||
sidx: '',
|
||||
keyword: '',
|
||||
queryJson: ''
|
||||
},
|
||||
options: [{
|
||||
text: '删除',
|
||||
style: {
|
||||
backgroundColor: '#dd524d'
|
||||
}
|
||||
}],
|
||||
showParser: false,
|
||||
columnList: {},
|
||||
searchList: [],
|
||||
searchFormConf: [],
|
||||
searchFormData: {},
|
||||
key: +new Date()
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.init()
|
||||
},
|
||||
methods: {
|
||||
init() {
|
||||
this.columnList = this.transformColumnList(this.columnText)
|
||||
this.columnList.map((o) => {
|
||||
if (o.jnpfKey != 'table' && o.label.length > 4) {
|
||||
o.label = o.label.substring(0, 4)
|
||||
}
|
||||
})
|
||||
let config = JSON.parse(this.config.appColumnData)
|
||||
this.setDefaultQuery(config.defaultSortConfig)
|
||||
this.$nextTick(() => {
|
||||
this.key = +new Date()
|
||||
})
|
||||
},
|
||||
setDefaultQuery(defaultSortList) {
|
||||
const defaultSortConfig = (defaultSortList || []).map(o =>
|
||||
(o.sort === 'desc' ? '-' : '') + o.field);
|
||||
this.listQuery.sidx = defaultSortConfig.join(',')
|
||||
},
|
||||
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
|
||||
}
|
||||
},
|
||||
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 + '-', '');
|
||||
let newItem = {
|
||||
align: "center",
|
||||
jnpfKey: "table",
|
||||
prop,
|
||||
label,
|
||||
children: []
|
||||
}
|
||||
e.vModel = vModel
|
||||
e.childLabel = 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
|
||||
},
|
||||
upCallback(page) {
|
||||
if (this.isPreview == '1') return this.mescroll.endSuccess(0, false);
|
||||
const query = {
|
||||
currentPage: page.num,
|
||||
pageSize: page.size,
|
||||
menuId: this.modelId,
|
||||
...this.listQuery
|
||||
}
|
||||
listLink(this.modelId, query, this.encryption, {
|
||||
load: page.num == 1
|
||||
}, this.encryption).then(res => {
|
||||
this.showParser = true
|
||||
if (page.num == 1) this.list = [];
|
||||
this.mescroll.endSuccess(res.data.list.length);
|
||||
const list = res.data.list.map((o, i) => ({
|
||||
show: false,
|
||||
...o
|
||||
}));
|
||||
this.list = this.list.concat(list);
|
||||
uni.$off('refresh')
|
||||
}).catch((err) => {
|
||||
this.mescroll.endByPage(0, 0);
|
||||
this.mescroll.endErr();
|
||||
uni.$off('refresh')
|
||||
})
|
||||
},
|
||||
goDetail(item) {
|
||||
if (!item.id) return
|
||||
let config = {
|
||||
modelId: this.modelId,
|
||||
id: item.id,
|
||||
formTitle: '详情',
|
||||
noShowBtn: 1,
|
||||
encryption: this.encryption
|
||||
}
|
||||
this.$nextTick(() => {
|
||||
const url = `./detail?config=${this.jnpf.base64.encode(JSON.stringify(config),"UTF-8")}`
|
||||
uni.navigateTo({
|
||||
url: url
|
||||
})
|
||||
})
|
||||
},
|
||||
reset() {
|
||||
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
|
||||
config.defaultValue = defaultValue
|
||||
this.searchFormData[item.__vModel__] = defaultValue
|
||||
}
|
||||
this.searchFormConf = JSON.parse(JSON.stringify(this.searchList))
|
||||
},
|
||||
closeDropdown() {
|
||||
if (this.isPreview == '1') return this.$u.toast('功能预览不支持检索')
|
||||
this.$refs.searchForm && this.$refs.searchForm.submitForm()
|
||||
},
|
||||
fillFormData(list, data) {
|
||||
for (let i = 0; i < list.length; i++) {
|
||||
let item = list[i]
|
||||
const val = data.hasOwnProperty(item.__vModel__) ? data[item.__vModel__] : item.__config__
|
||||
.defaultValue
|
||||
if (!item.__config__.custom && item.__config__.defaultCurrent && item.__config__
|
||||
.jnpfKey === 'timePicker') val = this.jnpf.toDate(new Date(), item.format)
|
||||
if (!item.__config__.custom && item.__config__.defaultCurrent && item.__config__
|
||||
.jnpfKey === 'datePicker') val = new Date().getTime()
|
||||
item.__config__.defaultValue = val
|
||||
}
|
||||
},
|
||||
sumbitSearchForm(data) {
|
||||
const queryJson = data || {}
|
||||
this.searchFormData = data
|
||||
this.listQuery.queryJson = JSON.stringify(queryJson) !== '{}' ? JSON.stringify(queryJson) : ''
|
||||
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 */
|
||||
}
|
||||
|
||||
.item {
|
||||
padding: 0 !important;
|
||||
}
|
||||
|
||||
.notData-box {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
padding-bottom: 200rpx;
|
||||
|
||||
.notData-inner {
|
||||
width: 280rpx;
|
||||
height: 308rpx;
|
||||
align-items: center;
|
||||
|
||||
|
||||
.iconImg {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.notData-inner-text {
|
||||
padding: 30rpx 0;
|
||||
color: #909399;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.screen-box {
|
||||
background-color: #fff;
|
||||
height: 100%;
|
||||
|
||||
.screen-list {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
|
||||
.list {
|
||||
height: calc(100% - 88rpx);
|
||||
overflow-y: scroll;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
182
pages/index/components/PasswordPopup/index.vue
Normal file
@@ -0,0 +1,182 @@
|
||||
<template>
|
||||
<u-popup v-model="showPopup" mode="center" length="auto">
|
||||
<view class="jnpf-wrap jnpf-wrap-workflow">
|
||||
<u-form :model="dataForm" :rules="rules" ref="dataForm" label-position="left" label-width="150"
|
||||
label-align="left">
|
||||
<u-form-item label="旧密码" prop="oldPassword" required>
|
||||
<u-input v-model="dataForm.oldPassword" placeholder="旧密码" type="password"></u-input>
|
||||
</u-form-item>
|
||||
<u-form-item label="新密码" prop="password" required>
|
||||
<u-input v-model="dataForm.password" placeholder="新密码" type="password"></u-input>
|
||||
</u-form-item>
|
||||
<u-form-item label="重复密码" prop="repeatPsd" required>
|
||||
<u-input v-model="dataForm.repeatPsd" placeholder="重复密码" type="password"></u-input>
|
||||
</u-form-item>
|
||||
<u-form-item label="验证码" prop="code" required>
|
||||
<view class="u-flex">
|
||||
<u-input v-model="dataForm.code" placeholder="验证码"></u-input>
|
||||
<view style="flex: 0.1">
|
||||
<u-image :showLoading="true" :src="baseURL + imgUrl" width="130px" height="38px"
|
||||
@click="changeCode">
|
||||
</u-image>
|
||||
</view>
|
||||
</view>
|
||||
</u-form-item>
|
||||
<u-button class="buttom-btn" type="primary" @click.stop="dataFormSubmit">
|
||||
{{ "保存" }}
|
||||
</u-button>
|
||||
</u-form>
|
||||
</view>
|
||||
</u-popup>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import md5Libs from "@/uni_modules/vk-uview-ui/libs/function/md5";
|
||||
export default {
|
||||
props: {
|
||||
passwordShow: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
baseForm: {
|
||||
type: Object,
|
||||
default: () => {}
|
||||
},
|
||||
},
|
||||
data() {
|
||||
var validatePass = (rule, value, callback) => {
|
||||
// const passwordreg = /(?=.*\d)(?=.*[a-zA-Z])(?=.*[^a-zA-Z0-9]).{6,16}/
|
||||
//是否包含数字
|
||||
const containsNumbers = /[0-9]+/;
|
||||
//是否包含小写字符
|
||||
const includeLowercaseLetters = /[a-z]+/;
|
||||
//是否包含大写字符
|
||||
const includeUppercaseLetters = /[A-Z]+/;
|
||||
//是否包含字符
|
||||
const containsCharacters = /\W/;
|
||||
if (value === "") {
|
||||
callback(new Error("新密码不能为空"));
|
||||
} else if (this.baseForm.passwordStrengthLimit == 1) {
|
||||
if (this.baseForm.passwordLengthMin) {
|
||||
if (value.length < this.baseForm.passwordLengthMinNumber) {
|
||||
callback(
|
||||
new Error(
|
||||
"新密码长度不能小于" +
|
||||
this.baseForm.passwordLengthMinNumber +
|
||||
"位"
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
if (this.baseForm.containsNumbers) {
|
||||
if (!containsNumbers.test(value)) {
|
||||
callback(new Error("新密码必须包含数字"));
|
||||
}
|
||||
}
|
||||
if (this.baseForm.includeLowercaseLetters) {
|
||||
if (!includeLowercaseLetters.test(value)) {
|
||||
callback(new Error("新密码必须包含小写字母"));
|
||||
}
|
||||
}
|
||||
if (this.baseForm.includeUppercaseLetters) {
|
||||
if (!includeUppercaseLetters.test(value)) {
|
||||
callback(new Error("新密码必须包含大写字字母"));
|
||||
}
|
||||
}
|
||||
if (this.baseForm.containsCharacters) {
|
||||
if (!containsCharacters.test(value)) {
|
||||
callback(new Error("新密码必须包含字符"));
|
||||
}
|
||||
}
|
||||
callback();
|
||||
} else {
|
||||
callback();
|
||||
}
|
||||
};
|
||||
var validatePass2 = (rule, value, callback) => {
|
||||
if (value === "") {
|
||||
callback(new Error("重复密码不能为空"));
|
||||
} else if (value !== this.dataForm.password) {
|
||||
callback(new Error("两次密码输入不一致"));
|
||||
} else {
|
||||
callback();
|
||||
}
|
||||
};
|
||||
return {
|
||||
showPopup: false,
|
||||
imgUrl: "",
|
||||
timestamp: "",
|
||||
dataForm: {
|
||||
oldPassword: "",
|
||||
password: "",
|
||||
repeatPsd: "",
|
||||
code: "",
|
||||
timestamp: "",
|
||||
},
|
||||
rules: {
|
||||
oldPassword: [{
|
||||
required: true,
|
||||
message: "旧密码不能为空",
|
||||
trigger: "blur",
|
||||
}, ],
|
||||
password: [{
|
||||
required: true,
|
||||
validator: validatePass,
|
||||
trigger: "blur",
|
||||
}, ],
|
||||
repeatPsd: [{
|
||||
required: true,
|
||||
validator: validatePass2,
|
||||
trigger: "blur",
|
||||
}, ],
|
||||
code: [{
|
||||
required: true,
|
||||
message: "验证码不能为空",
|
||||
trigger: "blur",
|
||||
}, ],
|
||||
},
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
baseURL() {
|
||||
return this.define.baseURL;
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
passwordShow(val) {
|
||||
if (val) {
|
||||
this.showPopup = val
|
||||
this.$nextTick(() => {
|
||||
this.$refs.dataForm.setRules(this.rules);
|
||||
});
|
||||
}
|
||||
},
|
||||
},
|
||||
created() {
|
||||
this.changeCode()
|
||||
},
|
||||
methods: {
|
||||
changeCode() {
|
||||
let timestamp = Math.random();
|
||||
this.timestamp = timestamp;
|
||||
this.imgUrl = `/api/file/ImageCode/${timestamp}`;
|
||||
},
|
||||
dataFormSubmit() {
|
||||
this.$refs["dataForm"].validate((valid) => {
|
||||
if (valid) {
|
||||
let query = {
|
||||
oldPassword: md5Libs.md5(this.dataForm.oldPassword),
|
||||
password: md5Libs.md5(this.dataForm.password),
|
||||
code: this.dataForm.code,
|
||||
timestamp: this.timestamp,
|
||||
};
|
||||
this.$emit('submit', query)
|
||||
}
|
||||
});
|
||||
},
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
</style>
|
||||
577
pages/index/dashboard.vue
Normal file
@@ -0,0 +1,577 @@
|
||||
<template>
|
||||
<view class="index-v">
|
||||
<!-- #ifndef MP -->
|
||||
<uni-nav-bar class='nav' :fixed="true" :statusBar="true" :border="false" :right-icon="rightIcon"
|
||||
@clickRight="scan">
|
||||
<!-- 左边插槽 -->
|
||||
<template #left>
|
||||
<view v-if="portalList.length > 1 && userInfo.appPortalId">
|
||||
<uni-icons class='icon-ym icon-ym-header-role-toggle' color="#666" size="20"
|
||||
@click="showSelectBox" />
|
||||
</view>
|
||||
</template>
|
||||
<template #default>
|
||||
<view class="nav-left">
|
||||
<view class="nav-left-text">{{portalTitle}}</view>
|
||||
</view>
|
||||
</template>
|
||||
</uni-nav-bar>
|
||||
<template v-if="userInfo.appPortalId">
|
||||
<mescroll-body ref="mescrollRef" @init="mescrollInit" @down="downCallback" :down="downOption"
|
||||
@up="upCallback" :up="upOption" :bottombar="false" top='10'>
|
||||
<view class="portal-v" v-if="authConfig.type==0">
|
||||
<template v-if="formData.length">
|
||||
<view class="portal-box" v-for="(item,index) in formData" :key="index">
|
||||
<portalItem :item='item' ref="portalItem" :key="key" v-if="item.show" />
|
||||
</view>
|
||||
</template>
|
||||
<JnpfEmpty v-else></JnpfEmpty>
|
||||
</view>
|
||||
<template v-if="authConfig.type==1">
|
||||
<!-- #ifdef APP -->
|
||||
<view v-if="authConfig.linkType==1 && showWebView">
|
||||
<web-view :src="authConfig.customUrl"></web-view>
|
||||
</view>
|
||||
<!-- #endif -->
|
||||
<!-- #ifdef H5 -->
|
||||
<view v-if="authConfig.linkType==1 && showWebView">
|
||||
<web-view :src="authConfig.customUrl" :fullscreen="false"
|
||||
style="width: 100%;height: calc(100vh - 300rpx);"></web-view>
|
||||
</view>
|
||||
<!-- #endif -->
|
||||
<view v-else class="portal-v portal-nodata">
|
||||
<view class="u-flex-col" style="align-items: center;">
|
||||
<u-image width="280rpx" height="280rpx" :src="emptyImg"></u-image>
|
||||
<text class="u-m-t-20" style="color: #909399;">当前内容无法在APP上显示,请前往PC门户查看~~</text>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
</mescroll-body>
|
||||
</template>
|
||||
<view class="portal-v" style="padding-top: 20rpx;" v-else>
|
||||
<view class="portal-box">
|
||||
<defaultPortal></defaultPortal>
|
||||
</view>
|
||||
</view>
|
||||
<u-popup v-model="showSelect" mode="bottom" class="select-box" height="600rpx" @close="closePopup">
|
||||
<view class="search-box">
|
||||
<u-search :placeholder="$t('app.apply.pleaseKeyword')" v-model="keyword" height="72"
|
||||
:show-action="false" bg-color="#f0f2f6" shape="square" search-icon-color="#909399" />
|
||||
</view>
|
||||
<view v-for="(item,index) in columnList" :key="index" class="select-item" @click="selectPortal(item,index)">
|
||||
<text class="u-m-r-12 u-font-30"
|
||||
:class="[item.icon,{'currentItem':item.isDefault || item.id === item.appPortalId }]" />
|
||||
<text class="item-text sysName"
|
||||
:class="{'currentItem':item.isDefault || item.id === item.appPortalId}">{{item.fullName}}</text>
|
||||
<u-icon name="checkbox-mark " class="currentItem"
|
||||
v-if="item.isDefault || item.id === item.appPortalId"></u-icon>
|
||||
</view>
|
||||
</u-popup>
|
||||
<!-- #endif -->
|
||||
<!-- #ifdef MP -->
|
||||
<view>
|
||||
<web-view :src="mpPortalUrl"></web-view>
|
||||
</view>
|
||||
<!-- #endif -->
|
||||
</view>
|
||||
</template>
|
||||
<script>
|
||||
var wv; //计划创建的webview
|
||||
import {
|
||||
PortalList,
|
||||
SetPortal,
|
||||
auth
|
||||
} from '@/api/portal/portal'
|
||||
// #ifndef MP
|
||||
import MescrollMixin from "@/uni_modules/mescroll-uni/components/mescroll-uni/mescroll-mixins.js"
|
||||
import IndexMixin from './mixin'
|
||||
import portalItem from '@/pages/portal/components/index.vue'
|
||||
import defaultPortal from '@/pages/portal/components/defaultPortal.vue'
|
||||
// #endif
|
||||
import emptyImg from '@/static/image/defPortal.png'
|
||||
import {
|
||||
useUserStore
|
||||
} from '@/store/modules/user'
|
||||
import {
|
||||
refreshCurrentPage
|
||||
} from '@/utils/refreshCurrent'
|
||||
export default {
|
||||
// #ifndef MP
|
||||
mixins: [MescrollMixin, IndexMixin],
|
||||
// #endif
|
||||
components: {
|
||||
// #ifndef MP
|
||||
portalItem,
|
||||
defaultPortal
|
||||
// #endif
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
keyword: '',
|
||||
showWebView: true,
|
||||
emptyImg: emptyImg,
|
||||
rightIcon: '',
|
||||
key: +new Date(),
|
||||
formData: [],
|
||||
portalTitle: '门户',
|
||||
showSelect: false,
|
||||
upOption: {
|
||||
page: {
|
||||
num: 0,
|
||||
size: 50,
|
||||
time: null
|
||||
},
|
||||
empty: {
|
||||
use: false,
|
||||
},
|
||||
textNoMore: this.$t('app.apply.noMoreData'),
|
||||
},
|
||||
portalList: [],
|
||||
id: '',
|
||||
userInfo: {},
|
||||
downOption: {
|
||||
use: true,
|
||||
auto: true
|
||||
},
|
||||
authConfig: {},
|
||||
token: '',
|
||||
mpPortalUrl: '',
|
||||
timer: null,
|
||||
type: 0
|
||||
};
|
||||
},
|
||||
onShow() {
|
||||
this.token = uni.getStorageSync('token')
|
||||
this.mpPortalUrl = this.define.baseURL + '/pages/portal/mpPortal/index?token=' + this.token
|
||||
this.userInfo = uni.getStorageSync('userInfo') || {}
|
||||
this.showSelect = false
|
||||
if (!this.userInfo.appPortalId) return
|
||||
// #ifndef MP
|
||||
this.getPortalList()
|
||||
this.$nextTick(() => {
|
||||
this.mescroll.resetUpScroll();
|
||||
this.portalList = []
|
||||
})
|
||||
// #endif
|
||||
// #ifdef APP
|
||||
this.rightIcon = 'scan'
|
||||
// #endif
|
||||
},
|
||||
onReady() {
|
||||
// #ifdef APP
|
||||
this.setWebview()
|
||||
// #endif
|
||||
},
|
||||
onLoad(e) {
|
||||
// #ifndef MP
|
||||
this.token = uni.getStorageSync('token')
|
||||
// #endif
|
||||
},
|
||||
computed: {
|
||||
isPortalListValid() {
|
||||
return Array.isArray(this.portalList) && this.portalList.length;
|
||||
},
|
||||
columnList() {
|
||||
return this.portalList.filter((o) => (o.fullName && o.fullName.match(this.keyword)))
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
setWebview() {
|
||||
if (this.authConfig.linkType == 1) {
|
||||
var currentWebview = this.$scope
|
||||
.$getAppWebview() //此对象相当于html5plus里的plus.webview.currentWebview()。在uni-app里vue页面直接使用plus.webview.currentWebview()无效
|
||||
let height = 0;
|
||||
uni.getSystemInfo({
|
||||
//成功获取的回调函数,返回值为系统信息
|
||||
success: (sysinfo) => {
|
||||
height = sysinfo.windowHeight - 50; //自行修改,自己需要的高度 此处如底部有其他内容,可以直接---(-50)这种
|
||||
},
|
||||
complete: () => {}
|
||||
});
|
||||
this.$nextTick(() => {
|
||||
setTimeout(() => {
|
||||
wv = currentWebview.children()[0]
|
||||
wv.setStyle({
|
||||
top: 80,
|
||||
height,
|
||||
scalable: true
|
||||
})
|
||||
}, 500); //如果是页面初始化调用时,需要延时一下
|
||||
})
|
||||
}
|
||||
},
|
||||
upCallback(keyword) {
|
||||
auth(this.userInfo.appPortalId).then(res => {
|
||||
this.authConfig = res.data || {}
|
||||
let data = JSON.parse(res.data.formData) || {};
|
||||
this.formData = data.layout ? JSON.parse(JSON.stringify(data.layout)) : [];
|
||||
this.handelFormData(data);
|
||||
if (data.refresh.autoRefresh) {
|
||||
this.timer && clearInterval(this.timer);
|
||||
this.timer = setInterval(() => {
|
||||
uni.$emit('proRefresh')
|
||||
}, data.refresh.autoRefreshTime * 60000)
|
||||
}
|
||||
this.mescroll.endSuccess(this.formData.length);
|
||||
this.key = +new Date()
|
||||
// #ifdef APP
|
||||
this.setWebview()
|
||||
// #endif
|
||||
}).catch(() => {
|
||||
this.formData = []
|
||||
this.mescroll.endSuccess(0);
|
||||
this.mescroll.endErr();
|
||||
this.key = +new Date()
|
||||
})
|
||||
},
|
||||
handelFormData(data) {
|
||||
const loop = (list) => {
|
||||
list.forEach(o => {
|
||||
o.allRefresh = data.refresh
|
||||
o.show = false
|
||||
if (o.visibility && o.visibility.length && o.visibility.includes('app')) o.show =
|
||||
true
|
||||
if (o.children && o.children.length) loop(o.children)
|
||||
})
|
||||
this.key = +new Date()
|
||||
}
|
||||
loop(this.formData)
|
||||
this.dataList = this.formData.filter(o => o.show)
|
||||
if (this.dataList.length < 1) {
|
||||
this.formData = this.dataList
|
||||
this.mescroll.endSuccess(this.dataList.length);
|
||||
}
|
||||
},
|
||||
isJSON(str) {
|
||||
try {
|
||||
var obj = JSON.parse(str);
|
||||
if (typeof obj == 'object' && obj) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
} catch (e) {
|
||||
return false;
|
||||
}
|
||||
},
|
||||
scan() {
|
||||
if (!this.userInfo.appPortalId) return
|
||||
uni.scanCode({
|
||||
success: res => {
|
||||
let url = ""
|
||||
if (this.isJSON(res.result.trim())) {
|
||||
const result = JSON.parse(res.result.trim())
|
||||
if (result.t === 'ADP') {
|
||||
let config = {
|
||||
isPreview: 1,
|
||||
moduleId: result.id,
|
||||
previewType: result.previewType
|
||||
}
|
||||
url = '/pages/apply/dynamicModel/index?config=' + this.jnpf.base64.encode(JSON
|
||||
.stringify(config))
|
||||
}
|
||||
if (result.t === 'DFD') {
|
||||
url = '/pages/apply/dynamicModel/scanForm?config=' + JSON.stringify(result)
|
||||
}
|
||||
if (result.t === 'WFP') {
|
||||
url = '/pages/workFlow/scanForm/index?config=' + JSON.stringify(result)
|
||||
}
|
||||
if (result.t === 'report') {
|
||||
userInfo = uni.getStorageSync('userInfo') || {}
|
||||
const appCode = userInfo.systemCode
|
||||
let url_ =
|
||||
`${this.report}/preview.html?id=${result.id}&token=${this.token}&appCode=${appCode}&page=1&from=menu`
|
||||
url = '/pages/apply/externalLink/index?url=' + encodeURIComponent(url_) +
|
||||
'&fullName= ' + result.fullName
|
||||
}
|
||||
if (result.t === 'portal') {
|
||||
url = '/pages/portal/scanPortal/index?id=' + result.id
|
||||
}
|
||||
if (result.t === 'login') {
|
||||
url = '/pages/login/scanLogin?id=' + result.id
|
||||
}
|
||||
} else {
|
||||
url = '/pages/my/scanResult/index?result=' + res.result
|
||||
}
|
||||
uni.navigateTo({
|
||||
url,
|
||||
fail: (err) => {
|
||||
this.$u.toast("暂无此页面")
|
||||
}
|
||||
})
|
||||
}
|
||||
});
|
||||
},
|
||||
/* 获取门户列表 */
|
||||
getPortalList() {
|
||||
PortalList().then(res => {
|
||||
let list = res.data.list || [];
|
||||
this.portalList = list
|
||||
list.map(o => {
|
||||
this.portalList.forEach(o => {
|
||||
o.appPortalId = this.userInfo.appPortalId
|
||||
if (o.id === o.appPortalId) this.portalTitle = o.fullName
|
||||
})
|
||||
})
|
||||
})
|
||||
},
|
||||
closePopup() {
|
||||
// #ifdef APP
|
||||
this.setWebview()
|
||||
uni.$emit('showVideo', true)
|
||||
this.showWebView = true
|
||||
// #endif
|
||||
},
|
||||
showSelectBox() {
|
||||
this.showSelect = !this.showSelect;
|
||||
// #ifndef MP
|
||||
this.getPortalList();
|
||||
// #endif
|
||||
// #ifdef APP
|
||||
uni.$emit('showVideo', false);
|
||||
this.showWebView = false;
|
||||
this.setWebview();
|
||||
// #endif
|
||||
},
|
||||
selectPortal(item, index) {
|
||||
SetPortal(item.id).then(res => {
|
||||
this.portalTitle = this.portalList[index].fullName;
|
||||
this.userInfo.appPortalId = item.id;
|
||||
// #ifndef MP
|
||||
this.mescroll.triggerDownScroll();
|
||||
// #endif
|
||||
this.showSelectBox(false);
|
||||
uni.setStorageSync('userInfo', this.userInfo);
|
||||
});
|
||||
},
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
page {
|
||||
background-color: #f0f2f6;
|
||||
}
|
||||
|
||||
.index-v {
|
||||
.portal-v {
|
||||
padding: 0 20rpx 20rpx 20rpx;
|
||||
|
||||
.portal-box {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
|
||||
.htabs {
|
||||
.u-scroll-box {
|
||||
height: 80rpx;
|
||||
|
||||
.u-tab-item {
|
||||
border-right: 1px solid #e4e7ed;
|
||||
|
||||
&::before {
|
||||
content: "";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.card-v {
|
||||
&.u-card {
|
||||
margin: 0rpx !important;
|
||||
padding: 0rpx !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.nav {
|
||||
z-index: 99999;
|
||||
|
||||
::v-deep .uni-navbar__content {
|
||||
z-index: 99999;
|
||||
}
|
||||
|
||||
::v-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: 32rpx;
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.portal-select {
|
||||
background-color: #fff;
|
||||
height: 80rpx;
|
||||
padding-left: 20rpx;
|
||||
line-height: 80rpx;
|
||||
|
||||
.portal-select-inner {
|
||||
width: 200rpx;
|
||||
height: 100%;
|
||||
|
||||
.portal-select-text {
|
||||
color: #303133;
|
||||
}
|
||||
}
|
||||
|
||||
.right-icons {
|
||||
font-weight: 700;
|
||||
margin-top: 2px;
|
||||
margin-left: 4px;
|
||||
transition-duration: 0.3s;
|
||||
color: #606266 !important;
|
||||
}
|
||||
|
||||
.select-right-icons {
|
||||
transform: rotate(-180deg);
|
||||
}
|
||||
}
|
||||
|
||||
.select-box {
|
||||
overflow-y: scroll;
|
||||
|
||||
.search-box {
|
||||
height: 112rpx;
|
||||
width: 100%;
|
||||
padding: 20rpx 20rpx;
|
||||
z-index: 10000;
|
||||
background: #fff;
|
||||
|
||||
&::after {
|
||||
content: " ";
|
||||
position: absolute;
|
||||
left: 2%;
|
||||
top: 62px;
|
||||
box-sizing: border-box;
|
||||
width: 96%;
|
||||
height: 1px;
|
||||
transform: scale(1, .3);
|
||||
border: 0 solid #e4e7ed;
|
||||
z-index: 2;
|
||||
border-bottom-width: 1px;
|
||||
}
|
||||
}
|
||||
|
||||
.currentItem {
|
||||
color: #02a7f0;
|
||||
}
|
||||
|
||||
.select-item {
|
||||
height: 88rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 0 20rpx;
|
||||
font-size: 30rpx;
|
||||
color: #303133;
|
||||
text-align: left;
|
||||
position: relative;
|
||||
|
||||
&::after {
|
||||
content: " ";
|
||||
position: absolute;
|
||||
left: 2%;
|
||||
bottom: 0;
|
||||
box-sizing: border-box;
|
||||
width: 96%;
|
||||
height: 1px;
|
||||
transform: scale(1, .3);
|
||||
border: 0 solid #e4e7ed;
|
||||
z-index: 2;
|
||||
border-bottom-width: 1px;
|
||||
}
|
||||
|
||||
.sysName {
|
||||
flex: 1;
|
||||
overflow: auto;
|
||||
min-width: 0;
|
||||
font-size: 28rpx;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.popup {
|
||||
position: absolute;
|
||||
top: 244rpx;
|
||||
z-index: 99999;
|
||||
width: 70%;
|
||||
height: 200px;
|
||||
border: 1px solid #ccc;
|
||||
background-color: #fff;
|
||||
left: 283rpx;
|
||||
border-radius: 4rpx;
|
||||
transform: translate(-50%, -50%) scale(0);
|
||||
animation: popup-animation 0.4s ease-in-out forwards;
|
||||
}
|
||||
|
||||
.uni-select--mask {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
right: 0;
|
||||
left: 0;
|
||||
z-index: 2;
|
||||
}
|
||||
|
||||
@keyframes popup-animation {
|
||||
from {
|
||||
transform: translate(-50%, -50%) scale(0);
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
to {
|
||||
transform: translate(-50%, -50%) scale(1);
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
.nav {
|
||||
z-index: 99999;
|
||||
|
||||
::v-deep .uni-navbar__content {
|
||||
z-index: 99999;
|
||||
}
|
||||
|
||||
::v-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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.portal-nodata {
|
||||
position: absolute;
|
||||
top: 450rpx;
|
||||
width: 100%;
|
||||
text-align: center;
|
||||
z-index: 100;
|
||||
background-color: #f0f2f6;
|
||||
}
|
||||
</style>
|
||||
362
pages/index/index.vue
Normal file
@@ -0,0 +1,362 @@
|
||||
<template>
|
||||
<view class="index_v">
|
||||
<u-sticky>
|
||||
<view class="head-tabs u-flex">
|
||||
<view class="head-tabs-item" @click="openPage('/pages/workFlow/flowTodo/index','approve')">
|
||||
<text class="icon-ym icon-ym-flowTodo-app u-m-r-4 icon-style" />
|
||||
<text class="u-font-24 head-tabs-name">审批中心</text>
|
||||
<u-badge type="error" :count="count" :absolute="true" :offset="offset" />
|
||||
</view>
|
||||
<view class="head-tabs-item" @click="openPage('/pages/workFlow/entrustAgent/index','entrust')">
|
||||
<text class="icon-ym icon-ym-flowDone-app u-m-r-4 icon-style" />
|
||||
<text class="u-font-24 head-tabs-name">委托代理</text>
|
||||
</view>
|
||||
<view class="head-tabs-item" @click="openPage('/pages/workFlow/schedule/index','schedule')">
|
||||
<text class="icon-ym icon-ym-flowDone-app u-m-r-4 icon-style" />
|
||||
<text class="u-font-24 head-tabs-name">日程</text>
|
||||
</view>
|
||||
<view class="head-tabs-item" @click="openPage('/pages/workFlow/document/index','document')">
|
||||
<text class="icon-ym icon-ym-flowCopy-app u-m-r-4 icon-style" />
|
||||
<text class="u-font-24 head-tabs-name">文档</text>
|
||||
</view>
|
||||
</view>
|
||||
</u-sticky>
|
||||
<CommonPane :flowList="homeData.favoritesFlowList || []" :menuList="homeData.favoritesMenuList || []"
|
||||
type="collect" @launch="launch" v-if="homeData.favoritesEnable" @openPage="openPage" @addApp="addApp"
|
||||
:showAdd="true" :flowEnabled="homeData.flowEnabled" />
|
||||
|
||||
<CommonPane title="最近使用" :flowList="homeData.latelyUseFlowList || []" type="use"
|
||||
:menuList="homeData.latelyUseMenuList || []" @launch="launch" v-if="homeData.latelyUseEnable"
|
||||
@openPage="openPage" :flowEnabled="homeData.flowEnabled" />
|
||||
|
||||
<CommonPane title="最近常用" :flowList="homeData.commonUseFlowList || []" type="common"
|
||||
:menuList="homeData.commonUseMenuList || []" @launch="launch" v-if="homeData.commonUseEnable"
|
||||
@openPage="openPage" :flowEnabled="homeData.flowEnabled" />
|
||||
<PasswordPopup @submit="dataFormSubmit" :passwordShow="passwordShow" :formData="baseForm"></PasswordPopup>
|
||||
</view>
|
||||
</template>
|
||||
<script>
|
||||
import {
|
||||
getFlowTodoCount
|
||||
} from "@/api/workFlow/flowEngine";
|
||||
import {
|
||||
getHomeData
|
||||
} from "@/api/index/index";
|
||||
import {
|
||||
useUserStore
|
||||
} from '@/store/modules/user'
|
||||
import {
|
||||
useChatStore
|
||||
} from '@/store/modules/chat'
|
||||
import {
|
||||
updatePassword,
|
||||
updatePasswordMessage
|
||||
} from '@/api/common.js'
|
||||
import chat from '@/libs/chat'
|
||||
import CommonPane from '@/components/CommonPane'
|
||||
import PasswordPopup from './components/PasswordPopup'
|
||||
import {
|
||||
useLocale
|
||||
} from '@/locale/useLocale';
|
||||
const chatStore = useChatStore()
|
||||
export default {
|
||||
components: {
|
||||
CommonPane,
|
||||
PasswordPopup
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
homeData: [],
|
||||
count: 0,
|
||||
offset: [20, -10],
|
||||
menuList: [],
|
||||
passwordShow: false,
|
||||
baseForm: {
|
||||
passwordStrengthLimit: 0,
|
||||
passwordLengthMin: false,
|
||||
passwordLengthMinNumber: 0,
|
||||
containsNumbers: false,
|
||||
includeLowercaseLetters: false,
|
||||
includeUppercaseLetters: false,
|
||||
containsCharacters: false,
|
||||
mandatoryModificationOfInitialPassword: 0,
|
||||
},
|
||||
userInfo: {}
|
||||
};
|
||||
},
|
||||
onLoad() {
|
||||
const chatStore = useChatStore()
|
||||
if (!chatStore.getSocket) chat && chat.initSocket()
|
||||
const userStore = useUserStore()
|
||||
userStore.getCurrentUser().then(() => {
|
||||
this.getSystemName()
|
||||
}).catch(() => {
|
||||
setTimeout(() => {
|
||||
userStore.resetToken()
|
||||
setTimeout(() => {
|
||||
uni.reLaunch({
|
||||
url: '/pages/login/index'
|
||||
})
|
||||
}, 500)
|
||||
}, 1000)
|
||||
})
|
||||
const {
|
||||
changeLocale
|
||||
} = useLocale();
|
||||
changeLocale(uni.getLocale())
|
||||
},
|
||||
onShow(e) {
|
||||
this.init()
|
||||
},
|
||||
computed: {
|
||||
baseURL() {
|
||||
return this.define.baseURL;
|
||||
},
|
||||
token() {
|
||||
return uni.getStorageSync('token')
|
||||
},
|
||||
report() {
|
||||
return this.define.report;
|
||||
},
|
||||
pcURL() {
|
||||
return this.define.pcURL;
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
init() {
|
||||
this.getHomeData()
|
||||
this.getFlowCount()
|
||||
this.getSystemConfig()
|
||||
},
|
||||
// 获取系统配置
|
||||
getSystemConfig() {
|
||||
updatePasswordMessage();
|
||||
this.userInfo = uni.getStorageSync('userInfo') || {}
|
||||
const config = uni.getStorageSync('sysConfigInfo') || {};
|
||||
this.$nextTick(() => {
|
||||
this.baseForm.passwordStrengthLimit = config.passwordStrengthLimit
|
||||
this.baseForm.passwordLengthMin = config.passwordLengthMin
|
||||
this.baseForm.passwordLengthMinNumber = config.passwordLengthMinNumber
|
||||
this.baseForm.containsNumbers = config.containsNumbers
|
||||
this.baseForm.includeLowercaseLetters = config.includeLowercaseLetters
|
||||
this.baseForm.containsCharacters = config.containsCharacters
|
||||
this.baseForm.mandatoryModificationOfInitialPassword = config
|
||||
.mandatoryModificationOfInitialPassword
|
||||
if (this.userInfo.changePasswordDate == null && config
|
||||
.mandatoryModificationOfInitialPassword == 1)
|
||||
this.passwordShow = true;
|
||||
})
|
||||
},
|
||||
dataFormSubmit(query) {
|
||||
updatePassword(query).then((res) => {
|
||||
const userStore = useUserStore()
|
||||
userStore.logout().then(() => {
|
||||
uni.reLaunch({
|
||||
url: "/pages/login/index",
|
||||
});
|
||||
});
|
||||
})
|
||||
},
|
||||
//获取并设置应用名称
|
||||
getSystemName() {
|
||||
const userInfo = uni.getStorageSync("userInfo");
|
||||
this.menuList = uni.getStorageSync("menuList");
|
||||
uni.setNavigationBarTitle({
|
||||
title: userInfo.systemName
|
||||
})
|
||||
},
|
||||
launch(item) {
|
||||
if (item.tabType == 'flow') return this.JumpFlow(item)
|
||||
if (item.tabType == 'menu') return this.JumpApply(item)
|
||||
},
|
||||
JumpApply(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("暂无此页面");
|
||||
},
|
||||
});
|
||||
},
|
||||
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)
|
||||
},
|
||||
JumpFlow(item) {
|
||||
const config = {
|
||||
id: "",
|
||||
flowId: item.id,
|
||||
opType: "-1",
|
||||
isFlow: 1
|
||||
};
|
||||
uni.navigateTo({
|
||||
url: "/pages/workFlow/flowBefore/index?config=" +
|
||||
this.jnpf.base64.encode(JSON.stringify(config))
|
||||
});
|
||||
},
|
||||
//获取审批中心待办条数
|
||||
getFlowCount() {
|
||||
getFlowTodoCount().then((res) => {
|
||||
this.count = res.data.flowTodo || 0;
|
||||
})
|
||||
},
|
||||
getHomeData() {
|
||||
getHomeData().then((res) => {
|
||||
for (let i = 0; i < res.data.length; i++) {
|
||||
const e = res.data[i];
|
||||
this.homeData[`${e.code}Enable`] = e.enable;
|
||||
this.homeData['flowEnabled'] = e.flowEnabled
|
||||
this.handleProperty(e.appList)
|
||||
if (['commonUse', 'favorites', 'latelyUse'].includes(e.code)) {
|
||||
this.homeData[`${e.code}MenuList`] = e.appList || [];
|
||||
this.homeData[`${e.code}FlowList`] = e.flowList || [];
|
||||
}
|
||||
}
|
||||
}).catch(() => {});
|
||||
},
|
||||
//更多按钮
|
||||
openPage(path, type) {
|
||||
if (type === 'approve') {
|
||||
let workFlowList = this.menuList.filter(o => o.enCode === 'workFlow')
|
||||
if (!workFlowList[0]?.children?.length) return this.$u.toast('暂无权限')
|
||||
}
|
||||
if (!path) return;
|
||||
uni.navigateTo({
|
||||
url: path,
|
||||
});
|
||||
},
|
||||
//添加按钮
|
||||
addApp(path) {
|
||||
if (!path) return;
|
||||
uni.navigateTo({
|
||||
url: path,
|
||||
});
|
||||
},
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
page {
|
||||
background-color: #f0f2f6;
|
||||
padding-bottom: 20rpx;
|
||||
}
|
||||
|
||||
.index_v {
|
||||
.head-tabs {
|
||||
background-color: #fff;
|
||||
width: 100%;
|
||||
height: 120rpx;
|
||||
justify-content: space-between;
|
||||
padding: 0 20rpx;
|
||||
|
||||
.head-tabs-item {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
font-size: 28rpx;
|
||||
color: #303133;
|
||||
flex-shrink: 0;
|
||||
position: relative;
|
||||
align-items: center;
|
||||
height: 120rpx;
|
||||
|
||||
.icon-style {
|
||||
font-size: 42rpx;
|
||||
color: #666666;
|
||||
}
|
||||
|
||||
.head-tabs-name {
|
||||
color: #303133;
|
||||
font-family: PingFang SC;
|
||||
margin-left: 6rpx;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
464
pages/index/message.vue
Normal file
@@ -0,0 +1,464 @@
|
||||
<template>
|
||||
<view class="message-v">
|
||||
<view class="nav-bar-box">
|
||||
<uni-nav-bar :fixed="true" :statusBar="true" :border="false" @clickLeft="back" height="44px">
|
||||
<block #default>
|
||||
<view class="u-flex slot-wrap">
|
||||
<view class="title">{{$t('app.tabBar.message')}}</view>
|
||||
<view class="nav-icon u-m-l-10" @click="readAll">
|
||||
<text class="icon-ym icon-ym-clean" />
|
||||
</view>
|
||||
</view>
|
||||
</block>
|
||||
</uni-nav-bar>
|
||||
</view>
|
||||
<view class="notice-warp" :style="{'top':topSearch,'height':noticeWarpH+'px'}">
|
||||
<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 class="sticky-box-tabs">
|
||||
<view class="tabs-box">
|
||||
<u-tabs class="u-tab-box" :list="tablist" :current="current" @change="tabChange" :offset="offset">
|
||||
</u-tabs>
|
||||
</view>
|
||||
<view class="status-box">
|
||||
<view class="status-icon" @click="showAction = true">
|
||||
<uni-icons type="bottom" size="16" color="#3C3C3C"></uni-icons>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<mescroll-body ref="mescrollRef" @init="mescrollInit" @down="downCallback" @up="upCallback" :down="downOption"
|
||||
:up="upOption" :bottombar="false" :top="mescrollTop">
|
||||
<view class="message-list">
|
||||
<view class="u-flex message-item u-border-bottom " v-for="(item, i) in list" :key="i"
|
||||
@click="detail(item)">
|
||||
<view class="message-item-img message-item-icon u-flex u-row-center"
|
||||
:class="{'message-item-icon-flow':item.type == 2,'message-notice-icon':item.type == 3,'message-schedule':item.type == 4}">
|
||||
<text class="icon-ym icon-ym-xitong" v-if="item.type == 1" />
|
||||
<text class="icon-ym icon-ym-generator-notice" v-else-if="item.type == 3" />
|
||||
<text class="icon-ym icon-ym-portal-schedule" v-else-if="item.type == 4" />
|
||||
<text class="icon-ym icon-ym-generator-flow" v-else />
|
||||
<text class="redDot" v-if="!item.isRead"></text>
|
||||
</view>
|
||||
<view class="message-item-txt">
|
||||
<view class="message-item-title u-flex">
|
||||
<text class="title u-line-1">{{item.title}}</text>
|
||||
</view>
|
||||
<view class="u-flex u-row-between message-item-cell">
|
||||
<text>{{item.releaseUser}}</text>
|
||||
<text
|
||||
class="u-font-24">{{item.releaseTime?$u.timeFormat(item.releaseTime, 'mm-dd hh:MM'):''}}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</mescroll-body>
|
||||
<u-action-sheet :list="statusOptions" v-model="showAction" @click="handleClick"></u-action-sheet>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {
|
||||
getMessageList,
|
||||
getMessageDetail,
|
||||
checkInfo,
|
||||
getUnReadMsgNum,
|
||||
MessageAllRead
|
||||
} from '@/api/message.js'
|
||||
import resources from '@/libs/resources.js'
|
||||
import MescrollMixin from "@/uni_modules/mescroll-uni/components/mescroll-uni/mescroll-mixins.js";
|
||||
import IndexMixin from "@/pages/index/mixin.js";
|
||||
import {
|
||||
useChatStore
|
||||
} from '@/store/modules/chat'
|
||||
const chatStore = useChatStore()
|
||||
export default {
|
||||
mixins: [MescrollMixin, IndexMixin],
|
||||
data() {
|
||||
return {
|
||||
mescrollTop: 326,
|
||||
topSearch: '80px',
|
||||
appTopHeight: 0,
|
||||
offset: [5, 8],
|
||||
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: false,
|
||||
top: "640rpx",
|
||||
},
|
||||
textNoMore: this.$t('app.apply.noMoreData'),
|
||||
},
|
||||
keyword: '',
|
||||
type: "",
|
||||
list: [],
|
||||
current: 0,
|
||||
tablist: [{
|
||||
name: '全部',
|
||||
count: 0
|
||||
}, {
|
||||
name: '系统',
|
||||
count: 0
|
||||
}, {
|
||||
name: '流程',
|
||||
count: 0
|
||||
}, {
|
||||
name: '公告',
|
||||
count: 0
|
||||
}, {
|
||||
name: '日程',
|
||||
count: 0
|
||||
}],
|
||||
status: '未读',
|
||||
isRead: 0,
|
||||
statusOptions: [{
|
||||
text: '全部'
|
||||
}, {
|
||||
text: '未读'
|
||||
}, {
|
||||
text: '已读'
|
||||
}],
|
||||
showAction: false,
|
||||
noticeWarpH: 0
|
||||
}
|
||||
},
|
||||
onLoad(option) {
|
||||
this.getUnReadMsgNum()
|
||||
},
|
||||
mounted() {
|
||||
this.getContentHeight()
|
||||
},
|
||||
methods: {
|
||||
back() {
|
||||
uni.navigateBack()
|
||||
},
|
||||
upCallback(page) {
|
||||
let query = {
|
||||
currentPage: page.num,
|
||||
pageSize: page.size,
|
||||
keyword: this.keyword,
|
||||
type: this.type,
|
||||
isRead: this.isRead
|
||||
}
|
||||
getMessageList(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;
|
||||
this.list = this.list.concat(list);
|
||||
}).catch(() => {
|
||||
this.mescroll.endErr();
|
||||
})
|
||||
},
|
||||
getUnReadMsgNum() {
|
||||
getUnReadMsgNum().then(res => {
|
||||
const data = res.data
|
||||
for (var i = 0; i < this.tablist.length; i++) {
|
||||
const item = this.tablist[i]
|
||||
if (item.name == '全部') item.count = data.unReadNum
|
||||
if (item.name == '系统') item.count = data.unReadSystemMsg
|
||||
if (item.name == '流程') item.count = data.unReadMsg
|
||||
if (item.name == '公告') item.count = data.unReadNotice
|
||||
if (item.name == '日程') item.count = data.unReadSchedule
|
||||
}
|
||||
chatStore.setMsgInfoNum(Number(data.unReadNum))
|
||||
})
|
||||
},
|
||||
search() {
|
||||
this.searchTimer && clearTimeout(this.searchTimer)
|
||||
this.searchTimer = setTimeout(() => {
|
||||
this.list = [];
|
||||
this.mescroll.resetUpScroll();
|
||||
}, 300)
|
||||
},
|
||||
tabChange(e) {
|
||||
this.current = e
|
||||
if (e == 0) this.type = ''
|
||||
if (e == 1) this.type = 3
|
||||
if (e == 2) this.type = 2
|
||||
if (e == 3) this.type = 1
|
||||
if (e == 4) this.type = 4
|
||||
this.list = [];
|
||||
this.mescroll.resetUpScroll();
|
||||
},
|
||||
handleClick(index) {
|
||||
if (index == 0) {
|
||||
this.status = '全部'
|
||||
this.isRead = ''
|
||||
} else if (index == 1) {
|
||||
this.status = '未读'
|
||||
this.isRead = 0
|
||||
} else {
|
||||
this.status = '已读'
|
||||
this.isRead = 1
|
||||
}
|
||||
this.list = [];
|
||||
this.mescroll.resetUpScroll();
|
||||
},
|
||||
async getContentHeight() {
|
||||
const windowHeight = this.$u.sys().windowHeight;
|
||||
|
||||
// 获取元素尺寸
|
||||
const [navBarHeight, noticeWarpRect, searchBoxRect, stickyBoxTabsRect] = await Promise.all([
|
||||
this.$uGetRect('.nav-bar-box'),
|
||||
this.$uGetRect('.notice-warp'),
|
||||
this.$uGetRect('.search-box'),
|
||||
this.$uGetRect('.sticky-box-tabs')
|
||||
]);
|
||||
|
||||
// 计算高度
|
||||
const appTopHeight = navBarHeight.height;
|
||||
const searchBoxHeight = searchBoxRect.height;
|
||||
const stickyBoxTabsHeight = stickyBoxTabsRect.height;
|
||||
|
||||
// 设置组件数据
|
||||
this.topSearch = `${appTopHeight}px`;
|
||||
this.appTopHeight = appTopHeight;
|
||||
this.noticeWarpH = searchBoxHeight + stickyBoxTabsHeight;
|
||||
this.mescrollTop = appTopHeight + searchBoxHeight + stickyBoxTabsHeight + 10;
|
||||
},
|
||||
readAll() {
|
||||
const query = {
|
||||
keyword: this.keyword,
|
||||
type: this.type,
|
||||
isRead: this.isRead
|
||||
}
|
||||
MessageAllRead(query).then(res => {
|
||||
if (this.isRead === 0) {
|
||||
this.list = [];
|
||||
this.mescroll.resetUpScroll();
|
||||
} else {
|
||||
for (let i = 0; i < this.list.length; i++) {
|
||||
this.$set(this.list[i], 'isRead', '1')
|
||||
}
|
||||
}
|
||||
this.getUnReadMsgNum()
|
||||
uni.showToast({
|
||||
title: res.msg,
|
||||
icon: 'none'
|
||||
});
|
||||
})
|
||||
},
|
||||
detail(item) {
|
||||
if (item.type == '1' || item.type == '3') {
|
||||
if (!item.isRead) {
|
||||
item.isRead = 1
|
||||
chatStore.setMsgInfoNum()
|
||||
uni.$on('initUnReadMsgNum', () => {
|
||||
this.getUnReadMsgNum()
|
||||
})
|
||||
}
|
||||
uni.navigateTo({
|
||||
url: '/pages/message/messageDetail/index?id=' + item.id
|
||||
});
|
||||
} else {
|
||||
getMessageDetail(item.id).then(res => {
|
||||
if (!item.isRead) {
|
||||
item.isRead = 1
|
||||
chatStore.setMsgInfoNum()
|
||||
this.$nextTick(() => {
|
||||
this.getUnReadMsgNum()
|
||||
})
|
||||
}
|
||||
let data = res.data || {};
|
||||
let bodyText = data.bodyText ? JSON.parse(data.bodyText) : {};
|
||||
if (item.type == 4) {
|
||||
if (bodyText.type == 3) return
|
||||
let groupId = bodyText.groupId || ''
|
||||
uni.navigateTo({
|
||||
url: `/pages/workFlow/schedule/detail?groupId=${groupId}&id=${bodyText.id}`
|
||||
});
|
||||
return
|
||||
}
|
||||
let config = {
|
||||
id: data.id,
|
||||
flowId: bodyText.flowId,
|
||||
opType: bodyText.opType,
|
||||
taskId: bodyText.taskId,
|
||||
operatorId: bodyText.operatorId,
|
||||
}
|
||||
if (item.flowType == 1) {
|
||||
checkInfo(config.operatorId || config.taskId, config.opType).then(res => {
|
||||
config.opType = res.data.opType;
|
||||
setTimeout(() => {
|
||||
uni.navigateTo({
|
||||
url: '/pages/workFlow/flowBefore/index?config=' +
|
||||
this.jnpf.base64.encode(JSON.stringify(config))
|
||||
});
|
||||
}, 300)
|
||||
})
|
||||
} else {
|
||||
if (bodyText.type == 0) return
|
||||
let url = '/pages/workFlow/entrustAgent/index'
|
||||
let i = bodyText.type == 1 ? 0 : bodyText.type == 2 ? 1 : bodyText.type == 3 ? 2 : 3
|
||||
setTimeout(() => {
|
||||
uni.navigateTo({
|
||||
url: url + '?index=' + i
|
||||
});
|
||||
}, 300)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
page {
|
||||
background-color: #f0f2f6;
|
||||
}
|
||||
|
||||
.message-v {
|
||||
|
||||
height: 100%;
|
||||
|
||||
:deep(.u-border-bottom):after {
|
||||
border-bottom-width: 0px
|
||||
}
|
||||
|
||||
.slot-wrap {
|
||||
.title {
|
||||
font-size: 32rpx;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.nav-icon {
|
||||
width: 44rpx;
|
||||
height: 44rpx;
|
||||
background: rgb(240, 242, 246);
|
||||
border-radius: 50%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
||||
text {
|
||||
font-size: 32rpx;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.message-schedule {
|
||||
background-color: #77f !important;
|
||||
}
|
||||
|
||||
.sticky-box {
|
||||
height: 100%;
|
||||
position: sticky;
|
||||
z-index: 100;
|
||||
}
|
||||
|
||||
.sticky-box-tabs {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
background-color: #fff;
|
||||
align-items: center;
|
||||
|
||||
.tabs-box {
|
||||
width: 90%;
|
||||
}
|
||||
|
||||
.status-box {
|
||||
width: 10%;
|
||||
text-align: center;
|
||||
padding: 28rpx 18rpx;
|
||||
|
||||
.status-title {
|
||||
flex-shrink: 0;
|
||||
color: #999;
|
||||
font-size: 28rpx;
|
||||
}
|
||||
|
||||
.status-icon {
|
||||
width: 100%;
|
||||
align-items: center;
|
||||
font-size: 24rpx;
|
||||
}
|
||||
|
||||
.status-input {
|
||||
flex: 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.u-tab-box {}
|
||||
|
||||
.message-list {
|
||||
padding: 0 20rpx;
|
||||
background-color: #fff;
|
||||
|
||||
.message-item {
|
||||
height: 132rpx;
|
||||
|
||||
.message-item-icon-flow {
|
||||
background-color: #33CC51 !important;
|
||||
}
|
||||
|
||||
.message-notice-icon {
|
||||
background-color: #e09f0c !important;
|
||||
}
|
||||
|
||||
.message-item-img {
|
||||
width: 96rpx;
|
||||
height: 96rpx;
|
||||
margin-right: 16rpx;
|
||||
flex-shrink: 0;
|
||||
border-radius: 50%;
|
||||
background-color: #3B87F7;
|
||||
position: relative;
|
||||
|
||||
.icon-ym {
|
||||
color: #fff;
|
||||
font-size: 50rpx;
|
||||
}
|
||||
|
||||
.redDot {
|
||||
height: 16rpx;
|
||||
width: 16rpx;
|
||||
border-radius: 50%;
|
||||
background: #FE5146;
|
||||
display: inline-block;
|
||||
// margin-right: 6rpx;
|
||||
flex-shrink: 0;
|
||||
position: absolute;
|
||||
right: 2rpx;
|
||||
top: 2rpx;
|
||||
}
|
||||
}
|
||||
|
||||
.message-item-txt {
|
||||
width: calc(100% - 112rpx);
|
||||
|
||||
.message-item-title {
|
||||
line-height: 46rpx;
|
||||
margin-bottom: 6rpx;
|
||||
|
||||
.title {
|
||||
font-size: 28rpx;
|
||||
}
|
||||
}
|
||||
|
||||
.message-item-cell {
|
||||
color: #909399;
|
||||
font-size: 24rpx;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
24
pages/index/mixin.js
Normal file
@@ -0,0 +1,24 @@
|
||||
import {
|
||||
useChatStore
|
||||
} from '@/store/modules/chat'
|
||||
export default {
|
||||
onShow() {
|
||||
this.setTabBarBadge()
|
||||
},
|
||||
methods: {
|
||||
setTabBarBadge() {
|
||||
const chatStore = useChatStore()
|
||||
const badgeNum = chatStore.getBadgeNum || 0
|
||||
if (badgeNum) {
|
||||
uni.setTabBarBadge({
|
||||
index: 2,
|
||||
text: badgeNum > 99 ? '99+' : badgeNum.toString()
|
||||
});
|
||||
} else {
|
||||
uni.removeTabBarBadge({
|
||||
index: 2
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
376
pages/index/my.vue
Normal file
@@ -0,0 +1,376 @@
|
||||
<template>
|
||||
<view class="my-v" v-if="loading">
|
||||
<view class="u-flex user-box">
|
||||
<view class="u-m-r-10">
|
||||
<u-avatar size="127" @click='chooseAvatar' :src='avatarSrc'></u-avatar>
|
||||
</view>
|
||||
<view class="u-flex-1 f-right" @click="personalPage('/pages/my/personalData/index')">
|
||||
<view class="u-font-36 u-m-l-16">{{baseInfo.realName}}</view>
|
||||
<view class="u-m-l-10 u-p-10">
|
||||
<u-icon name="arrow-right" color="#969799" size="28"></u-icon>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="u-m-t-20 my-group-box" v-for="(group, index) in cellGroups" :key="index">
|
||||
<view class="my-group-box-inner">
|
||||
<u-cell-group :border="false" class="cell-group">
|
||||
<view v-for="(item, idx) in group.items" :key="idx">
|
||||
<u-cell-item :title="$t(item.title)" @click="openPage(item.page, item.param)"
|
||||
:title-style="titleStyle" :border-bottom="item.borderBottom"
|
||||
v-if="item.title!='app.my.scanCode'">
|
||||
<template #icon>
|
||||
<text :class="['icon-ym', item.icon, 'u-m-r-16', 'u-font-32', 'my-list']"
|
||||
:style="{ color: item.color }" />
|
||||
</template>
|
||||
</u-cell-item>
|
||||
<!-- #ifndef H5 -->
|
||||
<u-cell-item :title="$t(item.title)" @click="scanCode()" :title-style="titleStyle"
|
||||
:border-bottom="item.borderBottom" v-if="item.title=='app.my.scanCode'">
|
||||
<template #icon>
|
||||
<text :class="['icon-ym', item.icon, 'u-m-r-16', 'u-font-32', 'my-list']"
|
||||
:style="{ color: item.color }" />
|
||||
</template>
|
||||
</u-cell-item>
|
||||
<!-- #endif -->
|
||||
</view>
|
||||
</u-cell-group>
|
||||
</view>
|
||||
</view>
|
||||
<view class="u-p-t-20">
|
||||
<view class="logout-cell" hover-class="u-cell-hover" @click="logout">{{$t('app.my.logout')}}</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
<script>
|
||||
import IndexMixin from './mixin.js'
|
||||
import {
|
||||
UpdateAvatar,
|
||||
UserSettingInfo,
|
||||
setMajor
|
||||
} from '@/api/common'
|
||||
import chat from '@/libs/chat.js'
|
||||
import {
|
||||
useUserStore
|
||||
} from '@/store/modules/user'
|
||||
import {
|
||||
useChatStore
|
||||
} from '@/store/modules/chat'
|
||||
|
||||
export default {
|
||||
mixins: [IndexMixin],
|
||||
data() {
|
||||
return {
|
||||
titleStyle: {
|
||||
color: '#606266'
|
||||
},
|
||||
userInfo: '',
|
||||
avatarSrc: '',
|
||||
baseInfo: {},
|
||||
loading: false,
|
||||
cellGroups: [{
|
||||
items: [{
|
||||
title: 'app.my.organization',
|
||||
page: '/pages/my/organization/index',
|
||||
param: 'position',
|
||||
icon: 'icon-ym-zuzhi',
|
||||
color: '#6071F5',
|
||||
borderBottom: true
|
||||
},
|
||||
{
|
||||
title: 'app.my.switchIdentity',
|
||||
page: '/pages/my/identity/index',
|
||||
param: 'standing',
|
||||
icon: 'icon-ym-position1',
|
||||
color: '#F4A02F',
|
||||
borderBottom: true
|
||||
},
|
||||
{
|
||||
title: 'app.my.changeSystem',
|
||||
page: '/pages/my/changeSystem/index',
|
||||
icon: 'icon-ym-header-sys-toggle',
|
||||
color: '#3686F2',
|
||||
borderBottom: false
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
items: [{
|
||||
title: 'app.my.personalSetting',
|
||||
page: '/pages/my/personalSetting/index',
|
||||
icon: 'icon-ym-shezhi',
|
||||
color: '#F46E1B',
|
||||
borderBottom: true
|
||||
},
|
||||
{
|
||||
title: 'app.my.accountSecurity',
|
||||
page: '/pages/my/accountSecurity/index',
|
||||
icon: 'icon-ym-secure',
|
||||
color: '#26C6A1',
|
||||
borderBottom: true
|
||||
},
|
||||
{
|
||||
title: 'app.my.contacts',
|
||||
page: '/pages/my/contacts/index',
|
||||
icon: 'icon-ym-contacts',
|
||||
color: '#6071F5',
|
||||
borderBottom: true
|
||||
},
|
||||
{
|
||||
title: 'app.my.chat',
|
||||
page: '/pages/message/chat/index',
|
||||
icon: 'icon-ym-chat',
|
||||
color: '#4CBF2A',
|
||||
borderBottom: false
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
items: [{
|
||||
title: 'app.my.scanCode',
|
||||
page: '',
|
||||
icon: 'icon-ym-scanCode1',
|
||||
color: '#F7AA41',
|
||||
borderBottom: true
|
||||
},
|
||||
{
|
||||
title: 'app.my.setting',
|
||||
page: '/pages/my/settings/index',
|
||||
icon: 'icon-ym-route-appMenu',
|
||||
color: '#5944FC',
|
||||
borderBottom: false
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
baseURL() {
|
||||
return this.define.comUploadUrl
|
||||
},
|
||||
baseURL2() {
|
||||
return this.define.baseURL
|
||||
},
|
||||
token() {
|
||||
return uni.getStorageSync('token')
|
||||
},
|
||||
report() {
|
||||
return this.define.report
|
||||
}
|
||||
},
|
||||
onLoad() {
|
||||
const chatStore = useChatStore()
|
||||
if (!chatStore.getSocket) chat.initSocket()
|
||||
},
|
||||
onShow() {
|
||||
UserSettingInfo().then(res => {
|
||||
this.baseInfo = res.data || {}
|
||||
this.avatarSrc = this.baseURL2 + this.baseInfo.avatar
|
||||
this.loading = true
|
||||
})
|
||||
uni.setNavigationBarTitle({
|
||||
title: "我的"
|
||||
})
|
||||
},
|
||||
methods: {
|
||||
chooseAvatar() {
|
||||
uni.chooseImage({
|
||||
count: 1,
|
||||
sizeType: ['original', 'compressed'],
|
||||
success: (res) => {
|
||||
// #ifdef H5
|
||||
let isAccept = new RegExp('image/*').test(res.tempFiles[0].type)
|
||||
if (!isAccept) return this.$u.toast(`请上传图片`)
|
||||
// #endif
|
||||
let tempFilePaths = res.tempFilePaths[0]
|
||||
uni.uploadFile({
|
||||
url: this.baseURL + 'userAvatar',
|
||||
filePath: tempFilePaths,
|
||||
name: 'file',
|
||||
header: {
|
||||
'Authorization': this.token
|
||||
},
|
||||
success: (uploadFileRes) => {
|
||||
let data = JSON.parse(uploadFileRes.data)
|
||||
if (data.code === 200) {
|
||||
UpdateAvatar(data.data.name).then(res => {
|
||||
this.$u.toast('头像更换成功')
|
||||
this.avatarSrc = this.baseURL2 + data.data.url
|
||||
})
|
||||
} else {
|
||||
this.$u.toast(data.msg)
|
||||
}
|
||||
},
|
||||
fail: (err) => {
|
||||
this.$u.toast('头像更换失败')
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
},
|
||||
openPage(path, type) {
|
||||
if (!path) return
|
||||
let url = !!type ? path + '?majorType=' + type : path
|
||||
uni.navigateTo({
|
||||
url: url
|
||||
})
|
||||
},
|
||||
personalPage(path) {
|
||||
if (!path) return;
|
||||
const neededFields = [
|
||||
'realName', 'nation', 'gender', 'nativePlace', 'certificatesType',
|
||||
'certificatesNumber', 'education', 'birthday', 'telePhone', 'landline',
|
||||
'urgentContacts', 'urgentTelePhone', 'postalAddress', 'signature'
|
||||
];
|
||||
const baseInfo = neededFields.reduce((obj, key) => {
|
||||
if (this.baseInfo[key] !== undefined) {
|
||||
obj[key] = this.baseInfo[key];
|
||||
}
|
||||
return obj;
|
||||
}, {});
|
||||
uni.navigateTo({
|
||||
url: `${path}?baseInfo=${JSON.stringify(baseInfo)}`
|
||||
});
|
||||
},
|
||||
isJSON(str) {
|
||||
try {
|
||||
var obj = JSON.parse(str);
|
||||
if (typeof obj == 'object' && obj) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
} catch (e) {
|
||||
return false;
|
||||
}
|
||||
},
|
||||
logout() {
|
||||
uni.showModal({
|
||||
title: '提示',
|
||||
content: '确定退出当前账号吗?',
|
||||
success: res => {
|
||||
if (res.confirm) {
|
||||
const userStore = useUserStore()
|
||||
userStore.logout().then(() => {
|
||||
uni.closeSocket()
|
||||
uni.reLaunch({
|
||||
url: '/pages/login/index'
|
||||
})
|
||||
})
|
||||
this.removeAccount()
|
||||
}
|
||||
}
|
||||
})
|
||||
},
|
||||
removeAccount() {
|
||||
let model = uni.getStorageSync('rememberAccount')
|
||||
if (!model.remember) {
|
||||
model.account = ''
|
||||
model.password = ''
|
||||
model.remember = false
|
||||
uni.setStorageSync('rememberAccount', model)
|
||||
}
|
||||
},
|
||||
scanCode() {
|
||||
uni.scanCode({
|
||||
success: res => {
|
||||
let url = ""
|
||||
if (this.isJSON(res.result.trim())) {
|
||||
const result = JSON.parse(res.result.trim())
|
||||
if (result.t === 'ADP') {
|
||||
let config = {
|
||||
isPreview: 1,
|
||||
moduleId: result.id,
|
||||
previewType: result.previewType
|
||||
}
|
||||
url = '/pages/apply/dynamicModel/index?config=' + this.jnpf.base64.encode(JSON
|
||||
.stringify(config))
|
||||
}
|
||||
if (result.t === 'DFD') {
|
||||
url = '/pages/apply/dynamicModel/scanForm?config=' + JSON.stringify(result)
|
||||
}
|
||||
if (result.t === 'WFP') {
|
||||
url = '/pages/workFlow/scanForm/index?config=' + JSON.stringify(result)
|
||||
}
|
||||
if (result.t === 'report') {
|
||||
userInfo = uni.getStorageSync('userInfo') || {}
|
||||
const appCode = userInfo.systemCode
|
||||
let url_ =
|
||||
`${this.report}/preview.html?id=${result.id}&token=${this.token}&appCode=${appCode}&page=1&from=menu`
|
||||
url = '/pages/apply/externalLink/index?url=' + encodeURIComponent(url_) +
|
||||
'&fullName= ' + result.fullName
|
||||
}
|
||||
if (result.t === 'portal') {
|
||||
url = '/pages/portal/scanPortal/index?id=' + result.id
|
||||
}
|
||||
if (result.t === 'login') {
|
||||
url = '/pages/login/scanLogin?id=' + result.id
|
||||
}
|
||||
} else {
|
||||
url = '/pages/my/scanResult/index?result=' + res.result
|
||||
}
|
||||
uni.navigateTo({
|
||||
url,
|
||||
fail: (err) => {
|
||||
this.$u.toast("暂无此页面")
|
||||
}
|
||||
})
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
page {
|
||||
background-color: #f0f2f6;
|
||||
}
|
||||
|
||||
.my-v {
|
||||
:deep(.u-cell) {
|
||||
height: 112rpx;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.my-group-box {
|
||||
.my-group-box-inner {
|
||||
background-color: #fff;
|
||||
|
||||
.cell-group {
|
||||
/* #ifndef MP-WEIXIN */
|
||||
padding: 0 20rpx;
|
||||
/* #endif */
|
||||
// padding: 0 20rpx;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.user-box {
|
||||
background-color: #fff;
|
||||
padding: 0 10rpx 10rpx 20rpx;
|
||||
/* #ifdef MP-WEIXIN */
|
||||
padding: 0 20rpx 20rpx 20rpx !important;
|
||||
/* #endif */
|
||||
}
|
||||
|
||||
.logout-cell {
|
||||
text-align: center;
|
||||
font-size: 32rpx;
|
||||
height: 108rpx;
|
||||
background-color: #fff;
|
||||
color: #D82828;
|
||||
line-height: 98rpx;
|
||||
font-family: PingFang SC;
|
||||
}
|
||||
|
||||
.f-right {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
192
pages/launch/guide.vue
Normal file
@@ -0,0 +1,192 @@
|
||||
<template>
|
||||
<view class="guide-v">
|
||||
<view class="content">
|
||||
<swiper class="swiper" @change="onChange">
|
||||
<swiper-item>
|
||||
<view class="swiper-item">
|
||||
<view class="swiper-item-img">
|
||||
<image class="itemImg" :src="guide1"></image>
|
||||
</view>
|
||||
</view>
|
||||
</swiper-item>
|
||||
<swiper-item>
|
||||
<view class="swiper-item">
|
||||
<view class="swiper-item-img">
|
||||
<image class="itemImg" :src="guide2"></image>
|
||||
</view>
|
||||
</view>
|
||||
</swiper-item>
|
||||
<swiper-item>
|
||||
<view class="swiper-item">
|
||||
<view class="swiper-item-img">
|
||||
<image class="itemImg" :src="guide3"></image>
|
||||
</view>
|
||||
<view class="swiper-item-btn" @click="setLaunchFlag()">立即体验</view>
|
||||
</view>
|
||||
</swiper-item>
|
||||
</swiper>
|
||||
<view class="jump-over" @click="setLaunchFlag()">跳过</view>
|
||||
<view class="bannerDots" v-if="currenTab!=3">
|
||||
<view class="banner-dot" v-for="(item,index) in bannerDot" :key="index"
|
||||
:class="{'active':index===currenTab}">
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import resources from '@/libs/resources.js'
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
bannerDot: [0, 1, 2],
|
||||
currenTab: 0,
|
||||
guide1: resources.guide.guide1,
|
||||
guide2: resources.guide.guide2,
|
||||
guide3: resources.guide.guide3
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
setLaunchFlag() {
|
||||
uni.setStorageSync('launchFlag', true)
|
||||
uni.reLaunch({
|
||||
url: '/pages/login/index'
|
||||
})
|
||||
},
|
||||
onChange(e) {
|
||||
this.currenTab = e.detail.current
|
||||
},
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style lang="scss">
|
||||
page {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.guide-v {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
|
||||
.status-bar {
|
||||
height: var(--status-bar-height);
|
||||
width: 100%;
|
||||
background-color: #FFFFFF;
|
||||
|
||||
.top-view {
|
||||
height: var(--status-bar-height);
|
||||
width: 100%;
|
||||
position: fixed;
|
||||
background-color: #FFFFFF;
|
||||
top: 0;
|
||||
z-index: 999;
|
||||
}
|
||||
}
|
||||
|
||||
.content {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background-size: 100% auto;
|
||||
padding: 0;
|
||||
touch-action: none;
|
||||
position: fixed;
|
||||
}
|
||||
|
||||
.swiper {
|
||||
width: 100%;
|
||||
height: 100% !important;
|
||||
background: #FFFFFF;
|
||||
}
|
||||
|
||||
.itemImg {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.swiper-item {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.swiper-item-img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.swiper-item-text {
|
||||
.swiper-item-title {
|
||||
line-height: 130rpx;
|
||||
font-size: 87rpx;
|
||||
color: $u-type-primary;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.swiper-item-content {
|
||||
font-size: 28rpx;
|
||||
color: #666666;
|
||||
}
|
||||
}
|
||||
|
||||
.bannerDots {
|
||||
width: 100%;
|
||||
height: 16rpx;
|
||||
display: flex;
|
||||
position: fixed;
|
||||
bottom: 8%;
|
||||
z-index: 99;
|
||||
left: 50%;
|
||||
transform: translate(-50%);
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
||||
.banner-dot {
|
||||
width: 16rpx;
|
||||
height: 16rpx;
|
||||
border-radius: 50%;
|
||||
background: #CACACA;
|
||||
margin: 0 10rpx;
|
||||
|
||||
&.active {
|
||||
width: 40rpx;
|
||||
height: 16rpx;
|
||||
background: $u-type-primary;
|
||||
border-radius: 8rpx;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.jump-over {
|
||||
position: absolute;
|
||||
z-index: 999;
|
||||
right: 46rpx;
|
||||
top: 86rpx;
|
||||
width: 128rpx;
|
||||
height: 54rpx;
|
||||
line-height: 54rpx;
|
||||
color: #fff;
|
||||
border-radius: 27rpx;
|
||||
text-align: center;
|
||||
font-size: 32rpx;
|
||||
background: rgba(123, 123, 123, 0.42);
|
||||
}
|
||||
|
||||
.swiper-item-btn {
|
||||
position: absolute;
|
||||
right: 7rem;
|
||||
bottom: 10rem;
|
||||
text-align: center;
|
||||
width: 296rpx;
|
||||
height: 84rpx;
|
||||
background-color: #E8F2FF;
|
||||
opacity: 1;
|
||||
border-radius: 50rpx;
|
||||
line-height: 84rpx;
|
||||
color: #3463FF;
|
||||
font-size: 28rpx;
|
||||
z-index: 99999;
|
||||
letter-spacing: 2rpx;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
103
pages/launch/index.vue
Normal file
@@ -0,0 +1,103 @@
|
||||
<template>
|
||||
<view class="launch-v">
|
||||
<view class="launch-box">
|
||||
<view class="title">全新模式 为你而来</view>
|
||||
<view class="version">VERSION6.0</view>
|
||||
<view class="launch-img">
|
||||
<image :src="startup" mode="widthFix"></image>
|
||||
</view>
|
||||
<view class="copyright">Copyright © 2025 引迈信息技术有限公司出品</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import resources from '@/libs/resources.js'
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
startup: resources.startup.main
|
||||
}
|
||||
},
|
||||
onLoad() {
|
||||
if (uni.getStorageSync('isUpdate')) return
|
||||
const launchFlag = uni.getStorageSync('launchFlag');
|
||||
const token = uni.getStorageSync("token") || '';
|
||||
if (launchFlag) {
|
||||
if (token) {
|
||||
uni.switchTab({
|
||||
url: '/pages/index/index'
|
||||
})
|
||||
} else {
|
||||
uni.redirectTo({
|
||||
url: '/pages/login/index'
|
||||
})
|
||||
}
|
||||
} else {
|
||||
// #ifdef APP
|
||||
uni.redirectTo({
|
||||
url: '/pages/launch/policy'
|
||||
})
|
||||
// #endif
|
||||
// #ifndef APP
|
||||
if (token) {
|
||||
uni.switchTab({
|
||||
url: '/pages/index/index'
|
||||
})
|
||||
} else {
|
||||
uni.redirectTo({
|
||||
url: '/pages/login/index'
|
||||
})
|
||||
}
|
||||
// #endif
|
||||
}
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.launch-v {
|
||||
.launch-box {
|
||||
padding-top: 170rpx;
|
||||
|
||||
.title {
|
||||
font-size: 50rpx;
|
||||
line-height: 70rpx;
|
||||
color: #5098FA;
|
||||
text-align: center;
|
||||
margin-bottom: 10rpx;
|
||||
}
|
||||
|
||||
.version {
|
||||
width: 250rpx;
|
||||
margin: 0 auto;
|
||||
text-align: center;
|
||||
height: 50rpx;
|
||||
border: 1px solid #5098FA;
|
||||
border-radius: 25rpx;
|
||||
line-height: 48rpx;
|
||||
color: #5098FA;
|
||||
letter-spacing: 2rpx;
|
||||
}
|
||||
|
||||
.launch-img {
|
||||
margin: 0 auto;
|
||||
width: 680rpx;
|
||||
|
||||
image {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.copyright {
|
||||
position: fixed;
|
||||
bottom: 120rpx;
|
||||
right: 0;
|
||||
left: 0;
|
||||
text-align: center;
|
||||
color: #999999;
|
||||
font-size: 24rpx;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
102
pages/launch/policy.vue
Normal file
@@ -0,0 +1,102 @@
|
||||
<template>
|
||||
<view class="policy-v">
|
||||
<view class="reminder-content">
|
||||
<image :src="loginlogo" class="logo" mode="widthFix"></image>
|
||||
<view class="u-font-36 u-m-t-20 u-m-b-30">引迈开发平台</view>
|
||||
<view class="policy-tips u-m-t-20">
|
||||
<view>欢迎使用引迈开发平台,依据政策要求,为了您能使用所有功能,在使用中需要连接网络、定位、调用麦克风等服务,请仔细阅读
|
||||
<text class="u-type-primary" @click="userAgreement">《用户协议》</text>和<text class="u-type-primary"
|
||||
@click="privacyPolicy">《隐私政策》</text>,选择下方“同意并继续”表示您同意以上协议内容。
|
||||
</view>
|
||||
</view>
|
||||
<view class="operation-btn u-flex u-row-between">
|
||||
<u-button @click="exitApp" :custom-style="customStyle">不同意</u-button>
|
||||
<u-button type="primary" @click="agree" :custom-style="customStyle">同意并继续</u-button>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import resources from '@/libs/resources.js'
|
||||
// #ifdef APP-HARMONY
|
||||
import {
|
||||
exitApp
|
||||
} from "@/uni_modules/jnpf-exitApp"
|
||||
// #endif
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
loginlogo: resources.login.logo,
|
||||
agreement: resources.userAgreement,
|
||||
policy: resources.privacyPolicy,
|
||||
customStyle: {
|
||||
width: '40%'
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
exitApp() {
|
||||
// #ifdef APP-HARMONY
|
||||
exitApp().then(res => {})
|
||||
// #endif
|
||||
// #ifndef APP-HARMONY
|
||||
plus.os.name == "Android" ? plus.runtime.quit() : plus.ios.import("UIApplication").sharedApplication()
|
||||
.performSelector("exit");
|
||||
// #endif
|
||||
},
|
||||
openAppProductBtn() {
|
||||
ExitApp({
|
||||
success: (res) => {
|
||||
console.log('success: ', JSON.stringify(res));
|
||||
},
|
||||
fail: (err) => {
|
||||
console.error('fail: ', JSON.stringify(err));
|
||||
},
|
||||
complete: (res) => {
|
||||
console.log('complete: ', JSON.stringify(res));
|
||||
}
|
||||
});
|
||||
},
|
||||
userAgreement() {
|
||||
plus.runtime.openURL(this.agreement);
|
||||
},
|
||||
privacyPolicy() {
|
||||
plus.runtime.openURL(this.policy);
|
||||
},
|
||||
agree() {
|
||||
uni.redirectTo({
|
||||
url: '/pages/launch/guide'
|
||||
})
|
||||
},
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.policy-v {
|
||||
padding-top: 300rpx;
|
||||
|
||||
.logo {
|
||||
width: 164rpx;
|
||||
}
|
||||
|
||||
.reminder-content {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
margin: 0 54rpx;
|
||||
}
|
||||
|
||||
.policy-tips {
|
||||
color: #9A9A9A;
|
||||
}
|
||||
|
||||
.operation-btn {
|
||||
position: fixed;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 100rpx;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
790
pages/login/index.vue
Normal file
@@ -0,0 +1,790 @@
|
||||
<template>
|
||||
<view class="logo-v">
|
||||
<view class="login-bg">
|
||||
<image src="../../static/image/login-bg.jpg" mode="widthFix"></image>
|
||||
<view class="logoImg">
|
||||
<u-image :src="appIcon" mode="widthFix" :border-radius="20" width="160" height="160">
|
||||
<template #error>
|
||||
<u-image :src="logoImg" mode="widthFix" width="160" height="160">
|
||||
</u-image>
|
||||
</template>
|
||||
</u-image>
|
||||
</view>
|
||||
<view class="login-version">
|
||||
<view class="login-version-text">{{sysConfigInfo.sysVersion || define.sysVersion}}</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="logo-hd u-flex-col">
|
||||
<view class="loginSwitch u-flex-col">
|
||||
<view class="loginInputBox u-flex-col" v-show="!isSso && !ssoLoading">
|
||||
<u-form :model="formData" :rules="rules" ref="dataForm" :errorType="['toast']" label-position="left"
|
||||
label-width="150" label-align="left">
|
||||
<u-form-item prop="account" :borderBottom="false">
|
||||
<u-input input-align='left' v-model="formData.account" placeholder="请输入帐号" @focus="onFocus"
|
||||
@blur="onBlur" border border-color="#F0F1F3" placeholder-style="#9D9D9D">
|
||||
</u-input>
|
||||
</u-form-item>
|
||||
<u-form-item prop="password" :border-bottom="false">
|
||||
<u-input input-align='left' v-model="formData.password" type="password" placeholder="请输入密码"
|
||||
border border-color="#F0F1F3" placeholder-style="#9D9D9D">
|
||||
</u-input>
|
||||
</u-form-item>
|
||||
<u-form-item prop="code" required v-if="needCode">
|
||||
<view class="u-flex code-box">
|
||||
<u-input v-model="formData.code" placeholder="验证码" input-align='left'></u-input>
|
||||
<view class="code-img-box">
|
||||
<u-image :showLoading="true" :src="baseURL+imgUrl" width="130px" height="38px"
|
||||
@click="changeCode">
|
||||
</u-image>
|
||||
</view>
|
||||
</view>
|
||||
</u-form-item>
|
||||
</u-form>
|
||||
<view class="remember-wrap">
|
||||
<u-checkbox v-model="remember"><span class="remember-text">记住账号密码</span></u-checkbox>
|
||||
</view>
|
||||
<view class="loginBtnBox">
|
||||
<u-button @click="login" type="primary" :loading="loading">{{ loading ? "登录中...":"登录"}}
|
||||
</u-button>
|
||||
</view>
|
||||
<template v-if="socialsList.length">
|
||||
<u-divider margin-top='40' margin-bottom='40' half-width='100%'>其他登录方式</u-divider>
|
||||
<view class="other-list">
|
||||
<block v-for="(item,i) in socialsList" :key="i">
|
||||
<!--#ifdef H5 || MP-WEIXIN -->
|
||||
<view class="other-item" v-if="item.enname==='wechat_open'" :title="item.name"
|
||||
@click="wechatLogin()"><text :class="item.icon" />
|
||||
</view>
|
||||
<view class="other-item" v-else-if="item.enname==='qq'" :title="item.name"
|
||||
@click="otherslogin(item.enname,item.renderUrl)"><text :class="item.icon" />
|
||||
</view>
|
||||
<!-- #endif -->
|
||||
<!--#ifdef APP-->
|
||||
<view class="other-item" v-if="item.enname==='qq'" :title="item.name"
|
||||
@click="qqOtherlogin()"><text :class="item.icon" />
|
||||
</view>
|
||||
<!-- #endif -->
|
||||
<!-- #ifndef MP-WEIXIN -->
|
||||
<view class="other-item" v-else :title="item.name"
|
||||
@click="otherslogin(item.enname,item.renderUrl)"><text :class="item.icon" />
|
||||
</view>
|
||||
<!-- #endif -->
|
||||
</block>
|
||||
</view>
|
||||
</template>
|
||||
</view>
|
||||
<view class="sso-login-btn" v-show="isSso && !ssoLoading">
|
||||
<u-button @click="ssoLogin" type="primary" :loading="loading">{{ loading ? "登录中...":"登录"}}
|
||||
</u-button>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<u-popup v-model="show" mode="left" width="90%" height="100%">
|
||||
<view class="mian">
|
||||
<view class='top'>
|
||||
<view class='img-box'>
|
||||
<image class="img" src="/static/image/tabbar/contactsHL.png" mode="widthFix"></image>
|
||||
</view>
|
||||
<view class='title'>
|
||||
请选择登录账号
|
||||
</view>
|
||||
</view>
|
||||
<view v-for="(item,i) in tenantUserInfo" :key="i">
|
||||
<view class='info' @click="socailsLogin(item)">
|
||||
<view class='user-name'>
|
||||
{{item.socialName}}
|
||||
</view>
|
||||
<view class='user-tenancy'>
|
||||
租户名称: {{item.tenantName}}
|
||||
</view>
|
||||
<view class='user-tenancy'>
|
||||
租户id:{{item.tenantId}}
|
||||
</view>
|
||||
<view class='user-tenancy'>
|
||||
账号:{{item.accountName}}
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</u-popup>
|
||||
<view class="copyright" v-if="isKeyUp">{{copyright}}</view>
|
||||
</view>
|
||||
</template>
|
||||
<script>
|
||||
import {
|
||||
login,
|
||||
getConfig,
|
||||
getCallback,
|
||||
otherlogin,
|
||||
getLoginConfig,
|
||||
getSocialsUserList,
|
||||
socialsLogin,
|
||||
getTicket
|
||||
} from '@/api/common.js'
|
||||
import md5Libs from "@/uni_modules/vk-uview-ui/libs/function/md5";
|
||||
import resources from '@/libs/resources'
|
||||
import {
|
||||
useUserStore
|
||||
} from '@/store/modules/user'
|
||||
import logoImg from '@/static/logo.png'
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
remember: false,
|
||||
logoImg,
|
||||
imgUrl: '',
|
||||
loading: false,
|
||||
formData: {
|
||||
account: "",
|
||||
password: "",
|
||||
code: "",
|
||||
origin: 'password'
|
||||
},
|
||||
needCode: false,
|
||||
codeLength: 4,
|
||||
isCode: false,
|
||||
rules: {
|
||||
account: [{
|
||||
required: true,
|
||||
message: '请输入账号',
|
||||
trigger: 'blur',
|
||||
}],
|
||||
password: [{
|
||||
required: true,
|
||||
message: '请输入密码',
|
||||
trigger: 'blur',
|
||||
}],
|
||||
},
|
||||
sysConfigInfo: {},
|
||||
appIcon: '',
|
||||
sysName: '',
|
||||
copyright: '',
|
||||
socialsList: [],
|
||||
show: false,
|
||||
tenantUserInfo: [],
|
||||
ssoLoading: true,
|
||||
isSso: false,
|
||||
ssoTicket: '',
|
||||
ssoUrl: '',
|
||||
preUrl: '',
|
||||
ticketParams: "",
|
||||
loginCode: '',
|
||||
isKeyUp: true
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
remember: {
|
||||
handler(val) {
|
||||
let model = uni.getStorageSync('rememberAccount')
|
||||
if (!model) model = {
|
||||
account: '',
|
||||
password: ''
|
||||
}
|
||||
model.remember = val
|
||||
uni.setStorageSync('rememberAccount', model)
|
||||
},
|
||||
deep: true,
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
baseURL() {
|
||||
return this.define.baseURL
|
||||
},
|
||||
},
|
||||
onReady() {
|
||||
this.$refs.dataForm.setRules(this.rules);
|
||||
},
|
||||
onLoad(options) {
|
||||
if (options?.JNPF_TICKET) {
|
||||
this.ssoTicket = options.JNPF_TICKET
|
||||
uni.navigateTo({
|
||||
url: `/pages/login/otherLogin?ssoTicket=${this.ssoTicket}`
|
||||
})
|
||||
}
|
||||
this.ssoTicket = uni.getStorageSync('ssoTicket')
|
||||
this.sysConfigInfo = uni.getStorageSync('sysConfigInfo')
|
||||
this.appIcon = !!this.sysConfigInfo.appIcon ? this.baseURL + this.sysConfigInfo.appIcon :
|
||||
logoImg
|
||||
this.sysName = !!this.sysConfigInfo.companyName ? this.sysConfigInfo.sysName :
|
||||
'JNPF快速开发平台'
|
||||
this.copyright = !!this.sysConfigInfo.copyright ? this.sysConfigInfo.copyright :
|
||||
this.define.copyright
|
||||
uni.setNavigationBarTitle({
|
||||
title: this.sysName
|
||||
})
|
||||
let needCode = uni.getStorageSync('app_loginNeedCode')
|
||||
this.isCode = needCode
|
||||
this.changeCode()
|
||||
this.getLoginConfig()
|
||||
this.formData.password = '';
|
||||
if (options.data) {
|
||||
this.tenantUserInfo = JSON.parse(options.data)
|
||||
if (this.tenantUserInfo) this.show = true
|
||||
}
|
||||
this.initAccount()
|
||||
// #ifndef H5
|
||||
uni.onKeyboardHeightChange(res => {
|
||||
this.isKeyUp = res.height == 0 ? true : false
|
||||
return this.isKeyUp
|
||||
})
|
||||
// #endif
|
||||
},
|
||||
methods: {
|
||||
initAccount() {
|
||||
let model = uni.getStorageSync('rememberAccount')
|
||||
if (model && model.remember) {
|
||||
if (model.account) {
|
||||
this.formData.account = this.jnpf.aesEncryption.decrypt(model.account)
|
||||
}
|
||||
if (model.password) {
|
||||
this.formData.password = this.jnpf.aesEncryption.decrypt(model.password)
|
||||
}
|
||||
}
|
||||
this.remember = model.remember
|
||||
},
|
||||
rememberAccount() {
|
||||
// 是否记住密码
|
||||
if (this.remember) {
|
||||
let model = {};
|
||||
model.remember = true
|
||||
model.account = this.jnpf.aesEncryption.encrypt(this.formData.account)
|
||||
model.password = this.jnpf.aesEncryption.encrypt(this.formData.password)
|
||||
uni.setStorageSync('rememberAccount', model)
|
||||
}
|
||||
},
|
||||
loginHandel() {
|
||||
uni.showLoading({
|
||||
title: '登录中'
|
||||
})
|
||||
userStore.getCurrentUser().then((res) => {
|
||||
uni.hideLoading()
|
||||
uni.reLaunch({
|
||||
url: '/pages/index/index'
|
||||
});
|
||||
}).catch(() => {
|
||||
uni.hideLoading()
|
||||
uni.reLaunch({
|
||||
url: '/pages/login/index'
|
||||
});
|
||||
})
|
||||
},
|
||||
loginToken(res) {
|
||||
const userStore = useUserStore()
|
||||
userStore.setToken(res.data.value)
|
||||
if (res.data.status != 2) {
|
||||
// 登录成功
|
||||
if (res.data.status == 1) return this.loginHandel()
|
||||
if (res.data.status == 6) {
|
||||
this.tenantUserInfo = JSON.parse(res.data.value)
|
||||
if (this.tenantUserInfo.length == 1) {
|
||||
this.loginHandel()
|
||||
} else {
|
||||
this.show = true
|
||||
}
|
||||
} else {
|
||||
this.show = false
|
||||
this.ssoUrl = ''
|
||||
uni.showToast({
|
||||
title: res.data.value || '操作超时,请重新点击登录',
|
||||
icon: 'none'
|
||||
})
|
||||
}
|
||||
}
|
||||
},
|
||||
wechatLogin() {
|
||||
// #ifdef MP-WEIXIN
|
||||
getTicket().then(res => {
|
||||
this.ssoTicket = res.data
|
||||
uni.login({
|
||||
provider: 'weixin',
|
||||
success: (loginRes) => {
|
||||
this.loginCode = loginRes.code
|
||||
}
|
||||
})
|
||||
uni.getUserProfile({
|
||||
desc: '获取你的昵称、头像、地区及性别',
|
||||
success: (info) => {
|
||||
let qurey = {
|
||||
encryptedData: info.encryptedData,
|
||||
iv: info.iv,
|
||||
signature: info.signature,
|
||||
code: this.loginCode,
|
||||
jnpf_ticket: this.ssoTicket,
|
||||
socialName: info.userInfo.nickName,
|
||||
source: 'wechat_applets'
|
||||
}
|
||||
socialsLogin(qurey).then(res => {
|
||||
this.loginToken(res)
|
||||
})
|
||||
}
|
||||
})
|
||||
})
|
||||
// #endif
|
||||
// #ifdef APP-PLUS
|
||||
getTicket().then(res => {
|
||||
this.ssoTicket = res.data
|
||||
uni.login({
|
||||
provider: 'weixin',
|
||||
success: (loginRes) => {
|
||||
// 登录成功
|
||||
uni.getUserProfile({
|
||||
provider: 'weixin',
|
||||
success: (info) => {
|
||||
let data = {
|
||||
source: 'wechat_open',
|
||||
uuid: info.userInfo.unionId,
|
||||
socialName: info.userInfo.nickName,
|
||||
jnpf_ticket: this.ssoTicket
|
||||
};
|
||||
socialsLogin(data).then(res => {
|
||||
this.loginToken(res)
|
||||
})
|
||||
},
|
||||
fail: function(err) {
|
||||
// 登录授权失败
|
||||
// err.code是错误码
|
||||
}
|
||||
})
|
||||
}
|
||||
});
|
||||
})
|
||||
// #endif
|
||||
},
|
||||
qqOtherlogin() {
|
||||
getTicket().then(res => {
|
||||
this.ssoTicket = res.data
|
||||
uni.login({
|
||||
provider: 'qq',
|
||||
success: (loginRes) => {
|
||||
// 登录成功
|
||||
uni.getUserInfo({
|
||||
provider: 'qq',
|
||||
success: (info) => {
|
||||
let data = {
|
||||
source: 'qq',
|
||||
jnpf_ticket: this.ssoTicket,
|
||||
socialName: info.userInfo.nickName,
|
||||
uuid: info.userInfonickName.unionid,
|
||||
};
|
||||
socialsLogin(data).then(res => {
|
||||
this.loginToken(res)
|
||||
}).catch((err) => {})
|
||||
// 获取用户信息成功, info.authResult保存用户信息
|
||||
}
|
||||
})
|
||||
}
|
||||
});
|
||||
})
|
||||
},
|
||||
socailsLogin(item) {
|
||||
const userStore = useUserStore()
|
||||
item.tenantLogin = true
|
||||
socialsLogin(item).then(res => {
|
||||
if (res.code == 200) {
|
||||
uni.showLoading({
|
||||
title: '登录中'
|
||||
})
|
||||
userStore.setToken(res.data.token)
|
||||
userStore.getCurrentUser().then((res) => {
|
||||
uni.hideLoading()
|
||||
uni.switchTab({
|
||||
url: '/pages/index/index'
|
||||
});
|
||||
this.show = false
|
||||
}).catch(() => {
|
||||
uni.hideLoading()
|
||||
uni.switchTab({
|
||||
url: '/pages/login/index'
|
||||
});
|
||||
})
|
||||
}
|
||||
}).catch(() => {
|
||||
uni.hideLoading()
|
||||
uni.switchTab({
|
||||
url: '/pages/login/index'
|
||||
});
|
||||
})
|
||||
},
|
||||
otherslogin(key, url) {
|
||||
if (key === 'wechat_open') {
|
||||
this.wechatLogin();
|
||||
} else {
|
||||
getTicket().then(res => {
|
||||
this.ssoTicket = res.data
|
||||
url = url.replace('JNPF_TICKET', this.ssoTicket)
|
||||
uni.setStorageSync('ssoUrl', url)
|
||||
uni.navigateTo({
|
||||
url: `/pages/login/otherLogin?ssoTicket=` + this.ssoTicket
|
||||
})
|
||||
}).catch(() => {})
|
||||
}
|
||||
},
|
||||
onFocus(e) {
|
||||
this.getCodeConfig(e)
|
||||
},
|
||||
onBlur(e) {
|
||||
this.getCodeConfig(e)
|
||||
},
|
||||
// 获取登陆配置
|
||||
getLoginConfig() {
|
||||
getLoginConfig().then(res => {
|
||||
this.isSso = res.data.redirect
|
||||
this.preUrl = res.data.url
|
||||
this.ticketParams = res.data.ticketParams
|
||||
let socialsList = res.data.socialsList || []
|
||||
this.socialsList = socialsList.filter(o => o.latest && o.enname !=
|
||||
'github' && o
|
||||
.enname !=
|
||||
'wechat_enterprise')
|
||||
this.ssoLoading = false
|
||||
}).catch(() => {
|
||||
this.isSso = false
|
||||
this.ssoLoading = false
|
||||
})
|
||||
},
|
||||
getCodeConfig(val) {
|
||||
if (!val) return
|
||||
getConfig(val).then(res => {
|
||||
this.needCode = !!res.data.enableVerificationCode
|
||||
if (this.needCode) {
|
||||
this.codeLength = res.data.verificationCodeNumber || 4
|
||||
this.changeCode()
|
||||
}
|
||||
})
|
||||
},
|
||||
changeCode() {
|
||||
let timestamp = Math.random()
|
||||
this.timestamp = timestamp
|
||||
this.imgUrl = `/api/oauth/ImageCode/${this.codeLength || 4}/${timestamp}`
|
||||
},
|
||||
login() {
|
||||
const userStore = useUserStore()
|
||||
this.$refs.dataForm.validate(valid => {
|
||||
if (valid) {
|
||||
this.loading = true
|
||||
const password = md5Libs.md5(this.formData.password);
|
||||
const encryptPassword = this.jnpf.aesEncryption.encrypt(password);
|
||||
let query = {
|
||||
account: this.formData.account,
|
||||
password: encryptPassword,
|
||||
timestamp: this.timestamp,
|
||||
code: this.formData.code,
|
||||
origin: this.formData.origin,
|
||||
jnpf_ticket: this.ssoTicket,
|
||||
grant_type: 'password',
|
||||
}
|
||||
// #ifdef APP-PLUS
|
||||
const clientId = plus.push.getClientInfo().clientid;
|
||||
query.clientId = clientId
|
||||
/* unipush2.0 */
|
||||
// query.Client_Id = uni.getStorageSync('cid')
|
||||
// #endif
|
||||
login(query).then(res => {
|
||||
let token = res.data.token
|
||||
userStore.setToken(token)
|
||||
this.rememberAccount()
|
||||
setTimeout(()=>{
|
||||
userStore.getCurrentUser().then(res => {
|
||||
this.loading = false
|
||||
uni.switchTab({
|
||||
url: '/pages/index/index'
|
||||
});
|
||||
}).catch(() => {
|
||||
this.loading = false
|
||||
})
|
||||
},1000)
|
||||
}).catch((err) => {
|
||||
uni.showToast({
|
||||
title: err,
|
||||
icon: 'none'
|
||||
})
|
||||
this.getCodeConfig(this.formData.account)
|
||||
this.formData.code = ''
|
||||
this.changeCode()
|
||||
this.loading = false
|
||||
})
|
||||
}
|
||||
});
|
||||
},
|
||||
ssoLogin() {
|
||||
getTicket().then(res => {
|
||||
this.ssoTicket = res.data
|
||||
this.ssoUrl = this.preUrl + '?' + this.ticketParams + '=' + this.ssoTicket
|
||||
uni.setStorageSync('ssoUrl', this.ssoUrl)
|
||||
uni.navigateTo({
|
||||
url: `/pages/login/otherLogin?ssoTicket=${this.ssoTicket}`
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
page {
|
||||
width: 100%;
|
||||
min-height: 100vh;
|
||||
}
|
||||
|
||||
.remember-wrap {
|
||||
margin-top: 8px;
|
||||
|
||||
& .remember-text {
|
||||
color: #9A9A9A;
|
||||
font-size: 13px;
|
||||
}
|
||||
}
|
||||
|
||||
.logo-v {
|
||||
height: 100vh;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
z-index: -1;
|
||||
|
||||
.login-bg {
|
||||
height: 726rpx;
|
||||
position: relative;
|
||||
|
||||
image {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.login-version {
|
||||
position: fixed;
|
||||
right: 0px;
|
||||
top: 0px;
|
||||
width: 120rpx;
|
||||
height: 120rpx;
|
||||
background: url('../../static/image/login_version.png') no-repeat center;
|
||||
background-size: 100%;
|
||||
|
||||
.login-version-text {
|
||||
width: 120rpx;
|
||||
height: 120rpx;
|
||||
line-height: 70rpx;
|
||||
text-align: center;
|
||||
color: #fff;
|
||||
font-size: 28rpx;
|
||||
transform: rotate(45deg);
|
||||
}
|
||||
}
|
||||
|
||||
.logoImg {
|
||||
width: 160rpx;
|
||||
height: 160rpx;
|
||||
margin: 0 auto;
|
||||
position: absolute;
|
||||
/* #ifdef APP-PLUS */
|
||||
bottom: -90rpx;
|
||||
/* #endif */
|
||||
/* #ifndef APP-PLUS */
|
||||
bottom: 0;
|
||||
/* #endif */
|
||||
left: 0;
|
||||
right: 0;
|
||||
top: 270rpx;
|
||||
|
||||
.image {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
border-radius: 20%;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.logo-hd {
|
||||
width: 100%;
|
||||
margin-top: -240rpx;
|
||||
|
||||
.introduce {
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
|
||||
.text-one {
|
||||
height: 70rpx;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.text-two {
|
||||
color: #999999;
|
||||
}
|
||||
}
|
||||
|
||||
.loginSwitch {
|
||||
margin-top: 40rpx;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
|
||||
.tabs {
|
||||
color: #999999;
|
||||
position: relative;
|
||||
|
||||
&::after {
|
||||
content: "";
|
||||
width: 64rpx;
|
||||
height: 4rpx;
|
||||
background-color: #356efe;
|
||||
margin-top: 15rpx;
|
||||
position: absolute;
|
||||
left: 0;
|
||||
bottom: -15rpx;
|
||||
display: block;
|
||||
border-radius: 50rpx;
|
||||
}
|
||||
|
||||
&.active2 {
|
||||
&::after {
|
||||
left: 70%;
|
||||
}
|
||||
}
|
||||
|
||||
.tab {
|
||||
width: 50%;
|
||||
height: 80upx;
|
||||
text-align: center;
|
||||
color: #AEAFB5;
|
||||
font-size: 32upx;
|
||||
|
||||
&.active {
|
||||
color: #3281ff;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
.loginInputBox {
|
||||
width: 100%;
|
||||
/* #ifdef APP-PLUS */
|
||||
margin-top: 120rpx;
|
||||
/* #endif */
|
||||
/* #ifndef APP-PLUS */
|
||||
margin-top: 80rpx;
|
||||
/* #endif */
|
||||
padding: 0 64rpx;
|
||||
|
||||
.code-box {
|
||||
width: 100%;
|
||||
|
||||
.code-img-box {
|
||||
flex: 0.1;
|
||||
}
|
||||
}
|
||||
|
||||
.loginBtnBox {
|
||||
margin-top: 156rpx;
|
||||
}
|
||||
|
||||
.u-form-item {
|
||||
padding: 12rpx 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.copyright {
|
||||
width: 100%;
|
||||
height: 32rpx;
|
||||
position: fixed;
|
||||
bottom: 102rpx;
|
||||
left: 50%;
|
||||
right: 0;
|
||||
text-align: center;
|
||||
color: #A2A7BE;
|
||||
font-size: 12px;
|
||||
font-family: PingFang SC;
|
||||
transform: translateX(-50%);
|
||||
}
|
||||
|
||||
.sso-login-btn {
|
||||
width: 100%;
|
||||
padding: 0 64rpx;
|
||||
/* #ifdef APP-PLUS */
|
||||
margin-top: 404rpx;
|
||||
/* #endif */
|
||||
/* #ifndef APP-PLUS */
|
||||
margin-top: 364rpx;
|
||||
/* #endif */
|
||||
}
|
||||
}
|
||||
|
||||
.other-list {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-around;
|
||||
|
||||
.other-item {
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
line-height: 30px;
|
||||
text-align: center;
|
||||
cursor: pointer;
|
||||
border-radius: 50%;
|
||||
|
||||
text {
|
||||
font-size: 20px;
|
||||
color: #a0acb7;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.mian {
|
||||
background: url('/static/image/tenancy.png');
|
||||
height: 100%;
|
||||
|
||||
.top {
|
||||
.img_box {
|
||||
margin-top: 20rpx;
|
||||
margin-left: 30%;
|
||||
|
||||
.img {
|
||||
height: 50rpx;
|
||||
width: 50rpx;
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.title {
|
||||
margin-top: -55rpx;
|
||||
margin-left: 260rpx;
|
||||
font-size: 32rpx;
|
||||
}
|
||||
|
||||
.info {
|
||||
margin: auto auto;
|
||||
width: 96%;
|
||||
height: 300rpx;
|
||||
background-color: #fff;
|
||||
margin-bottom: 20rpx;
|
||||
border-radius: 10rpx;
|
||||
border-left: 10rpx solid #9DC8FA;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.user-name {
|
||||
font-weight: bold;
|
||||
font-size: 32rpx;
|
||||
margin-left: 20rpx;
|
||||
margin-bottom: 20rpx;
|
||||
margin-top: 30rpx;
|
||||
width: 100%;
|
||||
height: 60rpx;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.user-tenancy {
|
||||
font-size: 28rpx;
|
||||
margin-left: 20rpx;
|
||||
margin-bottom: 20rpx;
|
||||
width: 100%;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
</style>
|
||||
114
pages/login/otherLogin.vue
Normal file
@@ -0,0 +1,114 @@
|
||||
@@ -0,0 +1,70 @@
|
||||
<template>
|
||||
<view>
|
||||
<web-view :src="url"></web-view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {
|
||||
getTicketStatus,
|
||||
socialsLogin
|
||||
} from '@/api/common.js'
|
||||
import {
|
||||
useUserStore
|
||||
} from '@/store/modules/user'
|
||||
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
show: false,
|
||||
url: '',
|
||||
ticket: '',
|
||||
ssoTimer: null,
|
||||
tenantUserInfo: [],
|
||||
}
|
||||
},
|
||||
onLoad(option) {
|
||||
this.url = uni.getStorageSync('ssoUrl')
|
||||
this.ticket = option.ssoTicket
|
||||
this.ssoTimer = setInterval(() => {
|
||||
this.getTicketStatus()
|
||||
}, 1000)
|
||||
},
|
||||
onUnload() {
|
||||
this.clearTimer()
|
||||
},
|
||||
methods: {
|
||||
getTicketStatus() {
|
||||
const userStore = useUserStore()
|
||||
if (!this.ticket) return
|
||||
getTicketStatus(this.ticket).then(res => {
|
||||
if (res.data.status != 2) {
|
||||
this.clearTimer()
|
||||
// 登录成功
|
||||
if (res.data.status == 1) {
|
||||
uni.showLoading({
|
||||
title: '登录中'
|
||||
})
|
||||
userStore.setToken(res.data.value)
|
||||
userStore.getCurrentUser().then(res => {
|
||||
uni.hideLoading()
|
||||
uni.reLaunch({
|
||||
url: '/pages/index/index'
|
||||
});
|
||||
}).catch(() => {
|
||||
uni.hideLoading()
|
||||
uni.reLaunch({
|
||||
url: '/pages/index/index'
|
||||
});
|
||||
})
|
||||
} else if (res.data.status == 4) {
|
||||
uni.setStorageSync('ssoTicket', this.ticket)
|
||||
uni.reLaunch({
|
||||
url: '/pages/login/index',
|
||||
success: () => this.$u.toast('第三方账号未绑定,5分钟内登录本系统账号密码自动绑定该账号!')
|
||||
})
|
||||
|
||||
} else if (res.data.status == 6) {
|
||||
let tenantUserInfo = JSON.parse(res.data.value)
|
||||
if (tenantUserInfo.length == 1) {
|
||||
uni.showLoading({
|
||||
title: '登录中'
|
||||
})
|
||||
userStore.setToken(res.data.value)
|
||||
uni.hideLoading()
|
||||
uni.reLaunch({
|
||||
url: '/pages/index/index'
|
||||
});
|
||||
} else {
|
||||
uni.reLaunch({
|
||||
url: '/pages/login/index?data=' + JSON.stringify(tenantUserInfo)
|
||||
})
|
||||
}
|
||||
} else if (res.data.status == 7) {
|
||||
this.$u.toast('第三方账号未绑定账号,请绑定后重试')
|
||||
setTimeout(() => {
|
||||
uni.reLaunch({
|
||||
url: '/pages/login/index'
|
||||
})
|
||||
}, 600)
|
||||
} else {
|
||||
this.show = false
|
||||
this.ssoUrl = ''
|
||||
uni.showToast({
|
||||
title: res.data.value || '操作超时,请重新点击登录',
|
||||
icon: 'none'
|
||||
})
|
||||
uni.reLaunch({
|
||||
url: '/pages/login/index'
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
})
|
||||
},
|
||||
clearTimer() {
|
||||
if (this.ssoTimer) {
|
||||
clearInterval(this.ssoTimer)
|
||||
this.ssoTimer = null
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
148
pages/login/scanLogin.vue
Normal file
@@ -0,0 +1,148 @@
|
||||
<template>
|
||||
<view class="scanLogin-v">
|
||||
<view class="scanLogin-icon">
|
||||
<view class="icon-ym icon-ym-pc"></view>
|
||||
</view>
|
||||
<view class="title">登录确认</view>
|
||||
<view class="tip">请确认是否本人操作</view>
|
||||
<view class="tip">并确保二维码来源安全</view>
|
||||
<view class="scanLogin-actions">
|
||||
<u-button class="buttom-btn" type="primary" @click="handelConfirmLogin" v-if="!expired">确认登录</u-button>
|
||||
<u-button class="buttom-btn" type="primary" @click="reScan" v-if="expired">重新扫码登录</u-button>
|
||||
<text class="goBackText" @click="goBack()">取消</text>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {
|
||||
setCodeCertificateStatus,
|
||||
confirmLogin
|
||||
} from '@/api/common.js'
|
||||
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
ticket: '',
|
||||
expired: false
|
||||
}
|
||||
},
|
||||
onLoad(option) {
|
||||
this.init(option.id || '')
|
||||
},
|
||||
methods: {
|
||||
init(ticket) {
|
||||
this.ticket = ticket
|
||||
this.expired = false
|
||||
setCodeCertificateStatus(ticket, '1')
|
||||
},
|
||||
goBack() {
|
||||
setCodeCertificateStatus(this.ticket, '-1').then(res => {
|
||||
uni.navigateBack()
|
||||
})
|
||||
},
|
||||
reScan() {
|
||||
uni.scanCode({
|
||||
success: res => {
|
||||
let url = ""
|
||||
if (this.isJSON(res.result.trim())) {
|
||||
const result = JSON.parse(res.result.trim())
|
||||
if (result.t === 'login') this.init(result.id || '')
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
isJSON(str) {
|
||||
try {
|
||||
var obj = JSON.parse(str);
|
||||
if (typeof obj == 'object' && obj) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
} catch (e) {
|
||||
return false;
|
||||
}
|
||||
},
|
||||
handelConfirmLogin() {
|
||||
confirmLogin(this.ticket).then(res => {
|
||||
if (res.data.status === -1) {
|
||||
uni.showToast({
|
||||
title: '二维码已失效,请重新扫码登录',
|
||||
icon: 'none'
|
||||
})
|
||||
this.expired = true
|
||||
return;
|
||||
}
|
||||
if (res.data.status === 2) {
|
||||
uni.showToast({
|
||||
title: '登录成功',
|
||||
icon: 'none',
|
||||
complete: () => {
|
||||
setTimeout(() => {
|
||||
uni.navigateBack()
|
||||
}, 1500)
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
page {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.scanLogin-v {
|
||||
height: 100%;
|
||||
position: relative;
|
||||
text-align: center;
|
||||
padding-top: 160rpx;
|
||||
|
||||
.scanLogin-icon {
|
||||
height: 140rpx;
|
||||
width: 140rpx;
|
||||
margin: 0 auto 64rpx;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
border-radius: 50%;
|
||||
border: 4rpx solid #2979ff;
|
||||
color: #2979ff;
|
||||
|
||||
.icon-ym-pc {
|
||||
font-size: 80rpx;
|
||||
}
|
||||
}
|
||||
|
||||
.title {
|
||||
font-size: 40rpx;
|
||||
font-weight: 600;
|
||||
line-height: 56rpx;
|
||||
margin-bottom: 30rpx;
|
||||
}
|
||||
|
||||
.tip {
|
||||
font-size: 28rpx;
|
||||
color: #7E7E7E;
|
||||
line-height: 44rpx;
|
||||
}
|
||||
|
||||
.scanLogin-actions {
|
||||
margin-top: 270rpx;
|
||||
padding: 0 64rpx;
|
||||
|
||||
.buttom-btn {
|
||||
margin-bottom: 20rpx;
|
||||
}
|
||||
|
||||
.goBackText {
|
||||
line-height: 80rpx;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
35
pages/login/sso-redirect.vue
Normal file
@@ -0,0 +1,35 @@
|
||||
<template>
|
||||
<view class="">
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {
|
||||
useUserStore
|
||||
} from '@/store/modules/user'
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
token: ''
|
||||
}
|
||||
},
|
||||
onLoad(e) {
|
||||
this.token = e.token
|
||||
this.init()
|
||||
},
|
||||
methods: {
|
||||
init() {
|
||||
const userStore = useUserStore()
|
||||
userStore.setToken(this.token)
|
||||
this.show = false
|
||||
uni.hideLoading()
|
||||
uni.reLaunch({
|
||||
url: '/pages/index/index'
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
</style>
|
||||
292
pages/message/chat/index.vue
Normal file
@@ -0,0 +1,292 @@
|
||||
<template>
|
||||
<view class="message-v">
|
||||
<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" style="width: 100%;">
|
||||
</u-search>
|
||||
</view>
|
||||
<mescroll-body ref="mescrollRef" @init="mescrollInit" @down="downCallback" @up="upCallback" :sticky="false"
|
||||
:down="downOption" :up="upOption" :bottombar="false">
|
||||
<view class="message-list">
|
||||
<view class="message-list-box">
|
||||
<SwipeItem :list="list" :buttons="options" @action="handleRelocation" ref="swipeItem">
|
||||
<template v-slot="{ item }">
|
||||
<view class="reply-item u-border-bottom u-flex" @click="toIm(item)">
|
||||
<view class="reply-item-img">
|
||||
<u-avatar :src="baseURL+item.headIcon" mode="square" size="96" />
|
||||
</view>
|
||||
<view class="reply-item-txt u-flex-1">
|
||||
<view class="reply-item-cell reply-item-title u-flex u-row-between">
|
||||
<text class="title">{{item.realName}}/{{item.account}}</text>
|
||||
<text class="u-font-24 againColor">{{jnpf.toDateText(item.latestDate)}}</text>
|
||||
</view>
|
||||
<view class="reply-item-cell u-flex u-row-between">
|
||||
<text
|
||||
class="reply-item-txt-msg u-line-1 againColor">{{getMsgText(item.latestMessage,item.messageType)}}</text>
|
||||
<u-badge type="error" :count="item.unreadMessage" :absolute="false" />
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
</SwipeItem>
|
||||
</view>
|
||||
</view>
|
||||
</mescroll-body>
|
||||
<!-- -->
|
||||
</view>
|
||||
</template>
|
||||
<script>
|
||||
import MescrollMixin from "@/uni_modules/mescroll-uni/components/mescroll-uni/mescroll-mixins.js";
|
||||
import SwipeItem from "@/components/SwipeItem/index"
|
||||
import resources from '@/libs/resources.js'
|
||||
import {
|
||||
useChatStore
|
||||
} from '@/store/modules/chat'
|
||||
import {
|
||||
getIMReply,
|
||||
relocation
|
||||
} from '@/api/message.js'
|
||||
export default {
|
||||
mixins: [MescrollMixin],
|
||||
components: {
|
||||
SwipeItem
|
||||
},
|
||||
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",
|
||||
}
|
||||
},
|
||||
key: +new Date(),
|
||||
keyword: '',
|
||||
list: [],
|
||||
options: [{
|
||||
text: '移除',
|
||||
style: {
|
||||
backgroundColor: '#dd524d',
|
||||
},
|
||||
value: 'delete'
|
||||
}],
|
||||
swipeAction: false
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
msgInfo() {
|
||||
const chatStore = useChatStore()
|
||||
return chatStore.getMsgInfo
|
||||
},
|
||||
baseURL() {
|
||||
return this.define.baseURL
|
||||
},
|
||||
},
|
||||
onLoad() {
|
||||
this.keyword = ''
|
||||
uni.$on('updateList', data => {
|
||||
this.$nextTick(() => {
|
||||
this.mescroll.triggerDownScroll()
|
||||
})
|
||||
})
|
||||
uni.$on('updateMsgNum', id => {
|
||||
this.updateMsgNum(id)
|
||||
})
|
||||
},
|
||||
onUnload() {
|
||||
uni.$off('updateList')
|
||||
uni.$off('updateMsgNum')
|
||||
},
|
||||
methods: {
|
||||
handleRelocation(data) {
|
||||
let {
|
||||
index,
|
||||
action,
|
||||
btn,
|
||||
item
|
||||
} = data
|
||||
this.list.splice(index, 1)
|
||||
relocation(item.id).then(res => {
|
||||
this.init({
|
||||
...this.upOption.page
|
||||
})
|
||||
})
|
||||
},
|
||||
upCallback(page) {
|
||||
this.init(page)
|
||||
},
|
||||
init(page) {
|
||||
let query = {
|
||||
currentPage: page.num,
|
||||
pageSize: page.size,
|
||||
keyword: this.keyword
|
||||
}
|
||||
getIMReply(query).then(res => {
|
||||
this.mescroll.endSuccess(res.data.list.length, false);
|
||||
this.list = res.data.list || [];
|
||||
this.swipeAction = true
|
||||
uni.hideLoading()
|
||||
}).catch(() => {
|
||||
this.mescroll && this.mescroll.endErr();
|
||||
})
|
||||
},
|
||||
search() {
|
||||
this.searchTimer && clearTimeout(this.searchTimer)
|
||||
this.searchTimer = setTimeout(() => {
|
||||
this.list = [];
|
||||
this.mescroll.resetUpScroll();
|
||||
}, 300)
|
||||
},
|
||||
updateMsgNum(id) {
|
||||
const chatStore = useChatStore()
|
||||
const len = this.list.length
|
||||
for (let i = 0; i < len; i++) {
|
||||
if (id === this.list[i].id) {
|
||||
const num = this.list[i].unreadMessage
|
||||
chatStore.reduceBadgeNum(num)
|
||||
this.list[i].unreadMessage = 0
|
||||
break
|
||||
}
|
||||
}
|
||||
},
|
||||
getMsgText(text, type) {
|
||||
if (type === 'voice') return '[语音]';
|
||||
if (type === 'image') return '[图片]';
|
||||
return text;
|
||||
},
|
||||
toIm(item) {
|
||||
const chatStore = useChatStore()
|
||||
const name = item.realName + '/' + item.account
|
||||
if (item.unreadMessage) {
|
||||
chatStore.reduceBadgeNum(item.unreadMessage)
|
||||
item.unreadMessage = 0
|
||||
}
|
||||
this.$nextTick(() => {
|
||||
this.$refs.swipeItem.closeSwipe()
|
||||
})
|
||||
uni.navigateTo({
|
||||
url: '/pages/message/im/index?name=' + item.realName + '/' + item.account + '&formUserId=' +
|
||||
item.id + '&headIcon=' + item.headIcon
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
page {
|
||||
background-color: #f0f2f6;
|
||||
}
|
||||
|
||||
.message-v {
|
||||
.search-box {
|
||||
height: 120rpx;
|
||||
padding: 0rpx 20rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
background-color: #fff;
|
||||
margin-bottom: 16rpx;
|
||||
}
|
||||
|
||||
.replyList {
|
||||
padding: 0 20rpx;
|
||||
background-color: #fff;
|
||||
|
||||
.againColor {
|
||||
color: #909399;
|
||||
}
|
||||
}
|
||||
|
||||
.reply-item {
|
||||
height: 142rpx;
|
||||
background-color: #fff;
|
||||
padding: 0 20rpx;
|
||||
|
||||
.reply-item-img-sysMsg {
|
||||
width: 96rpx;
|
||||
height: 96rpx;
|
||||
border-radius: 16rpx;
|
||||
overflow: hidden;
|
||||
margin-right: 16rpx;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.reply-item-img {
|
||||
width: 96rpx;
|
||||
height: 96rpx;
|
||||
border-radius: 50%;
|
||||
overflow: hidden;
|
||||
margin-right: 16rpx;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.reply-item-icon-color {
|
||||
background-color: #2bd34f;
|
||||
}
|
||||
|
||||
.reply-item-icon-color2 {
|
||||
background-color: #3B87F7;
|
||||
}
|
||||
|
||||
.reply-item-icon {
|
||||
|
||||
.icon-ym {
|
||||
color: #fff;
|
||||
font-size: 50rpx;
|
||||
}
|
||||
}
|
||||
|
||||
.reply-item-txt {
|
||||
.reply-item-cell {
|
||||
height: 40rpx;
|
||||
color: #C6C6C6;
|
||||
font-size: 24rpx;
|
||||
|
||||
&.reply-item-title {
|
||||
height: 44rpx;
|
||||
margin-bottom: 4px;
|
||||
|
||||
.title {
|
||||
font-size: 28rpx;
|
||||
color: #303133;
|
||||
}
|
||||
}
|
||||
|
||||
.reply-item-txt-msg {
|
||||
width: 480rpx;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.search-box_sticky {
|
||||
padding: 0 32rpx;
|
||||
}
|
||||
|
||||
.message-list .uni-swipe {
|
||||
margin-bottom: 0px !important;
|
||||
border-radius: 0px !important;
|
||||
}
|
||||
|
||||
.message-list {
|
||||
.message-list-box {
|
||||
margin: 0px !important;
|
||||
|
||||
::v-deep .u-swipe-action {
|
||||
border-radius: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
988
pages/message/im/emoji.js
Normal file
@@ -0,0 +1,988 @@
|
||||
const emojiTree = [
|
||||
[{
|
||||
"url": "100.gif",
|
||||
"alt": "[微笑]"
|
||||
},
|
||||
{
|
||||
"url": "101.gif",
|
||||
"alt": "[伤心]"
|
||||
},
|
||||
{
|
||||
"url": "102.gif",
|
||||
"alt": "[美女]"
|
||||
},
|
||||
{
|
||||
"url": "103.gif",
|
||||
"alt": "[发呆]"
|
||||
},
|
||||
{
|
||||
"url": "104.gif",
|
||||
"alt": "[墨镜]"
|
||||
},
|
||||
{
|
||||
"url": "105.gif",
|
||||
"alt": "[哭]"
|
||||
},
|
||||
{
|
||||
"url": "106.gif",
|
||||
"alt": "[羞]"
|
||||
},
|
||||
{
|
||||
"url": "107.gif",
|
||||
"alt": "[哑]"
|
||||
},
|
||||
{
|
||||
"url": "108.gif",
|
||||
"alt": "[睡]"
|
||||
},
|
||||
{
|
||||
"url": "109.gif",
|
||||
"alt": "[大哭]"
|
||||
},
|
||||
{
|
||||
"url": "110.gif",
|
||||
"alt": "[囧]"
|
||||
},
|
||||
{
|
||||
"url": "111.gif",
|
||||
"alt": "[怒]"
|
||||
},
|
||||
{
|
||||
"url": "112.gif",
|
||||
"alt": "[调皮]"
|
||||
},
|
||||
{
|
||||
"url": "113.gif",
|
||||
"alt": "[呲牙]"
|
||||
},
|
||||
{
|
||||
"url": "114.gif",
|
||||
"alt": "[惊讶]"
|
||||
},
|
||||
{
|
||||
"url": "115.gif",
|
||||
"alt": "[难过]"
|
||||
},
|
||||
{
|
||||
"url": "116.gif",
|
||||
"alt": "[酷]"
|
||||
},
|
||||
{
|
||||
"url": "117.gif",
|
||||
"alt": "[汗]"
|
||||
},
|
||||
{
|
||||
"url": "118.gif",
|
||||
"alt": "[抓狂]"
|
||||
},
|
||||
{
|
||||
"url": "119.gif",
|
||||
"alt": "[吐]"
|
||||
},
|
||||
{
|
||||
"url": "120.gif",
|
||||
"alt": "[笑]"
|
||||
},
|
||||
{
|
||||
"url": "121.gif",
|
||||
"alt": "[快乐]"
|
||||
},
|
||||
{
|
||||
"url": "122.gif",
|
||||
"alt": "[疑惑]"
|
||||
},
|
||||
{
|
||||
"url": "123.gif",
|
||||
"alt": "[傲]"
|
||||
}
|
||||
],
|
||||
[{
|
||||
"url": "124.gif",
|
||||
"alt": "[饿]"
|
||||
},
|
||||
{
|
||||
"url": "125.gif",
|
||||
"alt": "[累]"
|
||||
},
|
||||
{
|
||||
"url": "126.gif",
|
||||
"alt": "[惊恐]"
|
||||
},
|
||||
{
|
||||
"url": "127.gif",
|
||||
"alt": "[汗1]"
|
||||
},
|
||||
{
|
||||
"url": "128.gif",
|
||||
"alt": "[高兴]"
|
||||
},
|
||||
{
|
||||
"url": "129.gif",
|
||||
"alt": "[闲]"
|
||||
},
|
||||
{
|
||||
"url": "130.gif",
|
||||
"alt": "[努力]"
|
||||
},
|
||||
{
|
||||
"url": "131.gif",
|
||||
"alt": "[骂]"
|
||||
},
|
||||
{
|
||||
"url": "132.gif",
|
||||
"alt": "[疑问]"
|
||||
},
|
||||
{
|
||||
"url": "133.gif",
|
||||
"alt": "[秘密]"
|
||||
},
|
||||
{
|
||||
"url": "134.gif",
|
||||
"alt": "[乱]"
|
||||
},
|
||||
{
|
||||
"url": "135.gif",
|
||||
"alt": "[疯]"
|
||||
},
|
||||
{
|
||||
"url": "136.gif",
|
||||
"alt": "[哀]"
|
||||
},
|
||||
{
|
||||
"url": "137.gif",
|
||||
"alt": "[鬼]"
|
||||
},
|
||||
{
|
||||
"url": "138.gif",
|
||||
"alt": "[打击]"
|
||||
},
|
||||
{
|
||||
"url": "139.gif",
|
||||
"alt": "[bye]"
|
||||
},
|
||||
{
|
||||
"url": "140.gif",
|
||||
"alt": "[擦汗]"
|
||||
},
|
||||
{
|
||||
"url": "141.gif",
|
||||
"alt": "[抠]"
|
||||
},
|
||||
{
|
||||
"url": "142.gif",
|
||||
"alt": "[鼓掌]"
|
||||
},
|
||||
{
|
||||
"url": "143.gif",
|
||||
"alt": "[糟糕]"
|
||||
},
|
||||
{
|
||||
"url": "144.gif",
|
||||
"alt": "[恶搞]"
|
||||
},
|
||||
{
|
||||
"url": "145.gif",
|
||||
"alt": "[左哼哼]"
|
||||
},
|
||||
{
|
||||
"url": "146.gif",
|
||||
"alt": "[右哼哼]"
|
||||
},
|
||||
{
|
||||
"url": "147.gif",
|
||||
"alt": "[哈欠]"
|
||||
}
|
||||
],
|
||||
[{
|
||||
"url": "148.gif",
|
||||
"alt": "[看]"
|
||||
},
|
||||
{
|
||||
"url": "149.gif",
|
||||
"alt": "[委屈]"
|
||||
},
|
||||
{
|
||||
"url": "150.gif",
|
||||
"alt": "[难过1]"
|
||||
},
|
||||
{
|
||||
"url": "151.gif",
|
||||
"alt": "[坏]"
|
||||
},
|
||||
{
|
||||
"url": "152.gif",
|
||||
"alt": "[亲]"
|
||||
},
|
||||
{
|
||||
"url": "153.gif",
|
||||
"alt": "[吓]"
|
||||
},
|
||||
{
|
||||
"url": "154.gif",
|
||||
"alt": "[可怜]"
|
||||
},
|
||||
{
|
||||
"url": "155.gif",
|
||||
"alt": "[刀]"
|
||||
},
|
||||
{
|
||||
"url": "156.gif",
|
||||
"alt": "[水果]"
|
||||
},
|
||||
{
|
||||
"url": "157.gif",
|
||||
"alt": "[酒]"
|
||||
},
|
||||
{
|
||||
"url": "158.gif",
|
||||
"alt": "[篮球]"
|
||||
},
|
||||
{
|
||||
"url": "159.gif",
|
||||
"alt": "[乒乓]"
|
||||
},
|
||||
{
|
||||
"url": "160.gif",
|
||||
"alt": "[咖啡]"
|
||||
},
|
||||
{
|
||||
"url": "161.gif",
|
||||
"alt": "[美食]"
|
||||
},
|
||||
{
|
||||
"url": "162.gif",
|
||||
"alt": "[动物]"
|
||||
},
|
||||
{
|
||||
"url": "163.gif",
|
||||
"alt": "[鲜花]"
|
||||
},
|
||||
{
|
||||
"url": "164.gif",
|
||||
"alt": "[枯]"
|
||||
},
|
||||
{
|
||||
"url": "165.gif",
|
||||
"alt": "[唇]"
|
||||
},
|
||||
{
|
||||
"url": "166.gif",
|
||||
"alt": "[爱]"
|
||||
},
|
||||
{
|
||||
"url": "167.gif",
|
||||
"alt": "[分手]"
|
||||
},
|
||||
{
|
||||
"url": "168.gif",
|
||||
"alt": "[生日]"
|
||||
},
|
||||
{
|
||||
"url": "169.gif",
|
||||
"alt": "[电]"
|
||||
},
|
||||
{
|
||||
"url": "170.gif",
|
||||
"alt": "[炸弹]"
|
||||
},
|
||||
{
|
||||
"url": "171.gif",
|
||||
"alt": "[刀子]"
|
||||
}
|
||||
],
|
||||
[{
|
||||
"url": "172.gif",
|
||||
"alt": "[足球]"
|
||||
},
|
||||
{
|
||||
"url": "173.gif",
|
||||
"alt": "[瓢虫]"
|
||||
},
|
||||
{
|
||||
"url": "174.gif",
|
||||
"alt": "[翔]"
|
||||
},
|
||||
{
|
||||
"url": "175.gif",
|
||||
"alt": "[月亮]"
|
||||
},
|
||||
{
|
||||
"url": "176.gif",
|
||||
"alt": "[太阳]"
|
||||
},
|
||||
{
|
||||
"url": "177.gif",
|
||||
"alt": "[礼物]"
|
||||
},
|
||||
{
|
||||
"url": "178.gif",
|
||||
"alt": "[抱抱]"
|
||||
},
|
||||
{
|
||||
"url": "179.gif",
|
||||
"alt": "[拇指]"
|
||||
},
|
||||
{
|
||||
"url": "180.gif",
|
||||
"alt": "[贬低]"
|
||||
},
|
||||
{
|
||||
"url": "181.gif",
|
||||
"alt": "[握手]"
|
||||
},
|
||||
{
|
||||
"url": "182.gif",
|
||||
"alt": "[剪刀手]"
|
||||
},
|
||||
{
|
||||
"url": "183.gif",
|
||||
"alt": "[抱拳]"
|
||||
},
|
||||
{
|
||||
"url": "184.gif",
|
||||
"alt": "[勾引]"
|
||||
},
|
||||
{
|
||||
"url": "185.gif",
|
||||
"alt": "[拳头]"
|
||||
},
|
||||
{
|
||||
"url": "186.gif",
|
||||
"alt": "[小拇指]"
|
||||
},
|
||||
{
|
||||
"url": "187.gif",
|
||||
"alt": "[拇指八]"
|
||||
},
|
||||
{
|
||||
"url": "188.gif",
|
||||
"alt": "[食指]"
|
||||
},
|
||||
{
|
||||
"url": "189.gif",
|
||||
"alt": "[ok]"
|
||||
},
|
||||
{
|
||||
"url": "190.gif",
|
||||
"alt": "[情侣]"
|
||||
},
|
||||
{
|
||||
"url": "191.gif",
|
||||
"alt": "[爱心]"
|
||||
},
|
||||
{
|
||||
"url": "192.gif",
|
||||
"alt": "[蹦哒]"
|
||||
},
|
||||
{
|
||||
"url": "193.gif",
|
||||
"alt": "[颤抖]"
|
||||
},
|
||||
{
|
||||
"url": "194.gif",
|
||||
"alt": "[怄气]"
|
||||
},
|
||||
{
|
||||
"url": "195.gif",
|
||||
"alt": "[跳舞]"
|
||||
}
|
||||
],
|
||||
[{
|
||||
"url": "196.gif",
|
||||
"alt": "[拜]"
|
||||
},
|
||||
{
|
||||
"url": "197.gif",
|
||||
"alt": "[背着]"
|
||||
},
|
||||
{
|
||||
"url": "198.gif",
|
||||
"alt": "[伸手]"
|
||||
},
|
||||
{
|
||||
"url": "199.gif",
|
||||
"alt": "[耍帅]"
|
||||
},
|
||||
{
|
||||
"url": "200.png",
|
||||
"alt": "[微笑1]"
|
||||
},
|
||||
{
|
||||
"url": "201.png",
|
||||
"alt": "[生病]"
|
||||
},
|
||||
{
|
||||
"url": "202.png",
|
||||
"alt": "[哭泣]"
|
||||
},
|
||||
{
|
||||
"url": "203.png",
|
||||
"alt": "[吐舌]"
|
||||
},
|
||||
{
|
||||
"url": "204.png",
|
||||
"alt": "[迷糊]"
|
||||
},
|
||||
{
|
||||
"url": "205.png",
|
||||
"alt": "[瞪眼]"
|
||||
},
|
||||
{
|
||||
"url": "206.png",
|
||||
"alt": "[恐怖]"
|
||||
},
|
||||
{
|
||||
"url": "207.png",
|
||||
"alt": "[忧愁]"
|
||||
},
|
||||
{
|
||||
"url": "208.png",
|
||||
"alt": "[眨眉]"
|
||||
},
|
||||
{
|
||||
"url": "209.png",
|
||||
"alt": "[闭眼]"
|
||||
},
|
||||
{
|
||||
"url": "210.png",
|
||||
"alt": "[鄙视]"
|
||||
},
|
||||
{
|
||||
"url": "211.png",
|
||||
"alt": "[阴暗]"
|
||||
},
|
||||
{
|
||||
"url": "212.png",
|
||||
"alt": "[小鬼]"
|
||||
},
|
||||
{
|
||||
"url": "213.png",
|
||||
"alt": "[爱心1]"
|
||||
},
|
||||
{
|
||||
"url": "214.png",
|
||||
"alt": "[拜佛]"
|
||||
},
|
||||
{
|
||||
"url": "215.png",
|
||||
"alt": "[力量]"
|
||||
},
|
||||
{
|
||||
"url": "216.png",
|
||||
"alt": "[金钱]"
|
||||
},
|
||||
{
|
||||
"url": "217.png",
|
||||
"alt": "[蛋糕]"
|
||||
},
|
||||
{
|
||||
"url": "218.png",
|
||||
"alt": "[彩带]"
|
||||
},
|
||||
{
|
||||
"url": "219.png",
|
||||
"alt": "[礼物1]"
|
||||
}
|
||||
]
|
||||
]
|
||||
const emojiList = [{
|
||||
"url": "100.gif",
|
||||
"alt": "[微笑]"
|
||||
},
|
||||
{
|
||||
"url": "101.gif",
|
||||
"alt": "[伤心]"
|
||||
},
|
||||
{
|
||||
"url": "102.gif",
|
||||
"alt": "[美女]"
|
||||
},
|
||||
{
|
||||
"url": "103.gif",
|
||||
"alt": "[发呆]"
|
||||
},
|
||||
{
|
||||
"url": "104.gif",
|
||||
"alt": "[墨镜]"
|
||||
},
|
||||
{
|
||||
"url": "105.gif",
|
||||
"alt": "[哭]"
|
||||
},
|
||||
{
|
||||
"url": "106.gif",
|
||||
"alt": "[羞]"
|
||||
},
|
||||
{
|
||||
"url": "107.gif",
|
||||
"alt": "[哑]"
|
||||
},
|
||||
{
|
||||
"url": "108.gif",
|
||||
"alt": "[睡]"
|
||||
},
|
||||
{
|
||||
"url": "109.gif",
|
||||
"alt": "[大哭]"
|
||||
},
|
||||
{
|
||||
"url": "110.gif",
|
||||
"alt": "[囧]"
|
||||
},
|
||||
{
|
||||
"url": "111.gif",
|
||||
"alt": "[怒]"
|
||||
},
|
||||
{
|
||||
"url": "112.gif",
|
||||
"alt": "[调皮]"
|
||||
},
|
||||
{
|
||||
"url": "113.gif",
|
||||
"alt": "[呲牙]"
|
||||
},
|
||||
{
|
||||
"url": "114.gif",
|
||||
"alt": "[惊讶]"
|
||||
},
|
||||
{
|
||||
"url": "115.gif",
|
||||
"alt": "[难过]"
|
||||
},
|
||||
{
|
||||
"url": "116.gif",
|
||||
"alt": "[酷]"
|
||||
},
|
||||
{
|
||||
"url": "117.gif",
|
||||
"alt": "[汗]"
|
||||
},
|
||||
{
|
||||
"url": "118.gif",
|
||||
"alt": "[抓狂]"
|
||||
},
|
||||
{
|
||||
"url": "119.gif",
|
||||
"alt": "[吐]"
|
||||
},
|
||||
{
|
||||
"url": "120.gif",
|
||||
"alt": "[笑]"
|
||||
},
|
||||
{
|
||||
"url": "121.gif",
|
||||
"alt": "[快乐]"
|
||||
},
|
||||
{
|
||||
"url": "122.gif",
|
||||
"alt": "[疑惑]"
|
||||
},
|
||||
{
|
||||
"url": "123.gif",
|
||||
"alt": "[傲]"
|
||||
},
|
||||
{
|
||||
"url": "124.gif",
|
||||
"alt": "[饿]"
|
||||
},
|
||||
{
|
||||
"url": "125.gif",
|
||||
"alt": "[累]"
|
||||
},
|
||||
{
|
||||
"url": "126.gif",
|
||||
"alt": "[惊恐]"
|
||||
},
|
||||
{
|
||||
"url": "127.gif",
|
||||
"alt": "[汗1]"
|
||||
},
|
||||
{
|
||||
"url": "128.gif",
|
||||
"alt": "[高兴]"
|
||||
},
|
||||
{
|
||||
"url": "129.gif",
|
||||
"alt": "[闲]"
|
||||
},
|
||||
{
|
||||
"url": "130.gif",
|
||||
"alt": "[努力]"
|
||||
},
|
||||
{
|
||||
"url": "131.gif",
|
||||
"alt": "[骂]"
|
||||
},
|
||||
{
|
||||
"url": "132.gif",
|
||||
"alt": "[疑问]"
|
||||
},
|
||||
{
|
||||
"url": "133.gif",
|
||||
"alt": "[秘密]"
|
||||
},
|
||||
{
|
||||
"url": "134.gif",
|
||||
"alt": "[乱]"
|
||||
},
|
||||
{
|
||||
"url": "135.gif",
|
||||
"alt": "[疯]"
|
||||
},
|
||||
{
|
||||
"url": "136.gif",
|
||||
"alt": "[哀]"
|
||||
},
|
||||
{
|
||||
"url": "137.gif",
|
||||
"alt": "[鬼]"
|
||||
},
|
||||
{
|
||||
"url": "138.gif",
|
||||
"alt": "[打击]"
|
||||
},
|
||||
{
|
||||
"url": "139.gif",
|
||||
"alt": "[bye]"
|
||||
},
|
||||
{
|
||||
"url": "140.gif",
|
||||
"alt": "[擦汗]"
|
||||
},
|
||||
{
|
||||
"url": "141.gif",
|
||||
"alt": "[抠]"
|
||||
},
|
||||
{
|
||||
"url": "142.gif",
|
||||
"alt": "[鼓掌]"
|
||||
},
|
||||
{
|
||||
"url": "143.gif",
|
||||
"alt": "[糟糕]"
|
||||
},
|
||||
{
|
||||
"url": "144.gif",
|
||||
"alt": "[恶搞]"
|
||||
},
|
||||
{
|
||||
"url": "145.gif",
|
||||
"alt": "[左哼哼]"
|
||||
},
|
||||
{
|
||||
"url": "146.gif",
|
||||
"alt": "[右哼哼]"
|
||||
},
|
||||
{
|
||||
"url": "147.gif",
|
||||
"alt": "[哈欠]"
|
||||
},
|
||||
{
|
||||
"url": "148.gif",
|
||||
"alt": "[看]"
|
||||
},
|
||||
{
|
||||
"url": "149.gif",
|
||||
"alt": "[委屈]"
|
||||
},
|
||||
{
|
||||
"url": "150.gif",
|
||||
"alt": "[难过1]"
|
||||
},
|
||||
{
|
||||
"url": "151.gif",
|
||||
"alt": "[坏]"
|
||||
},
|
||||
{
|
||||
"url": "152.gif",
|
||||
"alt": "[亲]"
|
||||
},
|
||||
{
|
||||
"url": "153.gif",
|
||||
"alt": "[吓]"
|
||||
},
|
||||
{
|
||||
"url": "154.gif",
|
||||
"alt": "[可怜]"
|
||||
},
|
||||
{
|
||||
"url": "155.gif",
|
||||
"alt": "[刀]"
|
||||
},
|
||||
{
|
||||
"url": "156.gif",
|
||||
"alt": "[水果]"
|
||||
},
|
||||
{
|
||||
"url": "157.gif",
|
||||
"alt": "[酒]"
|
||||
},
|
||||
{
|
||||
"url": "158.gif",
|
||||
"alt": "[篮球]"
|
||||
},
|
||||
{
|
||||
"url": "159.gif",
|
||||
"alt": "[乒乓]"
|
||||
},
|
||||
{
|
||||
"url": "160.gif",
|
||||
"alt": "[咖啡]"
|
||||
},
|
||||
{
|
||||
"url": "161.gif",
|
||||
"alt": "[美食]"
|
||||
},
|
||||
{
|
||||
"url": "162.gif",
|
||||
"alt": "[动物]"
|
||||
},
|
||||
{
|
||||
"url": "163.gif",
|
||||
"alt": "[鲜花]"
|
||||
},
|
||||
{
|
||||
"url": "164.gif",
|
||||
"alt": "[枯]"
|
||||
},
|
||||
{
|
||||
"url": "165.gif",
|
||||
"alt": "[唇]"
|
||||
},
|
||||
{
|
||||
"url": "166.gif",
|
||||
"alt": "[爱]"
|
||||
},
|
||||
{
|
||||
"url": "167.gif",
|
||||
"alt": "[分手]"
|
||||
},
|
||||
{
|
||||
"url": "168.gif",
|
||||
"alt": "[生日]"
|
||||
},
|
||||
{
|
||||
"url": "169.gif",
|
||||
"alt": "[电]"
|
||||
},
|
||||
{
|
||||
"url": "170.gif",
|
||||
"alt": "[炸弹]"
|
||||
},
|
||||
{
|
||||
"url": "171.gif",
|
||||
"alt": "[刀子]"
|
||||
},
|
||||
{
|
||||
"url": "172.gif",
|
||||
"alt": "[足球]"
|
||||
},
|
||||
{
|
||||
"url": "173.gif",
|
||||
"alt": "[瓢虫]"
|
||||
},
|
||||
{
|
||||
"url": "174.gif",
|
||||
"alt": "[翔]"
|
||||
},
|
||||
{
|
||||
"url": "175.gif",
|
||||
"alt": "[月亮]"
|
||||
},
|
||||
{
|
||||
"url": "176.gif",
|
||||
"alt": "[太阳]"
|
||||
},
|
||||
{
|
||||
"url": "177.gif",
|
||||
"alt": "[礼物]"
|
||||
},
|
||||
{
|
||||
"url": "178.gif",
|
||||
"alt": "[抱抱]"
|
||||
},
|
||||
{
|
||||
"url": "179.gif",
|
||||
"alt": "[拇指]"
|
||||
},
|
||||
{
|
||||
"url": "180.gif",
|
||||
"alt": "[贬低]"
|
||||
},
|
||||
{
|
||||
"url": "181.gif",
|
||||
"alt": "[握手]"
|
||||
},
|
||||
{
|
||||
"url": "182.gif",
|
||||
"alt": "[剪刀手]"
|
||||
},
|
||||
{
|
||||
"url": "183.gif",
|
||||
"alt": "[抱拳]"
|
||||
},
|
||||
{
|
||||
"url": "184.gif",
|
||||
"alt": "[勾引]"
|
||||
},
|
||||
{
|
||||
"url": "185.gif",
|
||||
"alt": "[拳头]"
|
||||
},
|
||||
{
|
||||
"url": "186.gif",
|
||||
"alt": "[小拇指]"
|
||||
},
|
||||
{
|
||||
"url": "187.gif",
|
||||
"alt": "[拇指八]"
|
||||
},
|
||||
{
|
||||
"url": "188.gif",
|
||||
"alt": "[食指]"
|
||||
},
|
||||
{
|
||||
"url": "189.gif",
|
||||
"alt": "[ok]"
|
||||
},
|
||||
{
|
||||
"url": "190.gif",
|
||||
"alt": "[情侣]"
|
||||
},
|
||||
{
|
||||
"url": "191.gif",
|
||||
"alt": "[爱心]"
|
||||
},
|
||||
{
|
||||
"url": "192.gif",
|
||||
"alt": "[蹦哒]"
|
||||
},
|
||||
{
|
||||
"url": "193.gif",
|
||||
"alt": "[颤抖]"
|
||||
},
|
||||
{
|
||||
"url": "194.gif",
|
||||
"alt": "[怄气]"
|
||||
},
|
||||
{
|
||||
"url": "195.gif",
|
||||
"alt": "[跳舞]"
|
||||
},
|
||||
{
|
||||
"url": "196.gif",
|
||||
"alt": "[拜]"
|
||||
},
|
||||
{
|
||||
"url": "197.gif",
|
||||
"alt": "[背着]"
|
||||
},
|
||||
{
|
||||
"url": "198.gif",
|
||||
"alt": "[伸手]"
|
||||
},
|
||||
{
|
||||
"url": "199.gif",
|
||||
"alt": "[耍帅]"
|
||||
},
|
||||
{
|
||||
"url": "200.png",
|
||||
"alt": "[微笑1]"
|
||||
},
|
||||
{
|
||||
"url": "201.png",
|
||||
"alt": "[生病]"
|
||||
},
|
||||
{
|
||||
"url": "202.png",
|
||||
"alt": "[哭泣]"
|
||||
},
|
||||
{
|
||||
"url": "203.png",
|
||||
"alt": "[吐舌]"
|
||||
},
|
||||
{
|
||||
"url": "204.png",
|
||||
"alt": "[迷糊]"
|
||||
},
|
||||
{
|
||||
"url": "205.png",
|
||||
"alt": "[瞪眼]"
|
||||
},
|
||||
{
|
||||
"url": "206.png",
|
||||
"alt": "[恐怖]"
|
||||
},
|
||||
{
|
||||
"url": "207.png",
|
||||
"alt": "[忧愁]"
|
||||
},
|
||||
{
|
||||
"url": "208.png",
|
||||
"alt": "[眨眉]"
|
||||
},
|
||||
{
|
||||
"url": "209.png",
|
||||
"alt": "[闭眼]"
|
||||
},
|
||||
{
|
||||
"url": "210.png",
|
||||
"alt": "[鄙视]"
|
||||
},
|
||||
{
|
||||
"url": "211.png",
|
||||
"alt": "[阴暗]"
|
||||
},
|
||||
{
|
||||
"url": "212.png",
|
||||
"alt": "[小鬼]"
|
||||
},
|
||||
{
|
||||
"url": "213.png",
|
||||
"alt": "[爱心1]"
|
||||
},
|
||||
{
|
||||
"url": "214.png",
|
||||
"alt": "[拜佛]"
|
||||
},
|
||||
{
|
||||
"url": "215.png",
|
||||
"alt": "[力量]"
|
||||
},
|
||||
{
|
||||
"url": "216.png",
|
||||
"alt": "[金钱]"
|
||||
},
|
||||
{
|
||||
"url": "217.png",
|
||||
"alt": "[蛋糕]"
|
||||
},
|
||||
{
|
||||
"url": "218.png",
|
||||
"alt": "[彩带]"
|
||||
},
|
||||
{
|
||||
"url": "219.png",
|
||||
"alt": "[礼物1]"
|
||||
}
|
||||
]
|
||||
|
||||
const req = import.meta.glob('../static/emoji/*.*', {
|
||||
eager: true
|
||||
})
|
||||
|
||||
const imagesMap = {}
|
||||
|
||||
// 循环所有图片,将图片名设置成键,值为导入该图片的地址
|
||||
for (const key in req) {
|
||||
// let name = key.split('/').slice(-1)[0].split('.')[0]
|
||||
let name = key.split('/').slice(-1)[0].replace('.', '')
|
||||
// 抛出图片大对象后,文件页面直接引入后将图片的具体名称作为属性就能导入该图片
|
||||
imagesMap[name] = req[key].default
|
||||
}
|
||||
|
||||
export {
|
||||
emojiList,
|
||||
emojiTree,
|
||||
imagesMap
|
||||
}
|
||||
606
pages/message/im/index.scss
Normal file
@@ -0,0 +1,606 @@
|
||||
@font-face {
|
||||
font-family: "HMfont-home";
|
||||
src: url('data:application/x-font-woff2;charset=utf-8;base64,d09GMgABAAAAAAn8AAsAAAAAE1wAAAmvAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHEIGVgCFDAqWYJI9ATYCJANACyIABCAFhFUHgV8bThBRlFFWNdkXBXbDsSFQq221McNWrxUbYqGhiTju98MTeXqNh/9fo90388cEMe0bwSOJRIjavZIgESqnE5J5JqQVDZH/XdNfoHSAjqKqRsA+Tf/Ruya33E/bkdHsJtycY2XWAGbM5oenzf173A3lHrEilsmMbu74Y5VmYtxpgza9DMxkWL0gfjGbGRE54AL2f2ut3h2u8Q7RaZRCjDPLIv8cfAUR30MtEUWbSReVJkk0RB4lWWkNg7WVA1sBKmIUdr0uzibQOmxA4vrWwQXkJUweKHPfdwXkA+FSik2o1aVizyTegEKdvWINwGv59bEGY9GeTJFjW95pswIrzz3LYi//0O4JEaDrY3DZjxwXgUR8V3IfIeXARaloVRXT3mK/tsi3LubcJfese8l96Xbd1l1ve2z7eJp5lv3zB7URSdJNYd3Dfm7UUxxkGu0sLFcbVEa5pP3D6/QmokQw3OGzfJp/2kBkLJYQDYuziJbFJUSweIkoWXQRNYuEGFi0BLzFOhAjS4+InKUPRGI5I2a+kg7VSWUGoXoos2BNmGIWexwFroD8IUD6C1A9lYp8F3ClwsFgcgPdNpN08v1czkEOJ4aeieaC3QyVfb9PX2kbn9/0CwTeNAm79H1Kc2x3i9C7LcEZtMSLfE6T4aM+YWOm06dZ5cm9I+xoYw+rqGlScKKlHytu9h6Dw0E5nXK7nbTZknT1jFldR9cuzNMz9Srf7FydqpYW5mRr6Dq1OC9HqzYzoiw1cjohV2tX1Ji1K9bSdVkEbaxS1xQwpmpVpUFheyyzPyGdbXKHexkByib+vtgeK1X75xKqWl+grUNIbRZDXT31tBMiPZAyF0KmniCQhSgACkh5+gIxtvTS/si+VjbAuY6SMdCzbqInzwkjk5ENzMCkNv+ghQQ0qSSAUGmAMQoBozoAIrUe6qpzM+tma1T1jDgvVzdBWcIcLT170njGQU3cCpnUTSdkHH3ltwPHpKotTIP6HH12Lvd4czCWgbJYhY1U5ddlTCICSs1is0in8tXExk7VVRuMQhIQGgOtFcolPmMkIqDVduTGEOn1jI4gFERmSUsv3rGmoKUEQLITLUyzqpFukq8T6U+omVQsT8XHxsnipPEyBAlKNmkNMlMJgOT5Tpsoo2RGP3lOTQyk5GRBgJKw2WQsarWzSa1aLF/+UBk2PkA3wEkBM/RwOLJ0ORWiVCR3YYAAFyIlAdaNqEnmh0sTqOsAq97R85Jt+HGHrNKWgDHmxOPxumKmRGzudayPtogu9D2Zx688C3D6XJSgpgF6MJbomdtyOYBgcXOGSgMAPXqy+F11pMYHlFLCkkKM0S1T+U5SN0Ynh39SxcxmTPNHrTFIuieyxYgZXSDUAPpLLT2ZciVvihOh05k+JIAjoL7HtNsVFc5Rl+1hgAAIlNqGX3GEK0llMm0nZUdmhQzymg3Q9j6yO4FQsmqtQbXmZ+z+sOynUrt3nmbeXu3MYW9f8y38128LpWAVeyLMz4cTORbEDPYKHU19Oyx0OF12GIhfEx+/RRIm2RzPeIPE2yYRM7HBWBx+GvANWXAlMYcmWriz1/Tt2bk+jq7CdOzMu5zsn3zZXwg2Gu14YCBuh3NggN0DI8BbJpCXZb2I4xh+kdAmbU0IA6HYquya81nqYSk87Xgi35ur4HnxZWEvnoLrzbOEjHmJiY2JjV6I8c4ynSEsJTKcHxuWYPRFFleV2Sbi0Dsk4XmDSToXTMnUnW/PW9J9W4UCgP+h0rTi9tiJd6qQgk2lPI/KKeybAPx+c7vZHdimbruzyCP9iZvd0VuBuIniuXirHQ8oG2IThFIUI8QOhjfNMg86GH4Bv4ixLlr4BDi2wDDwXTYYTgfnBJur1nAw2yGngw96JhQo+48cMWVE8kWwcA55ZuzwkSP/mpp9D6wFm2e1Bc8cPVraL2Ng7y6KfSNHqQfTYByYMmbT73WNmwZs6m8sBR54XCndTHwvu6v+8N+Jze9/jeGd8bpoHePtMv0/9U6e78bTtf+aly55P40cNtJ3PH3U6xQ9DkRNos+Chp2TpNwX4lZOwkTa4nOLPxpMLc8Sm0srSwD6Y1KW7ftPZ68x3DWS8d4cJbAKE6QJEfRrhAafMLV0RoCRLhKdBaJzNtzPD7dxLIgZ7Al4006exyHEYXMewjqApFokPRIu9FvLiPf96uWlpuZmRZKiH1i0OCNj1ar7zSDqYiRbCQsMrKUXZswxBkQEbCmv2RJgKK82+UcGbpk+0woVSxekQrYCzp4Hk30E3oHhAh+4fLcOPCfzOVu3cvKkHAWzNAVyjAyOQsrJix47n0OZpbTUDKdJp8CZs+BkAKfMnDkF+kJmmrcN4OSZs8CRuwZ+N76gampCxtj83XWO5X1GYc7hIypq+N32eTe6Wr/GfXW5GukBLnvJ1gEPhlmsuUHzg3Osp/vJCZ4flGsFf27fjV18spjdTfQUuVANcgldRA3hKhSUutCGgGhDaMo0tXMHwiUq3gG5entO2xmnECa3H53AjRpKFFYIK7qrHjMJ75sEC91BPlGc0TlZY9qlsdcuZaXy0D3hfz4cmLd2WzbK3Xhhdw7c2VLCxtxsFCMEo8bArEww9ruOrc5joK9g1xp85MghQ4wyuPV71+/tMVxAMmzA1lSt+WmbjFkwL/lV6az7APzZ5qvVmmy7b1bJGrTDhmRfMBYbWMZmNOu3bJdPlLL/5WOR2XZCTJpmU4mx8lv9Fg76T8NagO4vUacJ+n/Sr0b/LYb8+1z5QCb935a0m6WWYXzwh4DO2Sa9g2jEnJ6tYwTU5jp7N2RmaHkn/gjEb/fXpmpXbkpAGaAv7pnKAfdc6bg4GZx1L3QuQ8lVC3BvXbC8f2eHQEqkBuc9aO6h9849M3oPucrgAyQY/HEv7PYJJQy23Ft3/R+xczqmsHWDgrDCyzfcl1o5ehKxnUOr5Bm6NhTGR4u1rtDEvlZ8dGgklLeNCk3ZbeKaO0bkcMfoKt+6ng/DUPPI6AAlDXlE0dzwsKPadkjqKjDXGEgg4b2CK7vx65M0xSlPmNsOA58/g1xWSDDKeq/KV5AR89+zc6OGjKSKtxUqR4NtF47VuMZemcTBDQxGqzqqrXIMCnm2xkXq1QJIIkO8EpmROcOkIyevYmhUqurWBmgCe4U5WJFHiiLKqKKOJtrooo8hxphihl6g5bGv3MAXkfBvPaFbVq6ga4Uq+wWdEfo6NVTmr1oVkYoye2NvfCWLmYQx0sjozFSxszhZ4Ctjb7QtavLQDNa0L5HRZQYJYxrNLbJR4QhZvOV46Fm/lqB428nsrJSx/OwbEgYA') format('woff2');
|
||||
}
|
||||
|
||||
.icon {
|
||||
font-family: "HMfont-home" !important;
|
||||
font-size: 56rpx;
|
||||
font-style: normal;
|
||||
color: #333;
|
||||
|
||||
&.biaoqing:before {
|
||||
content: "\e797";
|
||||
}
|
||||
|
||||
&.jianpan:before {
|
||||
content: "\e7b2";
|
||||
}
|
||||
|
||||
&.yuyin:before {
|
||||
content: "\e805";
|
||||
}
|
||||
|
||||
&.tupian:before {
|
||||
content: "\e639";
|
||||
}
|
||||
|
||||
&.chehui:before {
|
||||
content: "\e904";
|
||||
}
|
||||
|
||||
&.luyin:before {
|
||||
content: "\e905";
|
||||
}
|
||||
|
||||
&.luyin2:before {
|
||||
content: "\e677";
|
||||
}
|
||||
|
||||
&.other-voice:before {
|
||||
content: "\e667";
|
||||
}
|
||||
|
||||
&.my-voice:before {
|
||||
content: "\e906";
|
||||
}
|
||||
|
||||
&.hongbao:before {
|
||||
content: "\e626";
|
||||
}
|
||||
|
||||
&.tupian2:before {
|
||||
content: "\e674";
|
||||
}
|
||||
|
||||
&.paizhao:before {
|
||||
content: "\e63e";
|
||||
}
|
||||
|
||||
&.add:before {
|
||||
content: "\e655";
|
||||
}
|
||||
|
||||
&.close:before {
|
||||
content: "\e607";
|
||||
}
|
||||
|
||||
&.to:before {
|
||||
content: "\e675";
|
||||
}
|
||||
}
|
||||
|
||||
page {
|
||||
background-color: #f0f2f6;
|
||||
}
|
||||
|
||||
.im-v {
|
||||
.notData-box {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
padding-top: 400rpx;
|
||||
|
||||
.notData-inner {
|
||||
width: 280rpx;
|
||||
height: 308rpx;
|
||||
align-items: center;
|
||||
|
||||
|
||||
.iconImg {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.notData-inner-text {
|
||||
padding: 30rpx 0;
|
||||
color: #909399;
|
||||
}
|
||||
}
|
||||
}
|
||||
.msg-end {
|
||||
padding: 40rpx 0;
|
||||
font-size: 28rpx;
|
||||
text-align: center;
|
||||
color: #999;
|
||||
}
|
||||
|
||||
.hidden {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
.popup-layer {
|
||||
&.showLayer {
|
||||
transform: translate3d(0, -42vw, 0);
|
||||
}
|
||||
|
||||
transition: all .15s linear;
|
||||
width: 100%;
|
||||
height: 42vw;
|
||||
padding: 20rpx 2%;
|
||||
background-color: #f2f2f2;
|
||||
position: fixed;
|
||||
z-index: 20;
|
||||
top: 100%;
|
||||
|
||||
.emoji-swiper {
|
||||
height: 40vw;
|
||||
|
||||
swiper-item {
|
||||
display: flex;
|
||||
align-content: flex-start;
|
||||
flex-wrap: wrap;
|
||||
|
||||
.emoji-item {
|
||||
width: 12vw;
|
||||
height: 12vw;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
|
||||
.emoji-item-img {
|
||||
width: 8.4vw;
|
||||
height: 8.4vw;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.more-layer {
|
||||
width: 100%;
|
||||
height: 42vw;
|
||||
|
||||
.list {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
|
||||
.box {
|
||||
width: 18vw;
|
||||
height: 18vw;
|
||||
border-radius: 20rpx;
|
||||
background-color: #fff;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
margin: 0 3vw 2vw 3vw;
|
||||
|
||||
.icon {
|
||||
font-size: 70rpx;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.input-box {
|
||||
width: 100%;
|
||||
box-sizing: border-box;
|
||||
min-height: 80rpx;
|
||||
padding: 24rpx 32rpx;
|
||||
background-color: #f2f2f2;
|
||||
display: flex;
|
||||
align-items: flex-end;
|
||||
position: fixed;
|
||||
z-index: 20;
|
||||
bottom: 0;
|
||||
|
||||
&.showLayer {
|
||||
transform: translate3d(0, -42vw, 0);
|
||||
}
|
||||
|
||||
transition: all .15s linear;
|
||||
|
||||
.input-box-icon {
|
||||
flex-shrink: 0;
|
||||
height: 56rpx;
|
||||
width: 56rpx;
|
||||
margin-bottom: 6rpx;
|
||||
margin-right: 16rpx;
|
||||
|
||||
&.add {
|
||||
margin-right: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.send-btn {
|
||||
flex-shrink: 0;
|
||||
width: 90rpx;
|
||||
margin-bottom: 6rpx;
|
||||
height: 56rpx;
|
||||
line-height: 56rpx;
|
||||
background: #339AFF;
|
||||
color: #fff;
|
||||
border-radius: 6rpx;
|
||||
font-size: 24rpx;
|
||||
text-align: center;
|
||||
margin-left: 16rpx;
|
||||
}
|
||||
|
||||
.voice-mode {
|
||||
flex: 1;
|
||||
height: 68rpx;
|
||||
border-radius: 16rpx;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
font-size: 28rpx;
|
||||
background-color: #fff;
|
||||
color: #555;
|
||||
margin-right: 16rpx;
|
||||
|
||||
&.recording {
|
||||
background-color: #e5e5e5;
|
||||
}
|
||||
}
|
||||
|
||||
.text-mode {
|
||||
flex: 1;
|
||||
min-height: 68rpx;
|
||||
display: flex;
|
||||
background-color: #fff;
|
||||
border-radius: 16rpx;
|
||||
margin-right: 16rpx;
|
||||
|
||||
.input-area {
|
||||
width: 100%;
|
||||
padding: 16rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
max-height: 100rpx;
|
||||
overflow-y: scroll;
|
||||
|
||||
textarea {
|
||||
width: 100%;
|
||||
font-size: 28rpx;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.record {
|
||||
width: 40vw;
|
||||
height: 40vw;
|
||||
position: fixed;
|
||||
top: 55%;
|
||||
left: 30%;
|
||||
background-color: rgba(0, 0, 0, .6);
|
||||
border-radius: 20rpx;
|
||||
|
||||
.ing {
|
||||
width: 100%;
|
||||
height: 30vw;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
|
||||
// 模拟录音音效动画
|
||||
@keyframes volatility {
|
||||
0% {
|
||||
background-position: 0% 130%;
|
||||
}
|
||||
|
||||
20% {
|
||||
background-position: 0% 150%;
|
||||
}
|
||||
|
||||
30% {
|
||||
background-position: 0% 155%;
|
||||
}
|
||||
|
||||
40% {
|
||||
background-position: 0% 150%;
|
||||
}
|
||||
|
||||
50% {
|
||||
background-position: 0% 145%;
|
||||
}
|
||||
|
||||
70% {
|
||||
background-position: 0% 150%;
|
||||
}
|
||||
|
||||
80% {
|
||||
background-position: 0% 155%;
|
||||
}
|
||||
|
||||
90% {
|
||||
background-position: 0% 140%;
|
||||
}
|
||||
|
||||
100% {
|
||||
background-position: 0% 135%;
|
||||
}
|
||||
}
|
||||
|
||||
.icon {
|
||||
background-image: linear-gradient(to bottom, #f09b37, #fff 50%);
|
||||
background-size: 100% 200%;
|
||||
animation: volatility 1.5s ease-in-out -1.5s infinite alternate;
|
||||
-webkit-background-clip: text;
|
||||
-webkit-text-fill-color: transparent;
|
||||
font-size: 150rpx;
|
||||
color: #f09b37;
|
||||
}
|
||||
}
|
||||
|
||||
.cancel {
|
||||
width: 100%;
|
||||
height: 30vw;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
|
||||
.icon {
|
||||
color: #fff;
|
||||
font-size: 150rpx;
|
||||
}
|
||||
}
|
||||
|
||||
.tis {
|
||||
width: 100%;
|
||||
height: 10vw;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
font-size: 28rpx;
|
||||
color: #fff;
|
||||
|
||||
&.change {
|
||||
color: #f09b37;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.msg-list {
|
||||
|
||||
padding: 0 24rpx;
|
||||
.msg-list-item {
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
padding: 20rpx 0;
|
||||
&.msg-list-item-l {
|
||||
flex-direction: row;
|
||||
|
||||
.avatar {
|
||||
flex-shrink: 0;
|
||||
width: 80rpx;
|
||||
height: 80rpx;
|
||||
margin-right: 20rpx;
|
||||
}
|
||||
}
|
||||
&.msg-list-item-r {
|
||||
flex-direction: row-reverse;
|
||||
|
||||
.avatar {
|
||||
flex-shrink: 0;
|
||||
width: 80rpx;
|
||||
height: 80rpx;
|
||||
margin-left: 20rpx;
|
||||
}
|
||||
}
|
||||
.msg-text {
|
||||
max-width: 70%;
|
||||
min-height: 50rpx;
|
||||
border-radius: 4rpx 30rpx 30rpx 30rpx;
|
||||
padding: 16rpx 32rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
font-size: 32rpx;
|
||||
word-break: break-word;
|
||||
flex-wrap: wrap;
|
||||
background-color: #fff;
|
||||
color: #303133;
|
||||
.msg-text-txt {
|
||||
font-size: 32rpx;
|
||||
line-height: 48rpx;
|
||||
}
|
||||
.msg-text-emoji {
|
||||
vertical-align: top;
|
||||
width: 48rpx;
|
||||
height: 48rpx;
|
||||
display: inline-block;
|
||||
}
|
||||
}
|
||||
.msg-img {
|
||||
background-color: transparent;
|
||||
padding: 0;
|
||||
overflow: hidden;
|
||||
image {
|
||||
max-width: 350rpx;
|
||||
max-height: 350rpx;
|
||||
border-radius: 16rpx;
|
||||
}
|
||||
}
|
||||
.msg-voice {
|
||||
.icon {
|
||||
font-size: 40rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
.icon:after {
|
||||
content: " ";
|
||||
width: 53rpx;
|
||||
height: 53rpx;
|
||||
border-radius: 100%;
|
||||
position: absolute;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
.length {
|
||||
font-size: 28rpx;
|
||||
}
|
||||
&.play {
|
||||
@keyframes my-play {
|
||||
0% {
|
||||
transform: translateX(80%);
|
||||
}
|
||||
|
||||
100% {
|
||||
transform: translateX(0%);
|
||||
}
|
||||
}
|
||||
|
||||
.icon:after {
|
||||
border-left: solid 10rpx rgba(186, 230, 253, .8);
|
||||
animation: my-play 1s linear infinite;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// .msg-list-item {
|
||||
// padding: 20rpx 0;
|
||||
|
||||
// .content {
|
||||
// width: 100%;
|
||||
// display: flex;
|
||||
|
||||
// .msg-text {
|
||||
// max-width: 70%;
|
||||
// min-height: 50rpx;
|
||||
// border-radius: 4rpx 30rpx 30rpx 30rpx;
|
||||
// padding: 16rpx 32rpx;
|
||||
// display: flex;
|
||||
// align-items: center;
|
||||
// font-size: 32rpx;
|
||||
// word-break: break-word;
|
||||
// flex-wrap: wrap;
|
||||
// background-color: #fff;
|
||||
// color: #3A3A3A;
|
||||
// .msg-text-txt{
|
||||
// font-size: 32rpx;
|
||||
// line-height: 48rpx;
|
||||
// }
|
||||
// .msg-text-emoji{
|
||||
// vertical-align: top;
|
||||
// width: 48rpx;
|
||||
// height: 48rpx;
|
||||
// display: inline-block;
|
||||
// }
|
||||
// }
|
||||
|
||||
// .msg-img {
|
||||
// background-color: transparent;
|
||||
// padding: 0;
|
||||
// overflow: hidden;
|
||||
|
||||
// image {
|
||||
// max-width: 350rpx;
|
||||
// max-height: 350rpx;
|
||||
// border-radius: 16rpx;
|
||||
// }
|
||||
// }
|
||||
|
||||
// .msg-voice {
|
||||
|
||||
// .icon {
|
||||
// font-size: 40rpx;
|
||||
// display: flex;
|
||||
// align-items: center;
|
||||
// }
|
||||
|
||||
// .icon:after {
|
||||
// content: " ";
|
||||
// width: 53rpx;
|
||||
// height: 53rpx;
|
||||
// border-radius: 100%;
|
||||
// position: absolute;
|
||||
// box-sizing: border-box;
|
||||
// }
|
||||
|
||||
// .length {
|
||||
// font-size: 28rpx;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
// .avatar {
|
||||
// // flex-shrink: 0;
|
||||
// // width: 80rpx;
|
||||
// // height: 80rpx;
|
||||
// }
|
||||
|
||||
// .my {
|
||||
// display: flex;
|
||||
// justify-content: flex-end;
|
||||
|
||||
// .content {
|
||||
// min-height: 80rpx;
|
||||
// align-items: center;
|
||||
// justify-content: flex-end;
|
||||
|
||||
// .msg-text {
|
||||
// background-color: #BAE6FD;
|
||||
// border-radius: 30rpx 4rpx 30rpx 30rpx;
|
||||
// }
|
||||
|
||||
// .msg-voice {
|
||||
// .length {
|
||||
// margin-right: 20rpx;
|
||||
// }
|
||||
|
||||
// &.play {
|
||||
// @keyframes my-play {
|
||||
// 0% {
|
||||
// transform: translateX(80%);
|
||||
// }
|
||||
|
||||
// 100% {
|
||||
// transform: translateX(0%);
|
||||
// }
|
||||
// }
|
||||
|
||||
// .icon:after {
|
||||
// border-left: solid 10rpx rgba(186, 230, 253, .8);
|
||||
// animation: my-play 1s linear infinite;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
// .avatar {
|
||||
// margin-left: 16rpx;
|
||||
// }
|
||||
// }
|
||||
|
||||
// .other {
|
||||
// display: flex;
|
||||
|
||||
// .avatar {
|
||||
// margin-right: 16rpx;
|
||||
// }
|
||||
|
||||
// .content {
|
||||
// flex-wrap: wrap;
|
||||
|
||||
// .msg-voice {
|
||||
// .icon {
|
||||
// color: #333;
|
||||
// }
|
||||
|
||||
// .length {
|
||||
// margin-left: 20rpx;
|
||||
// }
|
||||
|
||||
// &.play {
|
||||
// @keyframes other-play {
|
||||
// 0% {
|
||||
// transform: translateX(-80%);
|
||||
// }
|
||||
|
||||
// 100% {
|
||||
// transform: translateX(0%);
|
||||
// }
|
||||
// }
|
||||
|
||||
// .icon:after {
|
||||
// border-right: solid 10rpx rgba(255, 255, 255, .8);
|
||||
|
||||
// animation: other-play 1s linear infinite;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
}
|
||||
}
|
||||
588
pages/message/im/index.vue
Normal file
@@ -0,0 +1,588 @@
|
||||
<template>
|
||||
<view class="im-v">
|
||||
<view @click="hideDrawer">
|
||||
<mescroll-body ref="mescrollRef" bottom="50%" @init="mescrollInit" :down="downOption" @down="downCallback"
|
||||
:up="upOption">
|
||||
<!-- 无更多消息 -->
|
||||
<view v-if="isEnd && !isMsgList" class="msg-end">没有更多消息了</view>
|
||||
<JnpfEmpty v-if="isMsgList" description="暂无聊天记录"></JnpfEmpty>
|
||||
<view class="msg-list">
|
||||
<!-- 消息列表 (必须配置id,以便定位) -->
|
||||
<view class="msg-list-item" v-for="(msg,index) in msgList" :key="index" :id="'msg'+msg.id"
|
||||
:class="userId === msg.sendUserId ? 'msg-list-item-r' : 'msg-list-item-l'">
|
||||
<view class="avatar" v-if="userId === msg.sendUserId">
|
||||
<u-avatar :src="baseURL+userInfoHeadIcon" size="80"></u-avatar>
|
||||
</view>
|
||||
<view class="avatar" v-else>
|
||||
<u-avatar :src="baseURL+headIcon" size="80"></u-avatar>
|
||||
</view>
|
||||
<!-- 文字,表情 -->
|
||||
<view class="msg-text" v-if="msg.contentType==='text'">
|
||||
<view v-for="(item,i) in msg.msgContent" :key="i">
|
||||
<text class="msg-text-txt" v-if="item.type=='text'">{{item.content}}</text>
|
||||
<image class="msg-text-emoji" :src="item.content" v-if="item.type=='emjio'" />
|
||||
</view>
|
||||
</view>
|
||||
<!-- 图片消息 -->
|
||||
<view v-if="msg.contentType=='image'" class="msg-img" @click="showPic(msg.msgContent.path)">
|
||||
<image lazy-load="true" :src="msg.msgContent.path"
|
||||
:style="{'width': msg.msgContent.width+'px','height': msg.msgContent.height+'px'}">
|
||||
</image>
|
||||
</view>
|
||||
<!-- 语言消息 -->
|
||||
<view v-if="msg.contentType==='voice'" class="msg-text msg-voice" @click="playVoice(msg)"
|
||||
:class="playMsgid == msg.id?'play':''">
|
||||
<view class="length">{{msg.msgContent.length}}</view>
|
||||
<view class="icon my-voice"></view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</mescroll-body>
|
||||
</view>
|
||||
<!-- 抽屉栏 -->
|
||||
<view class="input-box" :class="popupLayerClass" @touchmove.stop.prevent="discard">
|
||||
<view class="input-box-icon icon biaoqing" @click="chooseEmoji"></view>
|
||||
<!-- #ifndef H5 -->
|
||||
<view class="input-box-icon icon" :class="isVoice?'jianpan':'yuyin'" @click="switchVoice"></view>
|
||||
<!-- #endif -->
|
||||
<view class="voice-mode" :class="[isVoice?'':'hidden',recording?'recording':'']" @touchstart="voiceBegin"
|
||||
@touchmove.stop.prevent="voiceIng" @touchend="voiceEnd" @touchcancel="voiceCancel">{{voiceTis}}</view>
|
||||
<view class="text-mode" v-if="!isVoice">
|
||||
<view class="input-area">
|
||||
<textarea auto-height :cursor-spacing="8" maxlength="500" v-model="textMsg" @focus="textareaFocus"
|
||||
:focus="textFocus" />
|
||||
</view>
|
||||
</view>
|
||||
<view class="input-box-icon icon add" @click="openMore"></view>
|
||||
<view class="send-btn" @click="sendText" v-if="!isVoice">发送</view>
|
||||
</view>
|
||||
<view class="popup-layer u-border-top" :class="popupLayerClass" @touchmove.stop.prevent="discard">
|
||||
<swiper class="emoji-swiper" indicator-dots="true" duration="150" v-show="showEmoji">
|
||||
<swiper-item v-for="(page,pid) in emojiTree" :key="pid">
|
||||
<view v-for="(em,eid) in page" :key="eid" @click="addEmoji(em)" class="emoji-item">
|
||||
<image mode="widthFix" :src="getEmojiUrl(em.url)" class="emoji-item-img"></image>
|
||||
</view>
|
||||
</swiper-item>
|
||||
</swiper>
|
||||
<view class="more-layer" v-show="showMore">
|
||||
<view class="list">
|
||||
<view class="box" @click="chooseImage('album')">
|
||||
<text class="icon tupian2"></text>
|
||||
</view>
|
||||
<!-- #ifndef H5 -->
|
||||
<view class="box" @click="chooseImage('camera')">
|
||||
<text class="icon paizhao"></text>
|
||||
</view>
|
||||
<!-- #endif -->
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<!-- 录音UI效果 -->
|
||||
<view class="record" :class="recording?'':'hidden'">
|
||||
<view class="ing" :class="willStop?'hidden':''">
|
||||
<view class="icon luyin2"></view>
|
||||
</view>
|
||||
<view class="cancel" :class="willStop?'':'hidden'">
|
||||
<view class="icon chehui"></view>
|
||||
</view>
|
||||
<view class="tis" :class="willStop?'change':''">{{recordTis}}</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import chat from '@/libs/chat.js'
|
||||
import {
|
||||
emojiList,
|
||||
emojiTree,
|
||||
imagesMap
|
||||
} from './emoji.js'
|
||||
import MescrollMixin from "@/uni_modules/mescroll-uni/components/mescroll-uni/mescroll-mixins.js";
|
||||
import {
|
||||
mapGetters
|
||||
} from 'vuex'
|
||||
import jnpf from '@/utils/jnpf'
|
||||
import {
|
||||
useChatStore
|
||||
} from '@/store/modules/chat'
|
||||
const chatStore = useChatStore()
|
||||
//播放语音相关参数
|
||||
const AUDIO = uni.createInnerAudioContext()
|
||||
export default {
|
||||
mixins: [MescrollMixin],
|
||||
name: 'im',
|
||||
data() {
|
||||
return {
|
||||
formUserId: '',
|
||||
headIcon: '',
|
||||
name: '',
|
||||
downOption: {
|
||||
auto: true,
|
||||
},
|
||||
upOption: {
|
||||
use: false,
|
||||
toTop: {
|
||||
src: ''
|
||||
}
|
||||
},
|
||||
currentPage: 1,
|
||||
pageSize: 30,
|
||||
//录音相关参数
|
||||
// #ifndef H5
|
||||
//H5不能录音
|
||||
RECORDER: uni.getRecorderManager(),
|
||||
// #endif
|
||||
playMsgid: null,
|
||||
popupLayerClass: '',
|
||||
textFocus: false,
|
||||
showMore: false,
|
||||
showEmoji: false,
|
||||
emojiList,
|
||||
emojiTree,
|
||||
msgList: [],
|
||||
isEnd: false,
|
||||
isMsgList: true,
|
||||
isVoice: false,
|
||||
voiceTis: '按住 说话',
|
||||
recordTis: "手指上滑 取消发送",
|
||||
recording: false,
|
||||
willStop: false,
|
||||
initPoint: {
|
||||
identifier: 0,
|
||||
Y: 0
|
||||
},
|
||||
recordTimer: null,
|
||||
recordLength: 0,
|
||||
textMsg: '',
|
||||
msgImageList: [],
|
||||
userId: '',
|
||||
userInfoHeadIcon: ''
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
baseURL() {
|
||||
return this.define.baseURL
|
||||
}
|
||||
},
|
||||
watch: {},
|
||||
onLoad(option) {
|
||||
let userInfo = uni.getStorageSync('userInfo')
|
||||
this.userId = userInfo.userId
|
||||
this.userInfoHeadIcon = userInfo.headIcon
|
||||
this.formUserId = option.formUserId;
|
||||
this.headIcon = option.headIcon;
|
||||
this.name = option.name;
|
||||
uni.$on('getMessageList', data => {
|
||||
this.getMessageList(data)
|
||||
})
|
||||
uni.$on('addMsg', data => {
|
||||
this.addMsg(data)
|
||||
})
|
||||
chatStore.setFormUserId(this.formUserId)
|
||||
const updateReadMessage = {
|
||||
method: "UpdateReadMessage",
|
||||
formUserId: this.formUserId,
|
||||
token: uni.getStorageSync('token')
|
||||
}
|
||||
chat.sendMsg(JSON.stringify(updateReadMessage))
|
||||
uni.setNavigationBarTitle({
|
||||
title: option.name
|
||||
});
|
||||
//语音自然播放结束
|
||||
// #ifndef MP-ALIPAY
|
||||
AUDIO.onEnded((res) => {
|
||||
this.playMsgid = null;
|
||||
});
|
||||
// #endif
|
||||
// #ifndef H5 || MP-ALIPAY
|
||||
//录音开始事件
|
||||
this.RECORDER.onStart((e) => {
|
||||
this.recordBegin(e);
|
||||
});
|
||||
//录音结束事件
|
||||
this.RECORDER.onStop((e) => {
|
||||
this.recordEnd(e);
|
||||
});
|
||||
// #endif
|
||||
},
|
||||
onUnload() {
|
||||
uni.$off('getMessageList')
|
||||
uni.$off('addMsg')
|
||||
chatStore.setFormUserId('')
|
||||
// #ifndef MP-ALIPAY
|
||||
AUDIO.stop();
|
||||
// #endif
|
||||
},
|
||||
methods: {
|
||||
getMessageList(data) {
|
||||
let msgImageList = []
|
||||
const list = data.list.map(o => {
|
||||
if (o.contentType === 'image') {
|
||||
if (o.content) {
|
||||
let content = {}
|
||||
if (typeof(o.content) === 'string') {
|
||||
content = JSON.parse(o.content)
|
||||
} else {
|
||||
content = o.content
|
||||
}
|
||||
msgImageList.push(jnpf.getAuthImgUrl(content.path))
|
||||
}
|
||||
}
|
||||
return this.dealMsg(o)
|
||||
})
|
||||
this.msgImageList = [...msgImageList, ...this.msgImageList]
|
||||
let topMsg = this.msgList[0]
|
||||
this.msgList = [...list, ...this.msgList]
|
||||
if (this.msgList.length) this.isMsgList = false
|
||||
if (data.list.length < data.pagination.pageSize) {
|
||||
this.mescroll.lockDownScroll(true)
|
||||
this.isEnd = true
|
||||
}
|
||||
this.$nextTick(() => {
|
||||
if (this.currentPage <= 2) {
|
||||
this.mescroll.scrollTo(99999, 0)
|
||||
} else if (topMsg) {
|
||||
let view = uni.createSelectorQuery().select('#msg' + topMsg.id);
|
||||
view.boundingClientRect(v => {
|
||||
this.mescroll.scrollTo(v.top - 100, 0)
|
||||
}).exec();
|
||||
}
|
||||
})
|
||||
},
|
||||
downCallback() {
|
||||
const messageList = {
|
||||
method: "MessageList",
|
||||
toUserId: this.formUserId,
|
||||
formUserId: this.userId,
|
||||
token: uni.getStorageSync('token'),
|
||||
currentPage: this.currentPage,
|
||||
pageSize: this.pageSize,
|
||||
sord: "desc"
|
||||
}
|
||||
chat.sendMsg(JSON.stringify(messageList))
|
||||
this.currentPage++;
|
||||
this.mescroll.endSuccess();
|
||||
},
|
||||
discard() {
|
||||
return;
|
||||
},
|
||||
switchVoice() {
|
||||
this.hideDrawer();
|
||||
this.isVoice = !this.isVoice;
|
||||
},
|
||||
openMore() {
|
||||
if (this.showMore) return this.hideDrawer()
|
||||
this.showMore = true;
|
||||
this.showEmoji = false;
|
||||
this.openDrawer();
|
||||
},
|
||||
openDrawer() {
|
||||
this.isVoice = false;
|
||||
this.popupLayerClass = 'showLayer';
|
||||
},
|
||||
hideDrawer() {
|
||||
this.popupLayerClass = '';
|
||||
setTimeout(() => {
|
||||
this.showMore = false;
|
||||
this.showEmoji = false;
|
||||
}, 150);
|
||||
},
|
||||
textareaFocus() {
|
||||
this.hideDrawer();
|
||||
},
|
||||
chooseEmoji() {
|
||||
if (this.showEmoji) return this.hideDrawer()
|
||||
this.showMore = false;
|
||||
this.showEmoji = true;
|
||||
this.openDrawer();
|
||||
},
|
||||
addEmoji(em) {
|
||||
this.textMsg += em.alt;
|
||||
},
|
||||
getEmojiUrl(url) {
|
||||
return imagesMap[url.replace('.', '')]
|
||||
},
|
||||
chooseImage(type) {
|
||||
uni.chooseImage({
|
||||
// #ifdef H5
|
||||
count: 1,
|
||||
// #endif
|
||||
sourceType: [type], //从相册选择
|
||||
success: (res) => {
|
||||
this.hideDrawer();
|
||||
if (res.tempFilePaths.length) res.tempFilePaths.map(o => (this.uploadFile(o)))
|
||||
}
|
||||
});
|
||||
},
|
||||
/* 上传图片 */
|
||||
uploadFile(files) {
|
||||
uni.uploadFile({
|
||||
url: this.define.comUploadUrl + 'IM',
|
||||
filePath: files,
|
||||
name: 'file',
|
||||
header: {
|
||||
Authorization: uni.getStorageSync('token') || ''
|
||||
},
|
||||
success: (uploadFileRes) => {
|
||||
const response = uploadFileRes.data ? JSON.parse(uploadFileRes
|
||||
.data) : {}
|
||||
if (uploadFileRes.statusCode !== 200) return this.$u.toast(
|
||||
response.msg)
|
||||
if (!response.data || !response.data.name) return
|
||||
const name = response.data.name
|
||||
this.getImageInfo(files, name)
|
||||
}
|
||||
})
|
||||
},
|
||||
/* 获取图片信息 */
|
||||
getImageInfo(files, name) {
|
||||
uni.getImageInfo({
|
||||
src: files,
|
||||
success: (image) => {
|
||||
let msg = {
|
||||
name,
|
||||
width: image.width,
|
||||
height: image.height,
|
||||
};
|
||||
this.sendMessage(msg, 'image');
|
||||
}
|
||||
})
|
||||
},
|
||||
addMsg(data) {
|
||||
if (data.method === 'receiveMessage') {
|
||||
const updateReadMessage = {
|
||||
method: "UpdateReadMessage",
|
||||
formUserId: this.formUserId,
|
||||
token: uni.getStorageSync('token')
|
||||
}
|
||||
chat.sendMsg(JSON.stringify(updateReadMessage))
|
||||
}
|
||||
data.id = this.$u.guid()
|
||||
if (data.contentType === "text") {
|
||||
data.msgContent = this.replaceEmoji(data.content)
|
||||
}
|
||||
if (data.contentType === "image") {
|
||||
this.msgImageList.push(jnpf.getAuthImgUrl(data.content.path))
|
||||
data.msgContent = this.setPicSize(data.content)
|
||||
data.msgContent.path = jnpf.getAuthImgUrl(data.content.path)
|
||||
}
|
||||
if (data.contentType === "voice") {
|
||||
data.msgContent = data.content
|
||||
}
|
||||
this.msgList.push(data)
|
||||
this.$nextTick(() => {
|
||||
this.mescroll.scrollTo(99999, 0)
|
||||
})
|
||||
},
|
||||
dealMsg(item) {
|
||||
if (item.contentType === "text") {
|
||||
item.msgContent = this.replaceEmoji(item.content)
|
||||
}
|
||||
if (item.contentType === "image") {
|
||||
item.msgContent = this.setPicSize(JSON.parse(item.content))
|
||||
item.msgContent.path = jnpf.getAuthImgUrl(item.msgContent.path)
|
||||
}
|
||||
if (item.contentType === "voice") {
|
||||
item.msgContent = JSON.parse(item.content)
|
||||
}
|
||||
return item
|
||||
},
|
||||
sendText() {
|
||||
if (!this.textMsg) return
|
||||
this.hideDrawer()
|
||||
this.sendMessage(this.textMsg, 'text')
|
||||
this.textMsg = ''
|
||||
},
|
||||
sendMessage(content, type) {
|
||||
const messageObj = {
|
||||
method: "SendMessage",
|
||||
token: uni.getStorageSync('token'),
|
||||
toUserId: this.formUserId,
|
||||
messageType: type,
|
||||
messageContent: content
|
||||
}
|
||||
chat.sendMsg(JSON.stringify(messageObj))
|
||||
this.isMsgList = false
|
||||
},
|
||||
voiceBegin(e) { // 录音开始
|
||||
this.RECORDER.stop();
|
||||
if (e.touches.length > 1) {
|
||||
return;
|
||||
}
|
||||
this.initPoint.Y = e.touches[0].clientY;
|
||||
this.initPoint.identifier = e.touches[0].identifier;
|
||||
// #ifdef APP-HARMONY
|
||||
this.RECORDER.start(); //录音开始,
|
||||
// #endif
|
||||
// #ifndef APP-HARMONY
|
||||
this.RECORDER.start({
|
||||
format: "mp3"
|
||||
}); //录音开始,
|
||||
// #endif
|
||||
},
|
||||
recordBegin(e) { //录音开始UI效果
|
||||
this.recording = true;
|
||||
this.voiceTis = '松开 结束';
|
||||
this.recordLength = 0;
|
||||
this.recordTimer = setInterval(() => {
|
||||
this.recordLength++;
|
||||
}, 1000)
|
||||
},
|
||||
voiceCancel() { // 录音被打断
|
||||
this.recording = false;
|
||||
this.voiceTis = '按住 说话';
|
||||
this.recordTis = '手指上滑 取消发送'
|
||||
this.willStop = true; //不发送录音
|
||||
this.RECORDER.stop(); //录音结束
|
||||
},
|
||||
voiceIng(e) { // 录音中(判断是否触发上滑取消发送)
|
||||
if (!this.recording) return
|
||||
let touche = e.touches[0];
|
||||
// #ifndef APP-HARMONY
|
||||
let voice = uni.upx2px(100)
|
||||
// #endif
|
||||
// #ifdef APP-HARMONY
|
||||
let voice = 100 / 2
|
||||
// #endif
|
||||
//上滑一个导航栏的高度触发上滑取消发送
|
||||
if (this.initPoint.Y - touche.clientY >= voice) {
|
||||
this.willStop = true;
|
||||
this.recordTis = '松开手指 取消发送'
|
||||
} else {
|
||||
this.willStop = false;
|
||||
this.recordTis = '手指上滑 取消发送'
|
||||
}
|
||||
},
|
||||
voiceEnd(e) { // 结束录音
|
||||
if (!this.recording) return
|
||||
this.recording = false;
|
||||
this.voiceTis = '按住 说话';
|
||||
this.recordTis = '手指上滑 取消发送'
|
||||
this.RECORDER.stop(); //录音结束
|
||||
},
|
||||
recordEnd(e) { //录音结束(回调文件)
|
||||
if (!this.willStop) {
|
||||
let min = parseInt(this.recordLength / 60);
|
||||
let sec = this.recordLength % 60;
|
||||
min = min < 10 ? '0' + min : min;
|
||||
sec = sec < 10 ? '0' + sec : sec;
|
||||
if (sec < '01') {
|
||||
this.willStop = true;
|
||||
this.$u.toast('说话时间太短');
|
||||
return
|
||||
}
|
||||
uni.uploadFile({
|
||||
url: this.define.comUploadUrl + 'IM',
|
||||
filePath: e.tempFilePath,
|
||||
name: 'file',
|
||||
header: {
|
||||
Authorization: uni.getStorageSync('token') || ''
|
||||
},
|
||||
success: (uploadFileRes) => {
|
||||
const handleUploadResponse = (uploadFileRes, min, sec) => {
|
||||
const response = (uploadFileRes.data && JSON.parse(uploadFileRes.data)) ||
|
||||
{};
|
||||
if (uploadFileRes.statusCode !== 200) {
|
||||
this.$u.toast(response.msg || '上传失败,未知错误');
|
||||
return;
|
||||
}
|
||||
const {
|
||||
data = {}
|
||||
} = response;
|
||||
if (!data.name) {
|
||||
this.$u.toast('上传的文件信息不完整');
|
||||
return;
|
||||
}
|
||||
const msg = {
|
||||
name: data.name,
|
||||
length: `${min}:${sec}`
|
||||
};
|
||||
this.sendMessage(msg, 'voice');
|
||||
};
|
||||
handleUploadResponse(uploadFileRes, min, sec);
|
||||
}
|
||||
})
|
||||
} else {
|
||||
// console.log('取消发送录音');
|
||||
}
|
||||
this.willStop = false;
|
||||
},
|
||||
setPicSize(content) { //处理图片尺寸,如果不处理宽高,新进入页面加载图片时候会闪
|
||||
// 让图片最长边等于设置的最大长度,短边等比例缩小,图片控件真实改变,区别于aspectFit方式。
|
||||
// #ifndef APP-HARMONY
|
||||
let maxW = uni.upx2px(350); //350是定义消息图片最大宽度
|
||||
let maxH = uni.upx2px(350); //350是定义消息图片最大高度
|
||||
// #endif
|
||||
// #ifdef APP-HARMONY
|
||||
let maxW = 350 / 2; //350是定义消息图片最大宽度
|
||||
let maxH = 350 / 2; //350是定义消息图片最大高度
|
||||
// #endif
|
||||
if (content.width > maxW || content.height > maxH) {
|
||||
let scale = content.width / content.height;
|
||||
content.width = scale > 1 ? maxW : maxH * scale;
|
||||
content.height = scale > 1 ? maxW / scale : maxH;
|
||||
}
|
||||
return content;
|
||||
},
|
||||
replaceEmoji(str) { //替换表情符号为图片
|
||||
let replacedStr = str.replace(/\[([^(\]|\[)]*)\]/g, item => 'jnpfjnpf' + item + 'jnpfjnpf');
|
||||
let strArr = replacedStr.split(/jnpfjnpfjnpfjnpf|jnpfjnpf/g)
|
||||
strArr = strArr.filter(o => o)
|
||||
let contentList = []
|
||||
for (let i = 0; i < strArr.length; i++) {
|
||||
let item = {
|
||||
content: strArr[i],
|
||||
type: 'emjio'
|
||||
}
|
||||
if (/\[([^(\]|\[)]*)\]/.test(strArr[i])) {
|
||||
let content = ''
|
||||
for (let j = 0; j < this.emojiList.length; j++) {
|
||||
let row = this.emojiList[j];
|
||||
if (row.alt == strArr[i]) {
|
||||
content = this.getEmojiUrl(row.url)
|
||||
break
|
||||
}
|
||||
}
|
||||
item = {
|
||||
content: content,
|
||||
type: 'emjio'
|
||||
}
|
||||
} else {
|
||||
item = {
|
||||
content: strArr[i],
|
||||
type: 'text'
|
||||
}
|
||||
}
|
||||
contentList.push(item)
|
||||
}
|
||||
return contentList
|
||||
},
|
||||
showPic(path) { // 预览图片
|
||||
uni.previewImage({
|
||||
indicator: "none",
|
||||
current: path,
|
||||
urls: this.msgImageList
|
||||
});
|
||||
},
|
||||
playVoice(msg) { // 播放语音
|
||||
AUDIO.stop();
|
||||
AUDIO.src = jnpf.getAuthImgUrl(msg.msgContent.path, false);
|
||||
if (this.playMsgid != null && this.playMsgid == msg.id) {
|
||||
this.$nextTick(() => {
|
||||
AUDIO.stop();
|
||||
});
|
||||
this.playMsgid = null;
|
||||
} else {
|
||||
this.$nextTick(() => {
|
||||
AUDIO.play();
|
||||
});
|
||||
this.playMsgid = msg.id;
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
@import "./index.scss";
|
||||
</style>
|
||||
155
pages/message/messageDetail/index.vue
Normal file
@@ -0,0 +1,155 @@
|
||||
<template>
|
||||
<view class="messageDetail-v u-p-l-20 u-p-r-20">
|
||||
<view class="u-flex-col u-border-bottom u-p-b-40 u-m-b-40">
|
||||
<text class="u-m-b-16 u-font-32 txt">{{info.title}}</text>
|
||||
<view>
|
||||
<text class="releaseUser u-font-24 ">{{info.releaseUser}}</text>
|
||||
<text
|
||||
class="releaseUser u-font-24 u-m-l-16">{{ info.releaseTime?$u.timeFormat(info.releaseTime, 'yyyy-mm-dd hh:MM:ss'):''}}</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="u-p-b-16 excerpt" v-if="info.excerpt">
|
||||
{{info.excerpt}}
|
||||
</view>
|
||||
<view class="messageDetail-content u-p-b-20 ">
|
||||
<mp-html :content="info.bodyText" />
|
||||
</view>
|
||||
<view class="file-box">
|
||||
<view class="file-list u-flex" v-for="(item,index) in fileList" :key="index">
|
||||
<view class="file-list-l">
|
||||
<u-icon name="attach" color="#969799"></u-icon>
|
||||
<text class="fileName">{{item.name}}</text>
|
||||
</view>
|
||||
<u-icon name="download" color="#969799" @click="openFile(item)"></u-icon>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
const imgTypeList = ['png', 'jpg', 'jpeg', 'bmp', 'gif']
|
||||
import {
|
||||
getMessageDetail
|
||||
} from '@/api/message.js'
|
||||
import {
|
||||
getDownloadUrl
|
||||
} from '@/api/common'
|
||||
import jnpf from '@/utils/jnpf'
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
info: {},
|
||||
fileList: []
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
baseURL() {
|
||||
return this.define.baseURL
|
||||
}
|
||||
},
|
||||
onLoad(option) {
|
||||
this.initDetail(option.id)
|
||||
},
|
||||
methods: {
|
||||
initDetail(id) {
|
||||
getMessageDetail(id).then(res => {
|
||||
this.info = res.data;
|
||||
this.fileList = JSON.parse(this.info.files)
|
||||
uni.$emit('initUnReadMsgNum')
|
||||
})
|
||||
},
|
||||
previewImage(item) {
|
||||
if (!item.url) return
|
||||
const url = jnpf.getAuthImgUrl(item.url)
|
||||
uni.previewImage({
|
||||
urls: [url],
|
||||
current: url,
|
||||
success: () => {},
|
||||
fail: () => {
|
||||
uni.showToast({
|
||||
title: '预览图片失败',
|
||||
icon: 'none'
|
||||
});
|
||||
}
|
||||
});
|
||||
},
|
||||
openFile(item) {
|
||||
if (item.fileExtension && imgTypeList.includes(item.fileExtension)) return this.previewImage(item)
|
||||
// #ifdef MP
|
||||
this.previewFile(item)
|
||||
// #endif
|
||||
// #ifndef MP
|
||||
getDownloadUrl('annex', item.fileId).then(res => {
|
||||
// #ifdef H5
|
||||
window.location.href = this.baseURL + res.data.url + '&name=' + item.name;
|
||||
// #endif
|
||||
// #ifndef H5
|
||||
uni.downloadFile({
|
||||
url: this.baseURL + res.data.url + '&name=' + item.name,
|
||||
success: function(res) {
|
||||
var filePath = res.tempFilePath;
|
||||
uni.openDocument({
|
||||
filePath: encodeURI(filePath),
|
||||
showMenu: true,
|
||||
success: function(res) {
|
||||
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
// #endif
|
||||
})
|
||||
// #endif
|
||||
},
|
||||
previewFile(item) {
|
||||
let url = item.url
|
||||
uni.downloadFile({
|
||||
url: this.baseURL + url,
|
||||
success: (res) => {
|
||||
var filePath = res.tempFilePath;
|
||||
uni.openDocument({
|
||||
filePath: encodeURI(filePath),
|
||||
success: (res) => {
|
||||
console.log('打开文档成功');
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
},
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.messageDetail-v {
|
||||
.excerpt {
|
||||
word-break: break-all;
|
||||
}
|
||||
|
||||
.txt {
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.messageDetail-content {
|
||||
color: #606266;
|
||||
word-break: break-all;
|
||||
}
|
||||
|
||||
.releaseUser {
|
||||
color: #606266;
|
||||
}
|
||||
|
||||
.file-box {
|
||||
.file-list {
|
||||
margin-top: 20rpx;
|
||||
justify-content: space-between;
|
||||
|
||||
.file-list-l {
|
||||
.fileName {
|
||||
margin-left: 10rpx;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
BIN
pages/message/static/emoji/100.gif
Normal file
|
After Width: | Height: | Size: 1.7 KiB |
BIN
pages/message/static/emoji/101.gif
Normal file
|
After Width: | Height: | Size: 1.5 KiB |
BIN
pages/message/static/emoji/102.gif
Normal file
|
After Width: | Height: | Size: 1.7 KiB |
BIN
pages/message/static/emoji/103.gif
Normal file
|
After Width: | Height: | Size: 1.7 KiB |
BIN
pages/message/static/emoji/104.gif
Normal file
|
After Width: | Height: | Size: 1.9 KiB |
BIN
pages/message/static/emoji/105.gif
Normal file
|
After Width: | Height: | Size: 1.8 KiB |
BIN
pages/message/static/emoji/106.gif
Normal file
|
After Width: | Height: | Size: 3.4 KiB |
BIN
pages/message/static/emoji/107.gif
Normal file
|
After Width: | Height: | Size: 3.8 KiB |
BIN
pages/message/static/emoji/108.gif
Normal file
|
After Width: | Height: | Size: 4.5 KiB |
BIN
pages/message/static/emoji/109.gif
Normal file
|
After Width: | Height: | Size: 3.1 KiB |
BIN
pages/message/static/emoji/110.gif
Normal file
|
After Width: | Height: | Size: 3.5 KiB |
BIN
pages/message/static/emoji/111.gif
Normal file
|
After Width: | Height: | Size: 7.7 KiB |
BIN
pages/message/static/emoji/112.gif
Normal file
|
After Width: | Height: | Size: 2.1 KiB |
BIN
pages/message/static/emoji/113.gif
Normal file
|
After Width: | Height: | Size: 1.6 KiB |
BIN
pages/message/static/emoji/114.gif
Normal file
|
After Width: | Height: | Size: 3.7 KiB |
BIN
pages/message/static/emoji/115.gif
Normal file
|
After Width: | Height: | Size: 1.5 KiB |
BIN
pages/message/static/emoji/116.gif
Normal file
|
After Width: | Height: | Size: 1.3 KiB |
BIN
pages/message/static/emoji/117.gif
Normal file
|
After Width: | Height: | Size: 2.9 KiB |
BIN
pages/message/static/emoji/118.gif
Normal file
|
After Width: | Height: | Size: 7.3 KiB |
BIN
pages/message/static/emoji/119.gif
Normal file
|
After Width: | Height: | Size: 7.3 KiB |
BIN
pages/message/static/emoji/120.gif
Normal file
|
After Width: | Height: | Size: 1.7 KiB |
BIN
pages/message/static/emoji/121.gif
Normal file
|
After Width: | Height: | Size: 1.8 KiB |
BIN
pages/message/static/emoji/122.gif
Normal file
|
After Width: | Height: | Size: 2.9 KiB |
BIN
pages/message/static/emoji/123.gif
Normal file
|
After Width: | Height: | Size: 1.9 KiB |
BIN
pages/message/static/emoji/124.gif
Normal file
|
After Width: | Height: | Size: 2.2 KiB |
BIN
pages/message/static/emoji/125.gif
Normal file
|
After Width: | Height: | Size: 2.3 KiB |
BIN
pages/message/static/emoji/126.gif
Normal file
|
After Width: | Height: | Size: 3.9 KiB |
BIN
pages/message/static/emoji/127.gif
Normal file
|
After Width: | Height: | Size: 2.5 KiB |
BIN
pages/message/static/emoji/128.gif
Normal file
|
After Width: | Height: | Size: 3.2 KiB |
BIN
pages/message/static/emoji/129.gif
Normal file
|
After Width: | Height: | Size: 5.0 KiB |
BIN
pages/message/static/emoji/130.gif
Normal file
|
After Width: | Height: | Size: 1.6 KiB |
BIN
pages/message/static/emoji/131.gif
Normal file
|
After Width: | Height: | Size: 5.4 KiB |
BIN
pages/message/static/emoji/132.gif
Normal file
|
After Width: | Height: | Size: 6.6 KiB |
BIN
pages/message/static/emoji/133.gif
Normal file
|
After Width: | Height: | Size: 4.1 KiB |
BIN
pages/message/static/emoji/134.gif
Normal file
|
After Width: | Height: | Size: 2.0 KiB |
BIN
pages/message/static/emoji/135.gif
Normal file
|
After Width: | Height: | Size: 12 KiB |
BIN
pages/message/static/emoji/136.gif
Normal file
|
After Width: | Height: | Size: 1.4 KiB |
BIN
pages/message/static/emoji/137.gif
Normal file
|
After Width: | Height: | Size: 1.2 KiB |
BIN
pages/message/static/emoji/138.gif
Normal file
|
After Width: | Height: | Size: 1.6 KiB |
BIN
pages/message/static/emoji/139.gif
Normal file
|
After Width: | Height: | Size: 1.7 KiB |
BIN
pages/message/static/emoji/140.gif
Normal file
|
After Width: | Height: | Size: 9.6 KiB |
BIN
pages/message/static/emoji/141.gif
Normal file
|
After Width: | Height: | Size: 3.2 KiB |
BIN
pages/message/static/emoji/142.gif
Normal file
|
After Width: | Height: | Size: 12 KiB |
BIN
pages/message/static/emoji/143.gif
Normal file
|
After Width: | Height: | Size: 4.0 KiB |
BIN
pages/message/static/emoji/144.gif
Normal file
|
After Width: | Height: | Size: 1.5 KiB |
BIN
pages/message/static/emoji/145.gif
Normal file
|
After Width: | Height: | Size: 4.2 KiB |
BIN
pages/message/static/emoji/146.gif
Normal file
|
After Width: | Height: | Size: 4.6 KiB |
BIN
pages/message/static/emoji/147.gif
Normal file
|
After Width: | Height: | Size: 3.6 KiB |
BIN
pages/message/static/emoji/148.gif
Normal file
|
After Width: | Height: | Size: 1.6 KiB |
BIN
pages/message/static/emoji/149.gif
Normal file
|
After Width: | Height: | Size: 5.8 KiB |
BIN
pages/message/static/emoji/150.gif
Normal file
|
After Width: | Height: | Size: 3.0 KiB |
BIN
pages/message/static/emoji/151.gif
Normal file
|
After Width: | Height: | Size: 3.6 KiB |