初始提交

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

95
pages/my/abouts/index.vue Normal file
View File

@@ -0,0 +1,95 @@
<template>
<view class="abouts-v">
<view class="head-box u-flex-col">
<view class="head-inner">
<view class="version">
{{sysVersion}}
</view>
<image src="/static/image/jnpf.png" mode="widthFix" class="head-img"></image>
</view>
</view>
<view class="content u-p-l-32 u-p-r-32 u-p-t-30 u-font-28">
<text>引迈信息技术有限公司是一家做快速开发平台的企业针对软件传统开发遇到招人难留人难用人成本高技术更新换代快等一系列问题只需要一套JNPF平台您遇到的一系列问题就依然而解
JNPF采用主流的两大技术Java/.Net开发是一套低代码开发平台可视化开发环境有拖拽式的代码生成器灵活的权限配置SaaS服务强大的接口对接随心可变的工作流引擎一站式开发多端使用WebAndroidIOS微信小程序并且有以构建业务流程逻辑和数据模型等所需的功能为企业项目节省80%的重回工作让开发者将重心放在业务逻辑不必烦恼底层架构设计可短时间开发出如ERPOACRMHRMIS以及电信银行政府企业等各行业的企业应用系统
引迈信息技术有限公司以诚信为根本服务为基础理念通过持续不断地研发技术创新强化平台质量和颜值为企业保驾护航</text>
</view>
<view class="copyright">{{copyright}}</view>
</view>
</template>
<script>
import resources from '@/libs/resources.js'
export default {
data() {
return {
logoSrc: resources.banner.loginlogo,
copyright: 'Copyright © 2024 引迈信息技术有限公司出品',
sysVersion: ''
}
},
onLoad() {
this.sysVersion = uni.getStorageSync('sysVersion') || this.define.sysVersion
this.copyright = uni.getStorageSync('copyright') || 'Copyright © 2024 引迈信息技术有限公司出品'
},
}
</script>
<style lang="scss">
.abouts-v {
.head-box {
height: 308rpx;
background: url('@/pages/my/static/image/about-head.png') center no-repeat;
background-size: 100% 100%;
align-items: center;
justify-content: center;
.head-inner {
position: relative;
.head-img {
width: 212rpx;
height: 60rpx;
margin-top: 20rpx;
}
.version {
position: absolute;
background-color: #FFFFFF;
color: #0F5BD2;
padding: 0 8rpx;
border-radius: 20rpx 0rpx 20rpx 0rpx;
top: -34rpx;
left: 218rpx;
}
}
}
.abouts-hd {
width: 100%;
align-items: center;
background-color: #3281ff;
height: 280rpx;
color: #FFFFFF;
padding-top: 20rpx;
image {
width: 160rpx;
height: 160rpx;
}
}
.copyright {
height: 80rpx;
bottom: 0;
line-height: 80rpx;
}
.content {
height: calc(100vh - 486rpx);
overflow-y: scroll;
line-height: 48rpx;
}
}
</style>

View File

@@ -0,0 +1,82 @@
<template>
<view class="accountSecurity-v">
<u-cell-group style="padding: 0 20rpx;">
<u-cell-item :title="$t('app.my.accountSecurity.changePassword')"
@click="handelClick('/pages/my/modifyPsd/index','password')">
</u-cell-item>
<u-cell-item :title="$t('app.my.accountSecurity.mobilePhone')" :value="userInfo.mobilePhone"
@click="handelClick('/pages/my/modifyPsd/index','mobilePhone',userInfo.mobilePhone)">
</u-cell-item>
<u-cell-item :title="$t('app.my.accountSecurity.email')" :value="userInfo.email"
@click="handelClick('/pages/my/modifyPsd/index','email',userInfo.email)">
</u-cell-item>
<!-- #ifdef APP-PLUS -->
<u-cell-item title="注销账号" @click="openPage('/pages/my/cancellation/index')"></u-cell-item>
<!-- #endif -->
</u-cell-group>
</view>
</template>
<script>
import {
getUserSettingInfo
} from "@/api/common.js"
export default {
data() {
return {
userInfo: {},
needRefresh: false
}
},
onShow() {
if (this.needRefresh) {
this.needRefresh = false;
this.init();
}
},
onLoad() {
this.init()
},
methods: {
init() {
getUserSettingInfo().then(res => {
this.userInfo = res.data || {}
})
},
openPage(path, type) {
uni.navigateTo({
url: path
})
},
handelClick(path, type, vuale) {
if (!path) return
this.needRefresh = true
let config = {
type,
vuale
}
uni.navigateTo({
url: path + '?config=' + encodeURIComponent(JSON.stringify(config))
})
}
}
}
</script>
<style lang="scss">
page {
background-color: #f0f2f6;
}
:deep(.u-cell) {
height: 112rpx;
padding: 20rpx 0;
}
.accountSecurity-v {
background-color: #fff;
/* #ifdef MP-WEIXIN */
height: 360rpx;
/* #endif */
}
</style>

View File

@@ -0,0 +1,124 @@
<template>
<view class="cancellation-v">
<view class="cancellation-hd">
<image :src="accountSecurity"></image>
</view>
<view class="content u-flex-col">
<view class="content-text u-flex-col">
<text class="content-title u-font-36 u-type-primary">确认注销账户</text>
<text class="content-tip u-font-28">注销账户后以下数据将全部清空</text>
<view class="list u-flex-col u-font-26">
<text class="item">企业组织架构和员工信息</text>
<text class="item">所有数据和聊天记录</text>
<text class="item">删除和永久注销JNPF账户</text>
</view>
</view>
<view class="btn">
<u-button type="primary" @click="handleClick">注销账号</u-button>
</view>
</view>
</view>
</template>
<script>
import {
accountCancel,
logout
} from '@/api/common.js'
import resources from '@/libs/resources.js'
export default {
data() {
return {
accountSecurity: resources.banner.accountSecurity
}
},
computed: {
token() {
return uni.getStorageSync('token')
},
userInfo() {
return uni.getStorageSync('userInfo') || {}
}
},
methods: {
handleClick() {
uni.showModal({
title: '提示',
content: '您的JNPF账号将被删除您确定要注销JNPF账号么',
success: res => {
if (res.confirm) {
if (this.userInfo.isAdministrator) return this.$u.toast('管理员账号不能注销')
accountCancel(this.token).then((res) => {
this.$u.toast(res.msg)
setTimeout(() => {
uni.reLaunch({
url: '/pages/login/index'
})
}, 1000)
})
}
}
})
},
}
}
</script>
<style lang="scss">
.cancellation-v {
.cancellation-hd {
width: 100%;
height: 280rpx;
image {
width: 100%;
height: 100%;
}
}
.content {
.content-text {
justify-content: center;
padding: 176rpx 0 0 190rpx;
}
.content-title {
height: 100rpx;
font-weight: 700;
}
.content-tip {
height: 80rpx;
color: #252B3A;
}
.list {
.item {
margin-bottom: 35rpx;
color: #666;
display: flex;
flex-direction: row;
align-items: center;
&::before {
content: "";
width: 12rpx;
height: 12rpx;
border-radius: 50%;
background-color: #356efe;
margin-right: 30rpx;
}
}
}
.btn {
padding: 0 32rpx;
width: 100%;
position: fixed;
bottom: 40rpx;
margin: 0 auto;
}
}
}
</style>

View File

@@ -0,0 +1,132 @@
<template>
<view class="change-system-v">
<view class="u-p-l-20 u-p-r-20 change-system-search">
<u-search :placeholder="$t('app.apply.pleaseKeyword')" v-model="keyword" height="72" :show-action="false"
@change="onSearchChange" bg-color="#f0f2f6" shape="square" style="width: 100%;">
</u-search>
</view>
<view class="system-box u-m-t-20">
<view class="system-container" v-if="systemList.length">
<view class="item u-flex-col u-col-center" v-for="(item, i) in systemList" :key="i"
@click="handelClick(item)">
<text class="u-font-40 item-icon" :class="item.icon"
:style="{ background: item.backgroundColor || '#008cff' }" />
<text class="u-font-24 u-line-1 item-text"
:style="{color:userInfo.systemId==item.id?'#008cff':''}">{{item.fullName}}</text>
</view>
</view>
<JnpfEmpty v-else />
</view>
</view>
</template>
<script>
import {
getSystemList
} from "@/api/system";
import {
setMajor,
} from "@/api/common";
export default {
data() {
return {
keyword: '',
systemList: [],
userInfo: {}
}
},
onShow() {
this.keyword = ''
this.getUserInfo()
this.init()
},
methods: {
onSearchChange(val) {
this.init()
},
init() {
getSystemList({
keyword: this.keyword
}).then(res => {
this.systemList = res.data || []
})
},
async getUserInfo() {
this.userInfo = uni.getStorageSync('userInfo') || {}
},
handelClick(item) {
if (item.id === this.userInfo.systemId) return
let query = {
majorId: item.id,
majorType: "system",
menuType: 1,
};
setMajor(query).then((res) => {
this.$u.toast(res.msg);
uni.setStorageSync('systemCode', item.enCode)
setTimeout(() => {
uni.reLaunch({
url: "/pages/index/index"
})
}, 500)
}).catch((err) => {
this.$u.toast(err);
});
}
}
}
</script>
<style lang="scss">
page {
background-color: #f0f2f6;
height: 100%;
}
.change-system-v {
height: 100%;
display: flex;
flex-direction: column;
.change-system-search {
background-color: #fff;
width: 100%;
height: 120rpx;
line-height: 120rpx;
}
.system-box {
background-color: #fff;
}
.system-container {
display: flex;
flex-direction: row;
flex-wrap: wrap;
overflow: auto;
padding-top: 20rpx;
}
.item {
margin-bottom: 32rpx;
width: 25%;
.item-icon {
width: 88rpx;
height: 88rpx;
margin-bottom: 8rpx;
line-height: 88rpx;
text-align: center;
border-radius: 30rpx;
color: #fff;
font-size: 40rpx;
}
.item-text {
width: 100%;
text-align: center;
padding: 0 16rpx;
}
}
}
</style>

View File

@@ -0,0 +1,193 @@
<template>
<view class="contacts-v" v-show="show">
<view class="contactusBanner">
<image :src="contactus" mode="widthFix"></image>
</view>
<view class="contactus u-flex-col">
<view class="u-flex items u-m-b-20" v-for="(item,index) in list" @click="Jump(index)" :key="index">
<view :class="item.bcg" style="" class="items-iconBox u-m-r-50 u-padding-15">
<u-icon :name="item.icon" color="#ffffff" size="54"></u-icon>
</view>
<view class="u-flex-col u-flex-1">
<text>{{item.name}}</text>
<text class="againColor">{{item.title}}</text>
</view>
<view>
<u-icon name="arrow-right" color="#969799" size="28"></u-icon>
</view>
</view>
<view class="serviceTime u-flex-col u-p-l-32 u-p-b-20 u-p-t-20">
<text class="u-font-xl" type='title'>服务时间</text>
<text class="textSize">工作日{{workingHours}}</text>
<text class="textSize">节假日{{holidayWorkingHours}}</text>
</view>
</view>
<view class="copyright">{{copyright}}</view>
<u-popup v-model="showPopup" mode="center">
<view class="center-box">
<image class="image" :src="wechat_qrcode" :data-path="wechat_qrcode" @longpress="saveImage" />
</view>
</u-popup>
</view>
</template>
<script>
import resources from '@/libs/resources.js'
export default {
data() {
return {
contactus: resources.banner.contactus,
wechat_qrcode: resources.common.wechat_qrcode,
holidayWorkingHours: '9:30-12:00 13:30-17:30',
workingHours: '8:30-12:00 13:00-20:00',
tell: '400-6868-969',
url: 'https://www.jnpfsoft.com',
showPopup: false,
list: [{
name: '微信公众号',
title: '扫码关注官网微信公众号',
icon: 'weixin-fill',
bcg: 'u-type-success-bg'
},
{
name: '服务热线',
title: '400-6868-969',
icon: 'kefu-ermai',
bcg: 'u-type-warning-bg'
},
{
name: '官方网站',
title: 'www.jnpfsoft.com',
icon: 'ie',
bcg: 'u-type-primary-bg'
}
],
copyright: 'Copyright © 2024 引迈信息技术有限公司出品',
show: false
}
},
onLoad() {
uni.showLoading({
title: '加载中'
});
this.copyright = uni.getStorageSync('copyright') || 'Copyright © 2024 引迈信息技术有限公司出品'
setTimeout(() => {
uni.hideLoading()
this.show = true
}, 800)
},
methods: {
Jump(index) {
switch (index) {
case 0:
this.showPopup = true
break;
case 1:
uni.makePhoneCall({
phoneNumber: this.tell,
})
break;
case 2:
// #ifdef APP-PLUS
plus.runtime.openURL(this.url);
// #endif
// #ifndef APP-PLUS
uni.navigateTo({
url: '/pages/apply/externalLink/index?fullName=福建引迈信息技术有限公司&url=' + encodeURIComponent(
this.url)
})
// #endif
break;
}
},
saveImage(e) {
// #ifdef APP-PLUS
uni.getImageInfo({
src: e.currentTarget.dataset.path,
success: (res) => {
uni.saveImageToPhotosAlbum({
filePath: res.path,
success: function() {
helper.msg('保存成功', 'success');
}
});
}
});
// #endif
},
}
}
</script>
<style lang="scss">
page {
width: 100%;
background-color: #f0f2f6;
}
.contacts-v {
width: 100%;
.contactusBanner {
width: 100%;
height: 280rpx;
image {
width: 100%;
height: 100%;
}
}
.contactus {
margin: 18rpx 16rpx 0;
.againColor {
color: #909399;
}
.items {
padding: 20rpx 32rpx;
background-color: #FFFFFF;
justify-content: start;
border-radius: 8rpx;
.items-iconBox {
border-radius: 50%;
height: 88rpx;
width: 88rpx;
display: flex;
align-items: center;
justify-content: center;
}
}
.serviceTime {
background-color: #FFFFFF;
border-radius: 8rpx;
}
}
.center-box {
width: 420rpx;
height: 420rpx;
image {
width: 100%;
height: 100%;
}
}
.textSize {
height: 66rpx;
line-height: 66rpx;
color: #909399;
}
text[type="title"] {
height: 86rpx;
line-height: 86rpx;
font-weight: 700;
}
}
</style>

204
pages/my/contacts/index.vue Normal file
View File

@@ -0,0 +1,204 @@
<template>
<view class="contacts-v">
<mescroll-body ref="mescrollRef" @init="mescrollInit" @down="downCallback" @up="upCallback" :sticky="true"
:down="downOption" :up="upOption" :bottombar="false">
<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 class="organization u-border-bottom">{{keyword?'联系人':'组织列表'}}</view>
</view>
<view class="list-cell u-p-l-20 u-p-r-20" v-if="!keyword">
<scroll-view :scroll-y="true" style="height: 100%">
<ly-tree :tree-data="list" :node-key="defaultProps.value" :props="defaultProps"
:load="loadNode" lazy :default-expand-all='false' :show-node-icon="true"
:defaultExpandedKeys="defaultExpandedKeys" child-visible-for-filter-node
@node-click="handleNodeClick" ref="tree">
</ly-tree>
</scroll-view>
</view>
<view class="list-cell u-p-l-20 u-p-r-20" v-for="(item, i) in list" :key="i" @click="detail(item)" v-else>
<view class="u-border-bottom list-item u-font-28 u-flex" v-if="list.length">
<u-avatar :src="baseURL+item.headIcon"></u-avatar>
<view class="list-cell-txt">
<view class="u-font-30 u-m-b-4" style="color: #303133;font-size: 28rpx;">
{{item.realName}}/{{item.account}}
</view>
<view class="u-font-24 department u-m-t-4">{{item.department}}</view>
</view>
</view>
</view>
</mescroll-body>
</view>
</template>
<script>
import {
getOrgAndPosSelector
} from '@/api/message.js'
import {
getUserList
} 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'),
},
keyword: '',
list: [],
defaultProps: {
label: 'fullName',
value: 'id',
icon: 'icon',
children: 'children',
isLeaf: 'isLeaf'
},
level: 0,
}
},
computed: {
baseURL() {
return this.define.baseURL
},
defaultExpandedKeys() {
return this.list.length ? [this.list[0].id] : []
}
},
methods: {
upCallback(page) {
let query = this.keyword ? {
currentPage: page.num,
pageSize: page.size,
keyword: this.keyword,
organizeId: '',
organizeName: '',
positionId: ''
} : {
id: '0',
type: 'organize'
};
let method = this.keyword ? getUserList(query) : getOrgAndPosSelector(query);
method.then(res => {
const list = res.data.list || [];
if (!this.keyword) {
this.list = list;
return this.mescroll.endSuccess(true);
}
this.mescroll.endSuccess(list.length);
if (page.num === 1) this.list = [];
this.list = this.list.concat(list);
}).catch(() => {
this.mescroll.endErr();
});
},
loadNode(node, resolve) {
let query = {
id: node.key || 0,
type: node.data.type || 'organize'
}
getOrgAndPosSelector(query).then(res => {
resolve(res.data.list)
})
},
search() {
// 节流,避免输入过快多次请求
this.searchTimer && clearTimeout(this.searchTimer)
this.searchTimer = setTimeout(() => {
this.list = [];
this.mescroll.resetUpScroll();
}, 300)
},
handleNodeClick(data) {
const type = data.data.type
const config = {
organizeId: type === 'organize' ? data.key : data.data?.organizeId,
organizeName: data.label,
...(type === 'position' ? {
positionId: data.key
} : {})
};
uni.navigateTo({
url: '/pages/my/contacts/userList?config=' + encodeURIComponent(JSON.stringify(
config)),
})
},
detail(item) {
uni.navigateTo({
url: '/pages/my/userDetail/index?data=' + encodeURIComponent(JSON.stringify(
item))
})
},
}
}
</script>
<style lang="scss">
page {
background-color: #eef0f4;
}
.contacts-v {
::v-deep .ly-tree-node__icon {
width: 1.5rem;
height: 1.5rem;
overflow: hidden;
margin-right: 0.5rem;
background: #43a1f3;
border-radius: 50%;
text-align: center;
line-height: 1.5rem;
color: #fff;
font-size: 24rpx;
}
.organization {
width: 100%;
background-color: #fff;
padding: 20rpx;
font-size: 32rpx;
}
.list-cell {
width: 100%;
background-color: #fff;
.list-item {
box-sizing: border-box;
overflow: hidden;
color: $u-content-color;
height: 136rpx;
.list-cell-txt {
margin-left: 20rpx;
.department {
color: #909399;
font-size: 24rpx;
}
}
}
}
}
</style>

View File

@@ -0,0 +1,147 @@
<template>
<view class="contacts-v">
<mescroll-body ref="mescrollRef" @init="mescrollInit" @down="downCallback" @up="upCallback" :sticky="true"
:down="downOption" :up="upOption" :bottombar="false">
<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="list-cell u-p-l-20 u-p-r-20" v-for="(item, i) in list" :key="i" @click="detail(item)">
<view class="u-border-bottom list-item u-font-28 u-flex">
<u-avatar :src="baseURL+item.headIcon"></u-avatar>
<view class="list-cell-txt">
<view class="u-font-30 u-m-b-4" style="color: #303133;font-size: 28rpx;">
{{item.realName}}/{{item.account}}
</view>
<view class="u-font-24 department u-m-t-4">{{item.department}}</view>
</view>
</view>
</view>
</mescroll-body>
</view>
</template>
<script>
import {
getUserList
} 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'),
},
keyword: '',
list: [],
organizeId: '',
organizeName: '',
positionId: ''
}
},
computed: {
baseURL() {
return this.define.baseURL
}
},
onLoad(e) {
const config = JSON.parse(decodeURIComponent(e.config))
this.organizeId = config.organizeId
this.organizeName = config.organizeName
this.positionId = config.positionId
uni.setNavigationBarTitle({
title: config.organizeName
})
},
methods: {
upCallback(page) {
let query = {
currentPage: page.num,
pageSize: page.size,
keyword: this.keyword,
organizeId: this.organizeId,
organizeName: this.organizeName,
positionId: this.positionId || ""
}
getUserList(query).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();
})
},
search() {
// 节流,避免输入过快多次请求
this.searchTimer && clearTimeout(this.searchTimer)
this.searchTimer = setTimeout(() => {
this.list = [];
this.mescroll.resetUpScroll();
}, 300)
},
detail(item) {
uni.navigateTo({
url: '/pages/my/userDetail/index?data=' + encodeURIComponent(JSON.stringify(
item))
})
},
}
}
</script>
<style lang="scss">
page {
background-color: #eef0f4;
}
.contacts-v {
.organization {
width: 100%;
background-color: #fff;
padding: 20rpx;
font-size: 32rpx;
}
.list-cell {
width: 100%;
background-color: #fff;
.list-item {
box-sizing: border-box;
overflow: hidden;
color: $u-content-color;
height: 136rpx;
.list-cell-txt {
margin-left: 20rpx;
.department {
color: #909399;
font-size: 24rpx;
}
}
}
}
}
</style>

177
pages/my/identity/index.vue Normal file
View File

@@ -0,0 +1,177 @@
<template>
<view class="page_v u-flex-col">
<view class="lists_box u-m-b-20" v-if="show" v-for="(item,index) in list" :key="index"
:class="item.isDefault ? 'active' : '' " @click="clickRadio(item)">
<view class="icon-checked-box" v-if="item.isDefault">
<text>默认</text>
<view class="icon-checked">
<u-icon name="checkbox-mark" color="#fff" size="28"></u-icon>
</view>
</view>
<view class="list_inner">
<text class="icon-ym" :class="item.icon"></text>
<text class="txt">{{item.name}}</text>
</view>
</view>
<JnpfEmpty v-if="!show"></JnpfEmpty>
</view>
</template>
<script>
import {
getUserOrganizes,
setMajor,
} from '@/api/common'
export default {
data() {
return {
list: [],
majorType: '',
show: true,
disabled: false,
userInfo: {}
}
},
onLoad(e) {
this.userInfo = uni.getStorageSync('userInfo') || {}
this.majorType = e.majorType
this.getUserOrganizes()
uni.setNavigationBarTitle({
title: this.$t('app.my.myIdentity')
})
},
methods: {
getUserOrganizes() {
let data = this.userInfo?.standingList || []
if (!data.length) return this.show = this.list.length > 0
this.list = JSON.parse(JSON.stringify(data));
this.show = this.list.length > 0
this.list.map(o => {
if (o.currentStanding) o.isDefault = true
})
},
clickRadio(item) {
if (this.disabled || item.isDefault) return
this.changeMajor(item.id)
},
change(id) {
this.list.map((o, i) => {
o.isDefault = false;
if (o.id === id) o.isDefault = true;
})
},
changeMajor(majorId) {
let query = {
majorId,
majorType: this.majorType
}
setMajor(query).then(res => {
this.$u.toast(res.msg)
if (res.code === 200) {
setTimeout(() => {
uni.reLaunch({
url: "/pages/index/index"
})
}, 500)
}
}).catch(() => {})
},
}
}
</script>
<style lang="scss">
page {
background-color: #f0f2f6;
}
.page_v {
/* #ifdef MP */
background-color: #f0f2f6;
/* #endif */
padding: 20rpx 20rpx 0 20rpx;
.active {
border: 1rpx solid #2979FF;
color: #2979FF;
.icon-ym-organization {
&::before {
color: #2979FF !important;
}
}
}
.lists_box {
width: 100%;
min-height: 160rpx;
border-radius: 8rpx;
position: relative;
display: flex;
flex-direction: column;
justify-content: center;
background-color: #FFFFFF;
.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;
}
}
.list_inner {
width: 100%;
min-height: 160rpx;
display: flex;
flex-direction: row;
padding: 0 20rpx;
align-items: center;
.icon-ym-wf-outgoingApply {
&::before {
margin-right: 6rpx;
font-size: 40rpx;
}
}
.icon-ym-organization {
&::before {
margin-right: 6rpx;
font-size: 40rpx;
color: #606266;
}
}
.txt_icon {}
.txt {
width: 100%;
align-items: flex-end;
word-wrap: break-word;
margin-left: 20rpx;
}
}
}
}
</style>

View File

@@ -0,0 +1,314 @@
<template>
<view class="jnpf-wrap jnpf-wrap-workflow">
<view class="" style="background-color: #fff">
<u-form :model="dataForm" :rules="rules" ref="dataForm" :errorType="['toast']" label-position="left"
label-width="150" label-align="left">
<view v-if="type == 'mobilePhone'">
<view class="u-p-l-20 u-p-r-20">
<u-form-item label="新手机" prop="mobilePhone" required>
<u-input v-model="dataForm[type]" placeholder="请输入"></u-input>
</u-form-item>
</view>
</view>
<view v-if="type == 'email'">
<view class="u-p-l-20 u-p-r-20">
<u-form-item label="新邮箱" prop="email" required>
<u-input v-model="dataForm[type]" placeholder="请输入"></u-input>
</u-form-item>
</view>
</view>
<view v-if="type == 'password'">
<view class="u-p-l-20 u-p-r-20">
<u-form-item label="旧密码" prop="oldPassword" required>
<u-input v-model="dataForm.oldPassword" placeholder="请输入" type="password"></u-input>
</u-form-item>
</view>
<view class="u-p-l-20 u-p-r-20">
<u-form-item label="新密码" prop="password" required>
<u-input v-model="dataForm.password" placeholder="请输入" type="password"></u-input>
</u-form-item>
</view>
<view class="u-p-l-20 u-p-r-20">
<u-form-item label="重复密码" prop="repeatPsd" required>
<u-input v-model="dataForm.repeatPsd" placeholder="请输入" type="password"></u-input>
</u-form-item>
</view>
<view class="u-p-l-20 u-p-r-20">
<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>
</view>
</view>
</u-form>
</view>
<!-- 底部按钮 -->
<view class="flowBefore-actions">
<u-button class="buttom-btn" type="primary" @click.stop="dataFormSubmit">保存</u-button>
</view>
</view>
</template>
<script>
import md5Libs from "@/uni_modules/vk-uview-ui/libs/function/md5";
import {
updatePassword,
updateUserInfo
} from "@/api/common.js";
import {
useUserStore
} from "@/store/modules/user";
export 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();
}
};
var validatPphone = (rule, value, callback) => {
// 手机号正则表达式
const phoneRegex = /^1[3-9]\d{9}$/;
if (value === "" || !value) {
callback(new Error('请输入手机号'));
} else if (!phoneRegex.test(value)) {
callback(new Error("手机号格式错误"));
} else {
callback();
}
};
var validateEmail = (rule, value, callback) => {
// 邮箱验证正则表达式
const emailRegex = /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/;
if (value === "" || !value) {
callback(new Error("请输入邮箱"));
} else if (!emailRegex.test(value)) {
callback(new Error("邮箱格式错误"));
} else {
callback();
}
};
return {
imgUrl: "",
timestamp: "",
dataForm: {
oldPassword: "",
password: "",
repeatPsd: "",
code: "",
timestamp: "",
mobilePhone: "",
email: "",
},
baseForm: {
passwordStrengthLimit: 0,
passwordLengthMin: false,
passwordLengthMinNumber: 0,
containsNumbers: false,
includeLowercaseLetters: false,
includeUppercaseLetters: false,
containsCharacters: false,
},
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",
}, ],
mobilePhone: [{
required: true,
validator: validatPphone,
trigger: "blur",
}, ],
email: [{
required: true,
validator: validateEmail,
trigger: "blur",
}, ],
},
type: "",
loading: false,
};
},
computed: {
baseURL() {
return this.define.baseURL;
},
},
onLoad(e) {
this.loading = false;
const config = JSON.parse(decodeURIComponent(e.config));
this.type = config.type;
uni.setNavigationBarTitle({
title: this.type == "mobilePhone" ?
"修改手机" : this.type == "email" ?
"修改邮箱" : "修改密码",
});
if (this.type != "password")
return (this.dataForm[this.type] = config.vuale);
this.changeCode();
this.initData();
},
mounted() {
this.$refs.dataForm.setRules(this.rules);
},
methods: {
initData() {
this.$nextTick(() => {
const config = uni.getStorageSync("sysConfigInfo") || {};
const {
passwordLengthMin = false,
containsNumbers = false,
includeLowercaseLetters = false,
includeUppercaseLetters = false,
containsCharacters = false,
passwordStrengthLimit = 0,
passwordLengthMinNumber = 0,
} = config;
Object.assign(this.baseForm, {
passwordLengthMin: !!passwordLengthMin,
containsNumbers: !!containsNumbers,
includeLowercaseLetters: !!includeLowercaseLetters,
includeUppercaseLetters: !!includeUppercaseLetters,
containsCharacters: !!containsCharacters,
passwordStrengthLimit: Number(passwordStrengthLimit) || 0,
passwordLengthMinNumber: Number(passwordLengthMinNumber) || 0,
});
});
},
changeCode() {
let timestamp = Math.random();
this.timestamp = timestamp;
this.imgUrl = `/api/file/ImageCode/${timestamp}`;
},
dataFormSubmit() {
this.$refs["dataForm"].validate((valid) => {
if (valid) {
this.loading = true;
let query = {};
if (this.type == "mobilePhone" || this.type == "email") {
query = {
[this.type]: this.dataForm[this.type],
};
updateUserInfo(query)
.then((res) => {
this.dataForm[this.type] = query[this.type];
this.$u.toast(res.msg);
this.loading = false;
})
.catch(() => {
this.loading = false;
});
return;
}
query = {
oldPassword: md5Libs.md5(this.dataForm.oldPassword),
password: md5Libs.md5(this.dataForm.password),
code: this.dataForm.code,
timestamp: this.timestamp,
};
updatePassword(query)
.then((res) => {
this.$u.toast(res.msg);
this.loading = false;
const userStore = useUserStore();
userStore.logout().then(() => {
uni.reLaunch({
url: "/pages/login/index",
});
});
})
.catch(() => {
this.changeImg();
this.loading = false;
});
}
});
},
},
};
</script>
<style lang="scss">
.jnpf-wrap.jnpf-wrap-workflow {
padding-bottom: 0;
}
:deep(.u-form-item) {
background-color: #fff;
min-height: 112rpx;
}
</style>

View File

@@ -0,0 +1,183 @@
<template>
<view class="page_v u-flex-col">
<view class="u-m-t-20 u-m-b-20">
<JnpfAlert type="warning" :title="description" effect="dark" />
</view>
<view class="organization_box u-m-b-20" v-if="show" v-for="(item,index) in list" :key="index"
:class="item.isDefault ? 'active' : '' " @click="clickRadio(item)">
<view class="icon-checked-box" v-if="item.isDefault">
<text>默认</text>
<view class="icon-checked">
<u-icon name="checkbox-mark" color="#fff" size="28"></u-icon>
</view>
</view>
<view class="list_inner u-flex-col">
<view class="inner_item">
<text>所属组织</text>
<text class="txt u-line-1"
:style="{color:item.isDefault ? '#2979FF' : ''}">{{item.orgTreeName}}</text>
</view>
<view class="inner_item">
<text>任职岗位</text>
<text class="txt u-line-1" :style="{color:item.isDefault ? '#2979FF' : ''}">{{item.fullName}}</text>
</view>
<view class="inner_item">
<text>上级岗位</text>
<text class="txt u-line-1"
:style="{color:item.isDefault ? '#2979FF' : ''}">{{ item.parentName || '-' }}</text>
</view>
<view class="inner_item">
<text>上级责任人</text>
<text class="txt u-line-1"
:style="{color:item.isDefault ? '#2979FF' : ''}">{{item.managerName}}</text>
</view>
</view>
</view>
<JnpfEmpty v-if="!show"></JnpfEmpty>
</view>
</template>
<script>
import {
getUserPositions,
setMajor,
} from '@/api/common'
export default {
data() {
return {
list: [],
majorType: '',
show: true,
disabled: false,
userInfo: {},
description: '默认组织仅逐级审批时使用'
}
},
onLoad(e) {
this.userInfo = uni.getStorageSync('userInfo') || {}
this.majorType = e.majorType
this.getUserPositions()
uni.setNavigationBarTitle({
title: this.$t('app.my.organization')
})
},
methods: {
getUserPositions() {
getUserPositions().then(res => {
let data = res.data || []
if (!data.length) return this.show = this.list.length > 0
this.list = JSON.parse(JSON.stringify(data));
this.show = this.list.length > 0
this.list.map(o => {
if (o.currentStanding) o.isDefault = true
})
})
},
clickRadio(item) {
if (this.disabled || item.isDefault) return
this.changeMajor(item.id)
},
change(id) {
this.list.map((o, i) => {
o.isDefault = false;
if (o.id === id) o.isDefault = true;
})
},
changeMajor(majorId) {
let query = {
majorId,
majorType: this.majorType
}
setMajor(query).then(res => {
this.$u.toast(res.msg)
if (res.code === 200) {
setTimeout(() => {
uni.reLaunch({
url: "/pages/index/index"
})
}, 500)
}
}).catch(() => {})
},
}
}
</script>
<style lang="scss">
page {
background-color: #f0f2f6;
}
.page_v {
/* #ifdef MP */
background-color: #f0f2f6;
/* #endif */
padding: 0 20rpx;
.active {
border: 1rpx solid #2979FF;
color: #2979FF;
}
.organization_box {
width: 100%;
border-radius: 8rpx;
position: relative;
display: flex;
flex-direction: column;
justify-content: center;
background-color: #FFFFFF;
.icon-checked-box {
position: absolute;
display: flex;
width: 140rpx;
height: 80rpx;
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;
}
}
.list_inner {
width: 100%;
min-height: 160rpx;
padding: 0 20rpx;
align-items: flex-start;
.inner_item {
width: 100%;
padding: 20rpx 0;
display: table-row;
}
.txt {
flex: 1.2;
white-space: nowrap;
color: #606266;
width: 400rpx;
overflow-x: auto;
display: inline-flex;
margin-left: 40rpx;
}
}
}
}
</style>

View File

@@ -0,0 +1,208 @@
<template>
<view class="jnpf-wrap personalData">
<view style="background-color: #fff;" class="u-p-l-20 u-p-r-20">
<u-form :model="dataForm" :errorType="['toast']" label-position="left" label-width="150" label-align="right"
ref="dataForm">
<u-form-item label="姓名" prop='realName' required>
<u-input input-align='right' v-model="dataForm.realName" placeholder="请输入"></u-input>
</u-form-item>
<u-form-item label="民族">
<JnpfSelect v-model="dataForm.nation" placeholder="请选择" :options='nationOptions' />
</u-form-item>
<u-form-item label="性别">
<JnpfSelect v-model="dataForm.gender" placeholder="请选择" :options='genderOptions' :props='props' />
</u-form-item>
<u-form-item label="籍贯">
<u-input input-align='right' v-model="dataForm.nativePlace" placeholder="请输入"></u-input>
</u-form-item>
<u-form-item label="证件类型">
<JnpfSelect v-model="dataForm.certificatesType" placeholder="请选择"
:options='certificatesTypeOptions' />
</u-form-item>
<u-form-item label="证件号码">
<u-input input-align='right' v-model="dataForm.certificatesNumber" placeholder="请输入">
</u-input>
</u-form-item>
<u-form-item label="文化程度">
<JnpfSelect v-model="dataForm.education" placeholder="请选择" :options='educationOptions' />
</u-form-item>
<u-form-item label="出生年月">
<JnpfDatePicker v-model="dataForm.birthday" placeholder="请选择" />
</u-form-item>
<u-form-item label="办公电话">
<u-input input-align='right' v-model="dataForm.telePhone" placeholder="请输入">
</u-input>
</u-form-item>
<u-form-item label="办公座机">
<u-input input-align='right' v-model="dataForm.landline" placeholder="请输入">
</u-input>
</u-form-item>
<u-form-item label="紧急联系">
<u-input input-align='right' v-model="dataForm.urgentContacts" placeholder="请输入">
</u-input>
</u-form-item>
<u-form-item label="紧急电话">
<u-input input-align='right' v-model="dataForm.urgentTelePhone" placeholder="请输入">
</u-input>
</u-form-item>
<u-form-item label="通讯地址">
<u-input input-align='right' v-model="dataForm.postalAddress" placeholder="请输入">
</u-input>
</u-form-item>
<u-form-item label="自我介绍">
<u-input input-align='right' v-model="dataForm.signature" placeholder="请输入" type="textarea" />
</u-form-item>
</u-form>
</view>
<view class="flowBefore-actions">
<u-button class="buttom-btn" type="primary" @click='submit'>保存</u-button>
</view>
</view>
</template>
<script>
import {
UpdateUser
} from '@/api/common'
import {
useBaseStore
} from '@/store/modules/base'
const baseStore = useBaseStore()
export default {
props: {
personalData: {
type: Object,
default: () => ({})
}
},
data() {
const data = {
show: false,
props: {
label: 'fullName',
value: 'enCode'
},
dataForm: {
birthday: null,
certificatesNumber: "",
certificatesType: "",
education: "",
email: "",
gender: "",
landline: "",
mobilePhone: "",
nation: "",
nativePlace: "",
postalAddress: "",
realName: "",
signature: null,
telePhone: "",
urgentContacts: "",
urgentTelePhone: "",
id: null
},
nationOptions: [],
genderOptions: [],
certificatesTypeOptions: [],
educationOptions: [],
rules: {
realName: [{
required: true,
message: '请输入姓名',
trigger: ['change', 'blur'],
}]
}
}
return data
},
computed: {
baseURL() {
return this.define.baseURL
}
},
watch: {
personalData: {
handler(val) {
this.init()
},
deep: true,
immediate: true
}
},
mounted() {
this.$refs.dataForm.setRules(this.rules);
},
methods: {
init() {
let initData = JSON.parse(JSON.stringify(this.personalData))
for (let key in initData) {
for (let k in this.dataForm) {
if (key === k) {
this.dataForm[key] = initData[key]
}
}
}
this.getOptions()
},
getOptions() {
baseStore.getDictionaryData({
sort: 'Education'
}).then((res) => {
this.educationOptions = JSON.parse(JSON.stringify(res))
baseStore.getDictionaryData({
sort: 'certificateType'
}).then((res) => {
this.certificatesTypeOptions = JSON.parse(JSON.stringify(res))
})
baseStore.getDictionaryData({
sort: 'sex'
}).then(res => {
this.genderOptions = JSON.parse(JSON.stringify(res))
})
baseStore.getDictionaryData({
sort: 'Nation'
}).then(res => {
this.nationOptions = JSON.parse(JSON.stringify(res))
})
})
this.show = true
},
submit() {
this.$refs.dataForm.validate(valid => {
if (valid) {
UpdateUser(this.dataForm).then(res => {
uni.showToast({
title: '保存成功',
duration: 800,
icon: 'none'
});
setTimeout(() => {
uni.navigateBack()
}, 1000)
})
}
});
}
}
}
</script>
<style lang="scss">
page {
background-color: #f0f2f6;
}
.slot-btn {
width: 329rpx;
height: 140rpx;
display: flex;
justify-content: center;
align-items: center;
background: rgb(244, 245, 246);
border-radius: 10rpx;
}
.slot-btn__hover {
background-color: rgb(235, 236, 238);
}
</style>

View File

@@ -0,0 +1,63 @@
<template>
<view class="personalData-v">
<view class="content">
<personalData ref="personalData" :personalData="baseInfo"></personalData>
</view>
</view>
</template>
<script>
import personalData from './components/personalData.vue';
export default {
components: {
personalData,
},
data() {
return {
baseInfo: {}
};
},
onLoad(e) {
// this.baseInfo = JSON.parse(e.baseInfo)
// #ifdef MP-WEIXIN || APP-HARMONY
this.baseInfo = JSON.parse(decodeURIComponent(e.baseInfo))
// #endif
// #ifndef MP-WEIXIN || APP-HARMONY
this.baseInfo = JSON.parse(decodeURIComponent(this.jnpf.encodeContent(e.baseInfo)))
// #endif
},
methods: {}
}
</script>
<style lang="scss">
page {
background-color: #f0f2f6;
height: 100%;
}
.notice-warp {
height: 100rpx;
.search-box {
padding: 20rpx;
}
}
.content {
margin-top: 20rpx;
}
.personalData-v {
display: flex;
flex-direction: column;
padding-bottom: 100rpx;
::v-deep .buttom-btn {
width: 100% !important;
}
}
</style>

View File

@@ -0,0 +1,180 @@
<template>
<view class="common_v">
<mescroll-uni ref="mescrollRef" @init="mescrollInit" @down="downCallback" @up="upCallback" :up="upOption"
:bottombar="false" top="120">
<SwipeItem :list="commonWordsList" :buttons="actionData" @action="bindClick" ref="swipeItem" :marginB="20">
<template v-slot="{ item }">
<view class="action-item">
{{item.commonWordsText}}
</view>
</template>
</SwipeItem>
</mescroll-uni>
<view class="flowBefore-actions">
<u-button class="buttom-btn" type="primary" @click='editCommonWord'>添加常用语</u-button>
</view>
</view>
<uni-popup ref="inputDialog" type="dialog">
<uni-popup-dialog ref="inputClose" @confirm="confirm" mode="input" class="popup-dialog"
borderRadius="20px 20px 20px 20px" beforeClose @close="close" title="审批常用语">
<!-- #ifndef MP-WEIXIN -->
<u-input v-model="commonWordsText" type="textarea" placeholder="请输入内容" :auto-height="false"
maxlength="99999" height="150" />
<!-- #endif -->
<!-- #ifdef MP-WEIXIN -->
<textarea v-model="commonWordsText" :maxlength="99999" placeholder="请输入内容"
style="padding: 20rpx 0; "></textarea>
<!-- #endif -->
</uni-popup-dialog>
</uni-popup>
</template>
<script>
import {
commonWords,
Create,
Update,
Delete
} from "@/api/commonWords.js";
import MescrollMixin from "@/uni_modules/mescroll-uni/components/mescroll-uni/mescroll-mixins.js";
import resources from '@/libs/resources.js'
import SwipeItem from "@/components/SwipeItem/index"
export default {
mixins: [MescrollMixin],
components: {
SwipeItem
},
props: {
showCommonWords: {
type: Boolean,
default: false
}
},
data() {
return {
downOption: {
use: true,
auto: true
},
upOption: {
page: {
num: 0,
size: 30,
time: null
},
empty: {
use: true,
icon: resources.message.nodata,
tip: this.$t('common.noData'),
fixed: true,
top: "360rpx"
},
textNoMore: this.$t('app.apply.noMoreData')
},
actionData: [{
style: {
backgroundColor: '#1890ff'
},
value: 'edit',
text: '编辑'
},
{
style: {
backgroundColor: '#F56C6C'
},
value: 'delete',
text: '删除'
}
],
commonWordsText: '',
commonWordsData: {},
commonWordsList: [],
showAdd: false
}
},
methods: {
upCallback(page) {
const query = {
currentPage: page.num,
pageSize: page.size,
commonWordsType: 1
}
commonWords(query).then(res => {
const curPageData = res.data.list || [] // 当前页数据
if (page.num == 1) this.commonWordsList = []; // 第一页需手动制空列表
this.mescroll.endSuccess(res.data.list.length);
this.commonWordsList = this.commonWordsList.concat(curPageData); //追加新数据
}).catch(() => {
this.mescroll.endErr();
})
},
bindClick(item) {
if (item.btn.value == 'edit') this.editCommonWord(item.item)
if (item.btn.value == 'delete') this.delCommonWord(item.item)
},
editCommonWord(item) {
this.$refs.inputDialog.open()
let data = {
commonWordsText: "",
enabledMark: 1,
id: 0,
sortCode: 0,
systemIds: [],
systemNames: [],
};
if (item.id) {
this.commonWordsText = item.commonWordsText;
this.commonWordsData = {
...item,
systemIds: [],
systemNames: []
};
} else {
this.commonWordsText = "";
this.commonWordsData = data;
}
},
delCommonWord(item) {
Delete(item.id).then(res => {
this.$u.toast(res.msg)
this.mescroll.resetUpScroll()
})
},
close() {
this.$refs.inputDialog.close()
},
confirm() {
this.commonWordsData.commonWordsText = this.commonWordsText;
this.commonWordsData.commonWordsType = 1
if (!this.commonWordsText) return this.$u.toast(`审批常用语不能为空`);
let funs = this.commonWordsData.id === 0 ? Create : Update;
funs(this.commonWordsData).then((res) => {
this.close()
this.commonWordsText = "";
uni.showToast({
title: res.msg,
icon: "none",
complete: () => {
this.mescroll.resetUpScroll()
},
});
}).catch(() => {
this.close()
this.mescroll.resetUpScroll()
});
}
}
}
</script>
<style lang="scss">
.action-item {
width: 100%;
min-height: 3.6rem;
background-color: #fff;
display: flex;
align-items: center;
border-bottom: 1rpx solid #eee;
padding: 10rpx 20rpx;
word-break: break-all;
}
</style>

View File

@@ -0,0 +1,256 @@
<template>
<view>
<view class="page_v u-flex-col">
<view>
<view v-if="show" v-for="(item,index) in signImg" :key="index" :class="item.isDefault ? 'active' : '' "
class="lists_box" @longpress="handleTouchStart(item,index)">
<view class="signImgBox">
<image :src="item.signImg" mode="scaleToFill" class="signImg"></image>
</view>
<view class="icon-checked-box" v-if="item.isDefault">
<view class="icon-checked">
<u-icon name="checkbox-mark" color="#fff" size="28"></u-icon>
</view>
</view>
<view class="sign-mask" v-if="!item.isDefault && item.isSet" :id="index">
<view class="sign-mask-btn">
<u-button @click.prevent="del(item.id,index)">删除</u-button>
<u-button type="primary" @click.prevent="setDefault(item.id,index)">设为默认</u-button>
</view>
</view>
</view>
</view>
<JnpfSign ref="signRef" @change="signData" :showBtn="false" />
<JnpfEmpty v-if="!show" />
</view>
<view class="flowBefore-actions">
<u-button class="buttom-btn" type="primary" @click='showAction = true'>添加签名</u-button>
</view>
<u-action-sheet @click="handleAction" :list="actionList" :tips="{ text: '' , color: '#000' , fontSize: 30 }"
v-model="showAction">
</u-action-sheet>
</view>
</template>
<script>
import {
pathToBase64
} from '@/libs/file.js'
import {
getSignImgList,
createSignImg,
setDefSignImg,
delSignImg
} from '@/api/common'
export default {
data() {
return {
value: '',
show: true,
signImg: [],
isSet: false,
showAction: false,
actionList: [{
text: '在线签名',
id: 1
},
{
text: '图片上传',
id: 2
}
]
}
},
computed: {
baseURL() {
return this.define.comUploadUrl
},
token() {
return uni.getStorageSync('token')
}
},
mounted() {
this.getSignImgList()
},
methods: {
getSignImgList() {
getSignImgList().then(res => {
let signList = JSON.parse(JSON.stringify(res.data)) || []
this.show = signList.length > 0 ? true : false
this.signImg = signList.map(o => ({
isSet: false,
...o
}))
})
},
signData(e) {
if (e) {
let data = {
'signImg': e,
'isDefault': 0
}
createSignImg(data).then((res) => {
this.getSignImgList()
})
}
},
handleTouchStart(item, index) {
this.signImg.map((o, i) => {
o.isSet = false
})
item.isSet = true
},
del(id, index) {
delSignImg(id, index).then((res) => {
this.signImg.splice(index, 1)
})
},
setDefault(id, index) {
let userInfo = uni.getStorageSync('userInfo')
setDefSignImg(id).then((res) => {
this.signImg.map((o, i) => {
o.isDefault = false;
if (index == i) {
o.isDefault = true
o.isSet = false
userInfo.signImg = o.signImg
uni.setStorageSync('userInfo', userInfo)
}
})
})
},
handleAction(e) {
if (e == 0) {
this.$refs.signRef.addSign();
} else {
uni.chooseImage({
count: 1, //默认9
sizeType: ['original', 'compressed'], //可以指定是原图还是压缩图,默认二者都有
sourceType: ['album'],
success: (res) => {
let tempFilePaths = res.tempFilePaths[0]
// #ifdef H5
let isAccept = new RegExp('image/*').test(res.tempFiles[0].type)
if (!isAccept) return this.$u.toast(`请上传图片`)
// #endif
if ((res.tempFiles[0].size / 1024) > 500) return this.$u.toast('操作失败图片大小超出500K')
// #ifdef APP-HARMONY
this.harmony(tempFilePaths)
// #endif
// #ifndef APP-HARMONY
pathToBase64(tempFilePaths).then(base64 => {
this.signData(base64)
})
// #endif
}
});
}
},
harmony(tempFilePaths) {
uni.uploadFile({
url: this.baseURL + 'imgToBase64',
filePath: tempFilePaths,
name: 'file',
header: {
'Authorization': this.token
},
success: (uploadFileRes) => {
let res = JSON.parse(uploadFileRes.data)
this.signData(res.data)
},
fail: (err) => {}
});
}
}
}
</script>
<style lang="scss">
page {
background-color: #f0f2f6;
}
.page_v {
height: 100%;
padding: 0 20rpx;
.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: 12rpx;
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-bottom: 20rpx;
overflow: hidden;
.signImgBox {
width: 100%;
height: 100%;
text-align: center;
.signImg {
width: 100%;
height: 100%;
}
}
.icon-checked-box {
display: flex;
width: 140rpx;
height: 80rpx;
position: absolute;
transform: scale(0.9);
right: -4rpx;
bottom: -2rpx;
flex-direction: row;
align-items: center;
.icon-checked {
width: 44rpx;
height: 44rpx;
border: 40rpx solid #1890ff;
border-left: 40rpx solid transparent;
border-top: 40rpx solid transparent;
border-bottom-right-radius: 12rpx;
position: absolute;
transform: scale(0.95);
right: -8rpx;
bottom: -6rpx;
}
}
}
}
</style>

View File

@@ -0,0 +1,72 @@
<template>
<view class="personalData-v">
<view class="notice-warp">
<u-tabs :list="tabBars" :is-scroll="false" v-model="current" @change="tabChange" height="100">
</u-tabs>
</view>
<view class="content">
<signList ref="signList" v-if="current == 0"></signList>
<commonText ref="commonText" v-if="current == 1"></commonText>
</view>
</view>
</template>
<script>
import signList from './components/signList.vue';
import commonText from './components/commonText.vue';
export default {
components: {
signList,
commonText
},
data() {
return {
tabBars: [{
name: '个人签名'
}, {
name: '审批常用语'
}],
current: 0,
baseInfo: {}
};
},
onLoad(e) {
this.current = 0
this.baseInfo = e.baseInfo && JSON.parse(decodeURIComponent(e.baseInfo))
},
methods: {
tabChange(index) {
this.current = index;
}
}
}
</script>
<style lang="scss">
page {
background-color: #f0f2f6;
height: 100%;
}
.notice-warp {
height: 100rpx;
.search-box {
padding: 20rpx;
}
}
.content {
margin-top: 120rpx;
}
.personalData-v {
display: flex;
flex-direction: column;
padding-bottom: 100rpx;
::v-deep .buttom-btn {
width: 100% !important;
}
}
</style>

View File

@@ -0,0 +1,32 @@
<template>
<view class="scanResult-v">
<view class="text">
{{result}}
</view>
</view>
</template>
<script>
export default {
name: 'scanResult',
data() {
return {
result: '',
}
},
onLoad(option) {
this.result = option.result;
}
}
</script>
<style lang="scss">
page {
background-color: #fff;
}
.scanResult-v {
height: 100%;
padding: 0 24rpx;
}
</style>

115
pages/my/settings/index.vue Normal file
View File

@@ -0,0 +1,115 @@
<template>
<view class="settings-v">
<u-cell-group class="u-p-l-20 u-p-r-20" :border="false">
<!-- #ifndef MP-WEIXIN -->
<u-cell-item :title="$t('app.my.settings.language')" @click="selectLocaleShow=true"
:title-style="titleStyle"></u-cell-item>
<!-- #endif -->
<!-- #ifdef APP-PLUS -->
<u-cell-item :title="$t('app.my.settings.userAgreement')" @click='openPage(agreement)'
:title-style="titleStyle"></u-cell-item>
<u-cell-item :title="$t('app.my.settings.privacyPolicy')" @click='openPage(policy)'
:title-style="titleStyle"></u-cell-item>
<!-- #endif -->
<u-cell-item :title="$t('app.my.settings.contact')" @click="modifyPsd('/pages/my/contactUs/index')"
:title-style="titleStyle">
</u-cell-item>
<u-cell-item :title="$t('app.my.settings.about')" @click="modifyPsd('/pages/my/abouts/index')"
:title-style="titleStyle" :border-bottom="false">
</u-cell-item>
</u-cell-group>
<u-select v-model="selectLocaleShow" :list="localeList" mode="single-column" :default-value="defaultLocale"
@confirm="localeConfirm"></u-select>
</view>
</template>
<script>
import resources from '@/libs/resources.js'
import {
useLocale
} from '@/locale/useLocale';
export default {
data() {
return {
// #ifdef APP-PLUS
agreement: resources.userAgreement,
policy: resources.privacyPolicy,
// #endif
titleStyle: {
color: '#303133'
},
localeList: [{
label: '简体中文',
value: 'zh-Hans'
},
{
label: '繁体中文',
value: 'zh-Hant'
},
{
label: 'English',
value: 'en'
}
],
selectLocaleShow: false,
defaultLocale: []
};
},
onLoad() {
this.defaultLocale = [this.localeList.findIndex(o => o.value === uni.getLocale())];
},
methods: {
modifyPsd(path) {
if (!path) return
uni.navigateTo({
url: path
})
},
// #ifdef APP-PLUS
openPage(url) {
plus.runtime.openURL(url);
},
// #endif
localeConfirm(e) {
if (e[0].index === this.defaultLocale[0]) return
const systemInfo = uni.getSystemInfoSync();
const isAndroid = systemInfo.platform.toLowerCase() === 'android';
if (isAndroid) {
uni.showModal({
content: '应用此设置将重启App',
success: (res) => {
if (res.confirm) {
this.handleChangeLocale(e[0])
}
}
})
} else {
this.handleChangeLocale(e[0])
}
},
handleChangeLocale(e) {
this.defaultLocale = [e.index];
const {
changeLocale
} = useLocale();
changeLocale(e.value)
},
}
}
</script>
<style lang="scss">
page {
background-color: #f0f2f6;
}
:deep(.u-cell) {
height: 112rpx;
padding: 20rpx 0;
}
.settings-v {
background-color: #fff;
}
</style>

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

View File

@@ -0,0 +1,128 @@
<template>
<view class="userDetail-v">
<view class="userDetail-hd u-flex-col">
<view class="u-m-t-60">
<u-avatar :src="define.baseURL+userData.headIcon" size="120"></u-avatar>
</view>
<view class="u-m-t-32 u-font-32 name">
<text>{{userData.realName}}/{{userData.account}}</text>
</view>
<view class="u-m-t-20 u-font-24 positionName">
<text>{{userData.organize}}</text>
</view>
<view class="u-m-t-32 u-flex userDetail-hd-btn">
<view class="u-m-r-40 btn" @click="call()">
<text class="ym-custom ym-custom-phone u-font-40" />
</view>
<view class="u-m-l-40 btn" @click="toIm()">
<text class="ym-custom ym-custom-comment u-font-40" />
</view>
</view>
</view>
<view class="u-p-l-20 u-p-r-20">
<u-cell-group>
<u-cell-item title="手机号" :value="userData.mobilePhone || '未填写'" :arrow="false"
:title-style="titleStyle">
</u-cell-item>
<u-cell-item title="邮箱" :value="userData.email || '未填写'" :arrow="false" :title-style="titleStyle">
</u-cell-item>
<u-cell-item title="岗位" :value="userData.position || '未填写'" :arrow="false" :title-style="titleStyle">
</u-cell-item>
</u-cell-group>
</view>
</view>
</template>
<script>
import {
getUesrDetail
} from '@/api/common.js'
export default {
data() {
return {
userData: {},
titleStyle: {
color: '#303133'
},
}
},
computed: {
baseURL() {
return this.define.baseURL
}
},
onLoad(e) {
this.userData = JSON.parse(decodeURIComponent(e.data))
},
methods: {
call() {
if (!this.userData.mobilePhone) return
uni.makePhoneCall({
phoneNumber: this.userData.mobilePhone
})
},
toIm() {
const userData = this.userData
const name = userData.realName + '/' + userData.account
uni.$emit('updateMsgNum', userData.id)
uni.navigateTo({
url: '/pages/message/im/index?name=' + name + '&formUserId=' + userData.id + '&headIcon=' +
userData.headIcon
})
}
}
}
</script>
<style lang="scss">
.userDetail-v {
:deep(.u-cell) {
height: 112rpx;
.u-cell__value {
color: #606266;
white-space: nowrap;
width: 400rpx;
overflow-x: auto;
}
}
:deep(uni-text) {
white-space: nowrap !important;
}
.userDetail-hd {
height: 482rpx;
background-color: #f0f2f6;
color: #FFFFFF;
align-items: center;
}
.name {
// font-weight: 700;
color: #303133;
}
.positionName {
color: #909399;
width: 400rpx;
text-align: center;
white-space: nowrap !important;
overflow: hidden;
text-overflow: ellipsis;
}
.userDetail-hd-btn {
.btn {
width: 84rpx;
height: 84rpx;
border: 2rpx solid #606266;
border-radius: 50%;
text-align: center;
line-height: 80rpx;
color: #606266;
}
}
}
</style>