@ -0,0 +1 @@ |
|||||||
|
unpackage |
@ -0,0 +1,16 @@ |
|||||||
|
{ // launch.json 配置了启动调试时相关设置,configurations下节点名称可为 app-plus/h5/mp-weixin/mp-baidu/mp-alipay/mp-qq/mp-toutiao/mp-360/ |
||||||
|
// launchtype项可配置值为local或remote, local代表前端连本地云函数,remote代表前端连云端云函数 |
||||||
|
"version": "0.0", |
||||||
|
"configurations": [{ |
||||||
|
"default" : |
||||||
|
{ |
||||||
|
"launchtype" : "local" |
||||||
|
}, |
||||||
|
"mp-weixin" : |
||||||
|
{ |
||||||
|
"launchtype" : "local" |
||||||
|
}, |
||||||
|
"type" : "uniCloud" |
||||||
|
} |
||||||
|
] |
||||||
|
} |
@ -0,0 +1,36 @@ |
|||||||
|
<script> |
||||||
|
export default { |
||||||
|
onLaunch: function() { |
||||||
|
// uni.setEnableDebug({ |
||||||
|
// enableDebug: true |
||||||
|
// }) |
||||||
|
}, |
||||||
|
onShow: function() { |
||||||
|
console.log('App Launch'); |
||||||
|
const updateManager = uni.getUpdateManager(); |
||||||
|
// 检查小程序是否有新版本发布 |
||||||
|
updateManager.onCheckForUpdate(function (res) { |
||||||
|
// 请求完新版本信息的回调 |
||||||
|
console.log('onCheckForUpdate', res.hasUpdate); |
||||||
|
}); |
||||||
|
|
||||||
|
// 小程序有新版本,则静默下载新版本,做好更新准备 |
||||||
|
updateManager.onUpdateReady(function (res) { |
||||||
|
updateManager.applyUpdate() |
||||||
|
}); |
||||||
|
|
||||||
|
updateManager.onUpdateFailed(function (res) { |
||||||
|
console.log('onUpdateFailed', res); |
||||||
|
// 新的版本下载失败 |
||||||
|
uni.showModal({ |
||||||
|
title: '已经有新版本了哟~', |
||||||
|
content: '新版本已经上线啦~,请您删除当前小程序,重新搜索打开哟~' |
||||||
|
}); |
||||||
|
}) |
||||||
|
} |
||||||
|
} |
||||||
|
</script> |
||||||
|
|
||||||
|
<style lang="scss"> |
||||||
|
@import '@/uni_modules/uni-scss/index.scss'; |
||||||
|
</style> |
@ -0,0 +1,54 @@ |
|||||||
|
import request from '@/apis/request.js' |
||||||
|
const { get, post } = request |
||||||
|
|
||||||
|
export const queryCustomer = (data) => { |
||||||
|
return post('nakadai/nakadai/customer/queryCustomer', data) |
||||||
|
} |
||||||
|
|
||||||
|
export const list = (data) => { |
||||||
|
return post('nakadai/nakadai/applets/customer/getCustomerListBasedOnBusinessManagerId', data) |
||||||
|
} |
||||||
|
|
||||||
|
export const all = (data) => { |
||||||
|
return post('nakadai/nakadai/applets/customer/customerList', data) |
||||||
|
} |
||||||
|
|
||||||
|
export const queryCustomerDetails = (data) => { |
||||||
|
return get('nakadai/nakadai/customer/queryCustomerDetails', data) |
||||||
|
} |
||||||
|
|
||||||
|
export const querySchool = (data) => { |
||||||
|
return get('nakadai/nakadai/school/querySchool', data) |
||||||
|
} |
||||||
|
|
||||||
|
export const queryIndustryClass = (data) => { |
||||||
|
return get('nakadai/nakadai/hrIndustryClass/queryIndustryClass', data) |
||||||
|
} |
||||||
|
|
||||||
|
export const queryIndustry = (data) => { |
||||||
|
return get('nakadai/nakadai/hrIndustry/queryIndustry', data) |
||||||
|
} |
||||||
|
|
||||||
|
export const queryCustomerIsExists = (data) => { |
||||||
|
return get('nakadai/nakadai/customer/queryCustomerIsExists', data) |
||||||
|
} |
||||||
|
|
||||||
|
export const addCustomer = (data) => { |
||||||
|
return post('nakadai/nakadai/customer/addCustomer', data) |
||||||
|
} |
||||||
|
|
||||||
|
export const updateCustomer = (data) => { |
||||||
|
return post('nakadai/nakadai/customer/updateCustomer', data) |
||||||
|
} |
||||||
|
|
||||||
|
export const getProductsSubscribedByCustomers = (data) => { |
||||||
|
return get('nakadai/nakadai/customer/getProductsSubscribedByCustomers', data) |
||||||
|
} |
||||||
|
|
||||||
|
export const getTeamsByAccountId = (data) => { |
||||||
|
return post('nakadai/nakadai/applets/customer/getTeamsByAccountId', data) |
||||||
|
} |
||||||
|
|
||||||
|
export const getTheBusinessManagerIdsUnderTheTeam = id => { |
||||||
|
return post(`nakadai/nakadai/applets/customer/getTheBusinessManagerIdsUnderTheTeam?id=${id}`) |
||||||
|
} |
@ -0,0 +1,38 @@ |
|||||||
|
import request from '@/apis/request.js' |
||||||
|
const { get, post } = request |
||||||
|
|
||||||
|
export const getOrderOtherTime = (data) => { |
||||||
|
return post('nakadai/nakadai/orderOther/getOrderOtherTime', data) |
||||||
|
} |
||||||
|
|
||||||
|
export const add = (data) => { |
||||||
|
return post('nakadai/nakadai/order/add', data) |
||||||
|
} |
||||||
|
|
||||||
|
export const update = (data) => { |
||||||
|
return post('nakadai/nakadai/order/update', data) |
||||||
|
} |
||||||
|
|
||||||
|
export const getDetail = (data) => { |
||||||
|
return get('nakadai/nakadai/order/get', data) |
||||||
|
} |
||||||
|
|
||||||
|
export const renew = (data) => { |
||||||
|
return post('nakadai/nakadai/orderOther/renew', data) |
||||||
|
} |
||||||
|
|
||||||
|
export const list = (data) => { |
||||||
|
return post('nakadai/nakadai/applets/order/orderList', data) |
||||||
|
} |
||||||
|
|
||||||
|
export const orderList = (data) => { |
||||||
|
return post('nakadai/nakadai/order/list', data) |
||||||
|
} |
||||||
|
|
||||||
|
export const del = (data) => { |
||||||
|
return post('nakadai/nakadai/order/delete', data) |
||||||
|
} |
||||||
|
|
||||||
|
export const miniProgramOrderRecord = (data) => { |
||||||
|
return post('nakadai/nakadai/applets/order/miniProgramOrderRecord', data) |
||||||
|
} |
@ -0,0 +1,26 @@ |
|||||||
|
import request from '@/apis/request.js' |
||||||
|
const { get, post } = request |
||||||
|
|
||||||
|
export const savePartnerAccount = (data) => { |
||||||
|
return post('nakadai/nakadai/partnerAccount/savePartnerAccount', data) |
||||||
|
} |
||||||
|
|
||||||
|
export const teamList = (data) => { |
||||||
|
return post('nakadai/nakadai/partnerAccount/partnerAccountList', data) |
||||||
|
} |
||||||
|
|
||||||
|
export const generateInvitationCode = accountId => { |
||||||
|
return post(`nakadai/nakadai/partnerAccount/generateInvitationCode?accountId=${accountId}`) |
||||||
|
} |
||||||
|
|
||||||
|
export const treeList = (data) => { |
||||||
|
return post('nakadai/nakadai/partnerClassification/treeList', data) |
||||||
|
} |
||||||
|
|
||||||
|
export const my = (data) => { |
||||||
|
return get('nakadai/nakadai/partner-team/my', data) |
||||||
|
} |
||||||
|
|
||||||
|
export const mailFileSend = (data) => { |
||||||
|
return post('nakadai/nakadai/partnerAccount/mailFileSend', data) |
||||||
|
} |
@ -0,0 +1,6 @@ |
|||||||
|
import request from '@/apis/request.js' |
||||||
|
const { get, post } = request |
||||||
|
|
||||||
|
export const AppletsDataProductList = (data) => { |
||||||
|
return post('nakadai/nakadai/dataProduct/AppletsDataProductList', data) |
||||||
|
} |
@ -0,0 +1,52 @@ |
|||||||
|
import request from '@/apis/request.js' |
||||||
|
const { get, post } = request |
||||||
|
|
||||||
|
export const login = (data) => { |
||||||
|
return post('users/users/user/weChatAppletCallback', data) |
||||||
|
} |
||||||
|
|
||||||
|
export const userBinding = (data) => { |
||||||
|
return post('users/users/user/userBinding', data) |
||||||
|
} |
||||||
|
|
||||||
|
export const examinePassword = (data) => { |
||||||
|
return post('users/users/userAccount/examinePassword', data) |
||||||
|
} |
||||||
|
|
||||||
|
export const getUserRolesPermissionMenu = (data) => { |
||||||
|
return get('users/users/user-role/getUserRolesPermissionMenu', data) |
||||||
|
} |
||||||
|
|
||||||
|
export const updatePersonCenter = (data) => { |
||||||
|
return post('users/users/userAccount/updatePersonCenter', data) |
||||||
|
} |
||||||
|
|
||||||
|
export const queryUserInfoDetails = () => { |
||||||
|
return get('users/users/userAccount/queryUserInfoDetails') |
||||||
|
} |
||||||
|
|
||||||
|
export const updateMyEmail = (data) => { |
||||||
|
return post('nakadai/nakadai/partner-team/updateMyEmail', data) |
||||||
|
} |
||||||
|
|
||||||
|
export const mailCodeSend = (data) => { |
||||||
|
return post('nakadai/nakadai/partner-team/mailCodeSend', data) |
||||||
|
} |
||||||
|
|
||||||
|
export const changeAccount = account => { |
||||||
|
return post(`users/users/applets/mine/changeAccount?account=${account}`) |
||||||
|
} |
||||||
|
|
||||||
|
export const changePhoneNumber = (phone, code) => { |
||||||
|
return post(`users/users/applets/mine/changePhoneNumber?phone=${phone}&code=${code}`) |
||||||
|
} |
||||||
|
|
||||||
|
export const checkIfAnAccountExists = account => { |
||||||
|
return post(`users/users/applets/mine/checkIfAnAccountExists?account=${account}`) |
||||||
|
} |
||||||
|
|
||||||
|
export const checkIfThePhoneNumberExists = phone => { |
||||||
|
return post(`users/users/applets/mine/checkIfThePhoneNumberExists?phone=${phone}`) |
||||||
|
} |
||||||
|
|
||||||
|
export const updateUserAvatars = `http://39.108.250.202:9000/users/users/userAccount/updateUserAvatars` |
@ -0,0 +1,89 @@ |
|||||||
|
import config from '@/config/request' |
||||||
|
let HTTP_COUNT = 0 // loading次数
|
||||||
|
|
||||||
|
const request = options => { |
||||||
|
HTTP_COUNT++ |
||||||
|
if (config.showLoading) { |
||||||
|
// 请求数据时的loading
|
||||||
|
// uni.showToast({
|
||||||
|
// title: '加载中',
|
||||||
|
// duration: 200,
|
||||||
|
// icon: 'loading'
|
||||||
|
// })
|
||||||
|
} |
||||||
|
const header = Object.assign({}, config.headers, { |
||||||
|
token: uni.getStorageSync('token') |
||||||
|
}) |
||||||
|
const otherUrl = ['getTeamsByAccountId'] |
||||||
|
return new Promise((resolve, reject)=>{ |
||||||
|
const { url } = options |
||||||
|
uni.request({ |
||||||
|
header, |
||||||
|
// url: (otherUrl.map(e => config.baseURL.includes(e)) ? 'http://192.168.31.137:9000/' : config.baseURL) + url,
|
||||||
|
url: config.baseURL + url, |
||||||
|
method: options.method || 'GET', // 请求类型,默认为GET
|
||||||
|
data: options.data || {}, // 请求参数,默认空对象
|
||||||
|
success: ({ data }) => { |
||||||
|
const { status, message } = data |
||||||
|
// 状态判断,根据后台定义并提示
|
||||||
|
if (status === 200) { |
||||||
|
resolve(data) |
||||||
|
} else if (status == 401) { |
||||||
|
// 登录过期
|
||||||
|
uni.clearStorageSync() |
||||||
|
uni.showToast({ |
||||||
|
title: message, |
||||||
|
icon: 'none' |
||||||
|
}) |
||||||
|
setTimeout(() => { |
||||||
|
uni.navigateTo({ |
||||||
|
url: '../login/login' |
||||||
|
}) |
||||||
|
}, 1500) |
||||||
|
reject(data) |
||||||
|
} else if (!status) { |
||||||
|
resolve(data) |
||||||
|
} else { |
||||||
|
uni.showToast({ |
||||||
|
title: message, |
||||||
|
icon: 'none' |
||||||
|
}) |
||||||
|
reject(data) |
||||||
|
} |
||||||
|
}, |
||||||
|
fail: err => { |
||||||
|
uni.showToast({ |
||||||
|
title: '请求失败!', |
||||||
|
icon: 'none' |
||||||
|
}) |
||||||
|
reject(err) |
||||||
|
}, |
||||||
|
complete: () => { |
||||||
|
if (config.showLoading) { |
||||||
|
// HTTP_COUNT--
|
||||||
|
// HTTP_COUNT || uni.hideLoading()
|
||||||
|
} |
||||||
|
} |
||||||
|
}) |
||||||
|
}) |
||||||
|
} |
||||||
|
|
||||||
|
const get = (url, data, options = {}) => { |
||||||
|
options.method = 'GET' |
||||||
|
options.data = data |
||||||
|
options.url = url |
||||||
|
return request(options) |
||||||
|
} |
||||||
|
|
||||||
|
const post = (url, data, options = {}) => { |
||||||
|
options.method = 'POST' |
||||||
|
options.data = data |
||||||
|
options.url = url |
||||||
|
return request(options) |
||||||
|
} |
||||||
|
|
||||||
|
export default { |
||||||
|
request, |
||||||
|
get, |
||||||
|
post |
||||||
|
} |
@ -0,0 +1,40 @@ |
|||||||
|
<template> |
||||||
|
<view class="none"> |
||||||
|
<image src="../../static/image/none.png" mode="widthFix"></image> |
||||||
|
<view class="text">{{ text }}</view> |
||||||
|
</view> |
||||||
|
</template> |
||||||
|
|
||||||
|
<script> |
||||||
|
export default { |
||||||
|
props: { |
||||||
|
text: { |
||||||
|
type: String, |
||||||
|
default: '暂无数据' |
||||||
|
}, |
||||||
|
}, |
||||||
|
data() { |
||||||
|
return { |
||||||
|
|
||||||
|
} |
||||||
|
}, |
||||||
|
methods: { |
||||||
|
|
||||||
|
} |
||||||
|
} |
||||||
|
</script> |
||||||
|
|
||||||
|
<style scoped lang="scss"> |
||||||
|
.none { |
||||||
|
padding-top: 100rpx; |
||||||
|
text-align: center; |
||||||
|
image { |
||||||
|
width: 426rpx; |
||||||
|
margin-bottom: 52rpx; |
||||||
|
} |
||||||
|
.text { |
||||||
|
font-size: 28rpx; |
||||||
|
color: #333; |
||||||
|
} |
||||||
|
} |
||||||
|
</style> |
@ -0,0 +1,130 @@ |
|||||||
|
<template> |
||||||
|
<view |
||||||
|
class="u-mask" |
||||||
|
hover-stop-propagation |
||||||
|
:style="[maskStyle, zoomStyle]" |
||||||
|
@tap="click" |
||||||
|
@touchmove.stop.prevent="() => {}" |
||||||
|
:class="{ |
||||||
|
'u-mask-zoom': zoom, |
||||||
|
'u-mask-show': show, |
||||||
|
}" |
||||||
|
> |
||||||
|
<slot /> |
||||||
|
</view> |
||||||
|
</template> |
||||||
|
|
||||||
|
<script> |
||||||
|
/** |
||||||
|
* mask 遮罩 |
||||||
|
* @description 创建一个遮罩层,用于强调特定的页面元素,并阻止用户对遮罩下层的内容进行操作,一般用于弹窗场景 |
||||||
|
* @tutorial https://www.uviewui.com/components/mask.html |
||||||
|
* @property {Boolean} show 是否显示遮罩(默认false) |
||||||
|
* @property {String Number} z-index z-index 层级(默认1070) |
||||||
|
* @property {Object} custom-style 自定义样式对象,见上方说明 |
||||||
|
* @property {String Number} duration 动画时长,单位毫秒(默认300) |
||||||
|
* @property {Boolean} zoom 是否使用scale对这招进行缩放(默认true) |
||||||
|
* @property {Boolean} mask-click-able 遮罩是否可点击,为false时点击不会发送click事件(默认true) |
||||||
|
* @event {Function} click mask-click-able为true时,点击遮罩发送此事件 |
||||||
|
* @example <u-mask :show="show" @click="show = false"></u-mask> |
||||||
|
*/ |
||||||
|
export default { |
||||||
|
name: "u-mask", |
||||||
|
props: { |
||||||
|
// 是否显示遮罩 |
||||||
|
show: { |
||||||
|
type: Boolean, |
||||||
|
default: false, |
||||||
|
}, |
||||||
|
// 层级z-index |
||||||
|
zIndex: { |
||||||
|
type: [Number, String], |
||||||
|
default: "", |
||||||
|
}, |
||||||
|
// 用户自定义样式 |
||||||
|
customStyle: { |
||||||
|
type: Object, |
||||||
|
default() { |
||||||
|
return {}; |
||||||
|
}, |
||||||
|
}, |
||||||
|
// 遮罩的动画样式, 是否使用使用zoom进行scale进行缩放 |
||||||
|
zoom: { |
||||||
|
type: Boolean, |
||||||
|
default: true, |
||||||
|
}, |
||||||
|
// 遮罩的过渡时间,单位为ms |
||||||
|
duration: { |
||||||
|
type: [Number, String], |
||||||
|
default: 300, |
||||||
|
}, |
||||||
|
// 是否可以通过点击遮罩进行关闭 |
||||||
|
maskClickAble: { |
||||||
|
type: Boolean, |
||||||
|
default: true, |
||||||
|
}, |
||||||
|
}, |
||||||
|
data() { |
||||||
|
return { |
||||||
|
zoomStyle: { |
||||||
|
transform: "", |
||||||
|
}, |
||||||
|
scale: "scale(1.2, 1.2)", |
||||||
|
}; |
||||||
|
}, |
||||||
|
watch: { |
||||||
|
show(n) { |
||||||
|
if (n && this.zoom) { |
||||||
|
// 当展示遮罩的时候,设置scale为1,达到缩小(原来为1.2)的效果 |
||||||
|
this.zoomStyle.transform = "scale(1, 1)"; |
||||||
|
} else if (!n && this.zoom) { |
||||||
|
// 当隐藏遮罩的时候,设置scale为1.2,达到放大(因为显示遮罩时已重置为1)的效果 |
||||||
|
this.zoomStyle.transform = this.scale; |
||||||
|
} |
||||||
|
}, |
||||||
|
}, |
||||||
|
computed: { |
||||||
|
maskStyle() { |
||||||
|
let style = {}; |
||||||
|
style.backgroundColor = "rgba(0, 0, 0, 0.6)"; |
||||||
|
if (this.show) |
||||||
|
style.zIndex = this.zIndex ? this.zIndex : this.$u.zIndex.mask; |
||||||
|
else style.zIndex = -1; |
||||||
|
style.transition = `all ${this.duration / 1000}s ease-in-out`; |
||||||
|
// 判断用户传递的对象是否为空,不为空就进行合并 |
||||||
|
if (Object.keys(this.customStyle).length) |
||||||
|
style = { |
||||||
|
...style, |
||||||
|
...this.customStyle, |
||||||
|
}; |
||||||
|
return style; |
||||||
|
}, |
||||||
|
}, |
||||||
|
methods: { |
||||||
|
click() { |
||||||
|
if (!this.maskClickAble) return; |
||||||
|
this.$emit("click"); |
||||||
|
}, |
||||||
|
}, |
||||||
|
}; |
||||||
|
</script> |
||||||
|
|
||||||
|
<style lang="scss" scoped> |
||||||
|
.u-mask { |
||||||
|
position: fixed; |
||||||
|
top: 0; |
||||||
|
left: 0; |
||||||
|
right: 0; |
||||||
|
bottom: 0; |
||||||
|
opacity: 0; |
||||||
|
transition: transform 0.3s; |
||||||
|
} |
||||||
|
|
||||||
|
.u-mask-show { |
||||||
|
opacity: 1; |
||||||
|
} |
||||||
|
|
||||||
|
.u-mask-zoom { |
||||||
|
transform: scale(1.2, 1.2); |
||||||
|
} |
||||||
|
</style> |
@ -0,0 +1,510 @@ |
|||||||
|
<template> |
||||||
|
<view |
||||||
|
v-if="visibleSync" |
||||||
|
:style="[ |
||||||
|
customStyle, |
||||||
|
{ |
||||||
|
zIndex: uZindex - 1, |
||||||
|
}, |
||||||
|
]" |
||||||
|
class="u-drawer" |
||||||
|
hover-stop-propagation |
||||||
|
> |
||||||
|
<z-mask |
||||||
|
:duration="duration" |
||||||
|
:custom-style="maskCustomStyle" |
||||||
|
:maskClickAble="maskCloseAble" |
||||||
|
:z-index="uZindex - 2" |
||||||
|
:show="showDrawer && mask" |
||||||
|
@click="maskClick" |
||||||
|
></z-mask> |
||||||
|
<view |
||||||
|
class="u-drawer-content" |
||||||
|
@tap="modeCenterClose(mode)" |
||||||
|
:class="[ |
||||||
|
safeAreaInsetBottom ? 'safe-area-inset-bottom' : '', |
||||||
|
'u-drawer-' + mode, |
||||||
|
showDrawer ? 'u-drawer-content-visible' : '', |
||||||
|
zoom && mode == 'center' ? 'u-animation-zoom' : '', |
||||||
|
]" |
||||||
|
@transitionend="transitionend" |
||||||
|
@touchmove.stop.prevent |
||||||
|
@tap.stop.prevent |
||||||
|
:style="[style]" |
||||||
|
> |
||||||
|
<view |
||||||
|
class="u-mode-center-box" |
||||||
|
@tap.stop.prevent |
||||||
|
@touchmove.stop.prevent |
||||||
|
v-if="mode == 'center'" |
||||||
|
:style="[centerStyle]" |
||||||
|
> |
||||||
|
<u-icon |
||||||
|
@click="close" |
||||||
|
v-if="closeable" |
||||||
|
class="u-close" |
||||||
|
:class="['u-close--' + closeIconPos]" |
||||||
|
:name="closeIcon" |
||||||
|
:color="closeIconColor" |
||||||
|
:size="closeIconSize" |
||||||
|
></u-icon> |
||||||
|
<scroll-view class="u-drawer__scroll-view" scroll-y="true"> |
||||||
|
<slot /> |
||||||
|
</scroll-view> |
||||||
|
<slot name="fixedContent" /> |
||||||
|
</view> |
||||||
|
<scroll-view class="u-drawer__scroll-view" scroll-y="true" v-else> |
||||||
|
<slot /> |
||||||
|
</scroll-view> |
||||||
|
<view @tap="close" class="u-close" :class="['u-close--' + closeIconPos]"> |
||||||
|
<u-icon |
||||||
|
v-if="mode != 'center' && closeable" |
||||||
|
:name="closeIcon" |
||||||
|
:color="closeIconColor" |
||||||
|
:size="closeIconSize" |
||||||
|
></u-icon> |
||||||
|
</view> |
||||||
|
</view> |
||||||
|
</view> |
||||||
|
</template> |
||||||
|
|
||||||
|
<script> |
||||||
|
/** |
||||||
|
* popup 弹窗 |
||||||
|
* @description 弹出层容器,用于展示弹窗、信息提示等内容,支持上、下、左、右和中部弹出。组件只提供容器,内部内容由用户自定义 |
||||||
|
* @tutorial https://www.uviewui.com/components/popup.html |
||||||
|
* @property {String} mode 弹出方向(默认left) |
||||||
|
* @property {Boolean} mask 是否显示遮罩(默认true) |
||||||
|
* @property {Stringr | Number} length mode=left | 见官网说明(默认auto) |
||||||
|
* @property {Boolean} zoom 是否开启缩放动画,只在mode为center时有效(默认true) |
||||||
|
* @property {Boolean} safe-area-inset-bottom 是否开启底部安全区适配(默认false) |
||||||
|
* @property {Boolean} mask-close-able 点击遮罩是否可以关闭弹出层(默认true) |
||||||
|
* @property {Object} custom-style 用户自定义样式 |
||||||
|
* @property {Stringr | Number} negative-top 中部弹出时,往上偏移的值 |
||||||
|
* @property {Numberr | String} border-radius 弹窗圆角值(默认0) |
||||||
|
* @property {Numberr | String} z-index 弹出内容的z-index值(默认1075) |
||||||
|
* @property {Boolean} closeable 是否显示关闭图标(默认false) |
||||||
|
* @property {String} close-icon 关闭图标的名称,只能uView的内置图标 |
||||||
|
* @property {String} close-icon-pos 自定义关闭图标位置(默认top-right) |
||||||
|
* @property {String} close-icon-color 关闭图标的颜色(默认#909399) |
||||||
|
* @property {Number | String} close-icon-size 关闭图标的大小,单位rpx(默认30) |
||||||
|
* @event {Function} open 弹出层打开 |
||||||
|
* @event {Function} close 弹出层收起 |
||||||
|
* @example <u-popup v-model="show"><view>出淤泥而不染,濯清涟而不妖</view></u-popup> |
||||||
|
*/ |
||||||
|
import ZMask from "./mask.vue"; |
||||||
|
export default { |
||||||
|
name: "popup", |
||||||
|
components: { |
||||||
|
ZMask, |
||||||
|
}, |
||||||
|
props: { |
||||||
|
/** |
||||||
|
* 显示状态 |
||||||
|
*/ |
||||||
|
show: { |
||||||
|
type: Boolean, |
||||||
|
default: false, |
||||||
|
}, |
||||||
|
/** |
||||||
|
* 弹出方向,left|right|top|bottom|center |
||||||
|
*/ |
||||||
|
mode: { |
||||||
|
type: String, |
||||||
|
default: "left", |
||||||
|
}, |
||||||
|
/** |
||||||
|
* 是否显示遮罩 |
||||||
|
*/ |
||||||
|
mask: { |
||||||
|
type: Boolean, |
||||||
|
default: true, |
||||||
|
}, |
||||||
|
// 抽屉的宽度(mode=left|right),或者高度(mode=top|bottom),单位rpx,或者"auto" |
||||||
|
// 或者百分比"50%",表示由内容撑开高度或者宽度 |
||||||
|
length: { |
||||||
|
type: [Number, String], |
||||||
|
default: "auto", |
||||||
|
}, |
||||||
|
// 是否开启缩放动画,只在mode=center时有效 |
||||||
|
zoom: { |
||||||
|
type: Boolean, |
||||||
|
default: true, |
||||||
|
}, |
||||||
|
// 是否开启底部安全区适配,开启的话,会在iPhoneX机型底部添加一定的内边距 |
||||||
|
safeAreaInsetBottom: { |
||||||
|
type: Boolean, |
||||||
|
default: false, |
||||||
|
}, |
||||||
|
// 是否可以通过点击遮罩进行关闭 |
||||||
|
maskCloseAble: { |
||||||
|
type: Boolean, |
||||||
|
default: true, |
||||||
|
}, |
||||||
|
// 用户自定义样式 |
||||||
|
customStyle: { |
||||||
|
type: Object, |
||||||
|
default() { |
||||||
|
return {}; |
||||||
|
}, |
||||||
|
}, |
||||||
|
value: { |
||||||
|
type: Boolean, |
||||||
|
default: false, |
||||||
|
}, |
||||||
|
// 此为内部参数,不在文档对外使用,为了解决Picker和keyboard等融合了弹窗的组件 |
||||||
|
// 对v-model双向绑定多层调用造成报错不能修改props值的问题 |
||||||
|
popup: { |
||||||
|
type: Boolean, |
||||||
|
default: true, |
||||||
|
}, |
||||||
|
// 显示显示弹窗的圆角,单位rpx |
||||||
|
borderRadius: { |
||||||
|
type: [Number, String], |
||||||
|
default: 0, |
||||||
|
}, |
||||||
|
zIndex: { |
||||||
|
type: [Number, String], |
||||||
|
default: "10075", |
||||||
|
}, |
||||||
|
// 是否显示关闭图标 |
||||||
|
closeable: { |
||||||
|
type: Boolean, |
||||||
|
default: false, |
||||||
|
}, |
||||||
|
// 关闭图标的名称,只能uView的内置图标 |
||||||
|
closeIcon: { |
||||||
|
type: String, |
||||||
|
default: "close", |
||||||
|
}, |
||||||
|
// 自定义关闭图标位置,top-left为左上角,top-right为右上角,bottom-left为左下角,bottom-right为右下角 |
||||||
|
closeIconPos: { |
||||||
|
type: String, |
||||||
|
default: "top-right", |
||||||
|
}, |
||||||
|
// 关闭图标的颜色 |
||||||
|
closeIconColor: { |
||||||
|
type: String, |
||||||
|
default: "#909399", |
||||||
|
}, |
||||||
|
// 关闭图标的大小,单位rpx |
||||||
|
closeIconSize: { |
||||||
|
type: [String, Number], |
||||||
|
default: "30", |
||||||
|
}, |
||||||
|
// 宽度,只对左,右,中部弹出时起作用,单位rpx,或者"auto" |
||||||
|
// 或者百分比"50%",表示由内容撑开高度或者宽度,优先级高于length参数 |
||||||
|
width: { |
||||||
|
type: String, |
||||||
|
default: "", |
||||||
|
}, |
||||||
|
// 高度,只对上,下,中部弹出时起作用,单位rpx,或者"auto" |
||||||
|
// 或者百分比"50%",表示由内容撑开高度或者宽度,优先级高于length参数 |
||||||
|
height: { |
||||||
|
type: String, |
||||||
|
default: "", |
||||||
|
}, |
||||||
|
// 给一个负的margin-top,往上偏移,避免和键盘重合的情况,仅在mode=center时有效 |
||||||
|
negativeTop: { |
||||||
|
type: [String, Number], |
||||||
|
default: 0, |
||||||
|
}, |
||||||
|
// 遮罩的样式,一般用于修改遮罩的透明度 |
||||||
|
maskCustomStyle: { |
||||||
|
type: Object, |
||||||
|
default() { |
||||||
|
return {}; |
||||||
|
}, |
||||||
|
}, |
||||||
|
// 遮罩打开或收起的动画过渡时间,单位ms |
||||||
|
duration: { |
||||||
|
type: [String, Number], |
||||||
|
default: 250, |
||||||
|
}, |
||||||
|
// 中间弹窗的背景颜色值 |
||||||
|
centerPupBg: { |
||||||
|
type: String, |
||||||
|
default: "#fff", |
||||||
|
}, |
||||||
|
bgColor: { |
||||||
|
type: String, |
||||||
|
default: "#fff", |
||||||
|
}, |
||||||
|
}, |
||||||
|
|
||||||
|
data() { |
||||||
|
return { |
||||||
|
visibleSync: false, |
||||||
|
showDrawer: false, |
||||||
|
timer: null, |
||||||
|
closeFromInner: false, // value的值改变,是发生在内部还是外部 |
||||||
|
}; |
||||||
|
}, |
||||||
|
computed: { |
||||||
|
// 根据mode的位置,设定其弹窗的宽度(mode = left|right),或者高度(mode = top|bottom) |
||||||
|
style() { |
||||||
|
let style = {}; |
||||||
|
// 如果是左边或者上边弹出时,需要给translate设置为负值,用于隐藏 |
||||||
|
if (this.mode == "left" || this.mode == "right") { |
||||||
|
style = { |
||||||
|
width: this.width |
||||||
|
? this.getUnitValue(this.width) |
||||||
|
: this.getUnitValue(this.length), |
||||||
|
height: "100%", |
||||||
|
transform: `translate3D(${ |
||||||
|
this.mode == "left" ? "-100%" : "100%" |
||||||
|
},0px,0px)`, |
||||||
|
background: this.bgColor, |
||||||
|
}; |
||||||
|
} else if (this.mode == "top" || this.mode == "bottom") { |
||||||
|
style = { |
||||||
|
width: "100%", |
||||||
|
height: this.height |
||||||
|
? this.getUnitValue(this.height) |
||||||
|
: this.getUnitValue(this.length), |
||||||
|
transform: `translate3D(0px,${ |
||||||
|
this.mode == "top" ? "-100%" : "100%" |
||||||
|
},0px)`, |
||||||
|
background: this.bgColor, |
||||||
|
}; |
||||||
|
} |
||||||
|
style.zIndex = this.uZindex; |
||||||
|
// 如果用户设置了borderRadius值,添加弹窗的圆角 |
||||||
|
if (this.borderRadius) { |
||||||
|
switch (this.mode) { |
||||||
|
case "left": |
||||||
|
style.borderRadius = `0 ${this.borderRadius}rpx ${this.borderRadius}rpx 0`; |
||||||
|
break; |
||||||
|
case "top": |
||||||
|
style.borderRadius = `0 0 ${this.borderRadius}rpx ${this.borderRadius}rpx`; |
||||||
|
break; |
||||||
|
case "right": |
||||||
|
style.borderRadius = `${this.borderRadius}rpx 0 0 ${this.borderRadius}rpx`; |
||||||
|
break; |
||||||
|
case "bottom": |
||||||
|
style.borderRadius = `${this.borderRadius}rpx ${this.borderRadius}rpx 0 0`; |
||||||
|
break; |
||||||
|
default: |
||||||
|
} |
||||||
|
// 不加可能圆角无效 |
||||||
|
style.overflow = "hidden"; |
||||||
|
} |
||||||
|
if (this.duration) |
||||||
|
style.transition = `all ${this.duration / 1000}s linear`; |
||||||
|
return style; |
||||||
|
}, |
||||||
|
// 中部弹窗的特有样式 |
||||||
|
centerStyle() { |
||||||
|
let style = {}; |
||||||
|
style.width = this.width |
||||||
|
? this.getUnitValue(this.width) |
||||||
|
: this.getUnitValue(this.length); |
||||||
|
// 中部弹出的模式,如果没有设置高度,就用auto值,由内容撑开高度 |
||||||
|
style.height = this.height ? this.getUnitValue(this.height) : "auto"; |
||||||
|
style.zIndex = this.uZindex; |
||||||
|
// style.marginTop = `-${this.$u.addUnit(this.negativeTop)}`; |
||||||
|
style.background = this.centerPupBg; |
||||||
|
if (this.borderRadius) { |
||||||
|
style.borderRadius = `${this.borderRadius}rpx`; |
||||||
|
// 不加可能圆角无效 |
||||||
|
style.overflow = "hidden"; |
||||||
|
} |
||||||
|
return style; |
||||||
|
}, |
||||||
|
// 计算整理后的z-index值 |
||||||
|
uZindex() { |
||||||
|
return this.zIndex ? this.zIndex : this.$u.zIndex.popup; |
||||||
|
}, |
||||||
|
}, |
||||||
|
watch: { |
||||||
|
value(val) { |
||||||
|
if (val) { |
||||||
|
this.open(); |
||||||
|
} else if (!this.closeFromInner) { |
||||||
|
this.close(); |
||||||
|
} |
||||||
|
this.closeFromInner = false; |
||||||
|
}, |
||||||
|
}, |
||||||
|
mounted() { |
||||||
|
// 组件渲染完成时,检查value是否为true,如果是,弹出popup |
||||||
|
this.value && this.open(); |
||||||
|
}, |
||||||
|
methods: { |
||||||
|
// 动画结束回调 |
||||||
|
transitionend(e) { |
||||||
|
// console.log(e, "动画结束popup"); |
||||||
|
}, |
||||||
|
// 判断传入的值,是否带有单位,如果没有,就默认用rpx单位 |
||||||
|
getUnitValue(val) { |
||||||
|
if (/(%|px|rpx|auto)$/.test(val)) return val; |
||||||
|
else return val + "rpx"; |
||||||
|
}, |
||||||
|
// 遮罩被点击 |
||||||
|
maskClick() { |
||||||
|
this.close(); |
||||||
|
}, |
||||||
|
close() { |
||||||
|
// 标记关闭是内部发生的,否则修改了value值,导致watch中对value检测,导致再执行一遍close |
||||||
|
// 造成@close事件触发两次 |
||||||
|
this.closeFromInner = true; |
||||||
|
this.change("showDrawer", "visibleSync", false); |
||||||
|
}, |
||||||
|
// 中部弹出时,需要.u-drawer-content将居中内容,此元素会铺满屏幕,点击需要关闭弹窗 |
||||||
|
// 让其只在mode=center时起作用 |
||||||
|
modeCenterClose(mode) { |
||||||
|
if (mode != "center" || !this.maskCloseAble) return; |
||||||
|
this.close(); |
||||||
|
}, |
||||||
|
open() { |
||||||
|
this.change("visibleSync", "showDrawer", true); |
||||||
|
}, |
||||||
|
// 此处的原理是,关闭时先通过动画隐藏弹窗和遮罩,再移除整个组件 |
||||||
|
// 打开时,先渲染组件,延时一定时间再让遮罩和弹窗的动画起作用 |
||||||
|
change(param1, param2, status) { |
||||||
|
// 如果this.popup为false,意味着为picker,actionsheet等组件调用了popup组件 |
||||||
|
if (this.popup == true) { |
||||||
|
this.$emit("input", status); |
||||||
|
} |
||||||
|
this[param1] = status; |
||||||
|
if (status) { |
||||||
|
// #ifdef H5 || MP |
||||||
|
this.timer = setTimeout(() => { |
||||||
|
this[param2] = status; |
||||||
|
this.$emit(status ? "open" : "close"); |
||||||
|
}, 50); |
||||||
|
// #endif |
||||||
|
// #ifndef H5 || MP |
||||||
|
this.$nextTick(() => { |
||||||
|
this[param2] = status; |
||||||
|
this.$emit(status ? "open" : "close"); |
||||||
|
}); |
||||||
|
// #endif |
||||||
|
} else { |
||||||
|
this.timer = setTimeout(() => { |
||||||
|
this[param2] = status; |
||||||
|
this.$emit(status ? "open" : "close"); |
||||||
|
}, this.duration); |
||||||
|
} |
||||||
|
}, |
||||||
|
}, |
||||||
|
}; |
||||||
|
</script> |
||||||
|
|
||||||
|
<style scoped lang="scss"> |
||||||
|
@mixin vue-flex($direction: row) { |
||||||
|
/* #ifndef APP-NVUE */ |
||||||
|
display: flex; |
||||||
|
flex-direction: $direction; |
||||||
|
/* #endif */ |
||||||
|
} |
||||||
|
.u-drawer { |
||||||
|
/* #ifndef APP-NVUE */ |
||||||
|
display: block; |
||||||
|
/* #endif */ |
||||||
|
position: fixed; |
||||||
|
top: 0; |
||||||
|
left: 0; |
||||||
|
right: 0; |
||||||
|
bottom: 0; |
||||||
|
overflow: hidden; |
||||||
|
} |
||||||
|
|
||||||
|
.u-drawer-content { |
||||||
|
/* #ifndef APP-NVUE */ |
||||||
|
display: block; |
||||||
|
/* #endif */ |
||||||
|
position: absolute; |
||||||
|
z-index: 1003; |
||||||
|
transition: all 0.25s linear; |
||||||
|
} |
||||||
|
|
||||||
|
.u-drawer__scroll-view { |
||||||
|
width: 100%; |
||||||
|
height: 100%; |
||||||
|
} |
||||||
|
|
||||||
|
.u-drawer-left { |
||||||
|
top: 0; |
||||||
|
bottom: 0; |
||||||
|
left: 0; |
||||||
|
} |
||||||
|
|
||||||
|
.u-drawer-right { |
||||||
|
right: 0; |
||||||
|
top: 0; |
||||||
|
bottom: 0; |
||||||
|
} |
||||||
|
|
||||||
|
.u-drawer-top { |
||||||
|
top: 0; |
||||||
|
left: 0; |
||||||
|
right: 0; |
||||||
|
} |
||||||
|
|
||||||
|
.u-drawer-bottom { |
||||||
|
bottom: 0; |
||||||
|
left: 0; |
||||||
|
right: 0; |
||||||
|
} |
||||||
|
|
||||||
|
.u-drawer-center { |
||||||
|
@include vue-flex; |
||||||
|
flex-direction: column; |
||||||
|
bottom: 0; |
||||||
|
left: 0; |
||||||
|
right: 0; |
||||||
|
top: 0; |
||||||
|
justify-content: center; |
||||||
|
align-items: center; |
||||||
|
opacity: 0; |
||||||
|
z-index: 99999; |
||||||
|
} |
||||||
|
|
||||||
|
.u-mode-center-box { |
||||||
|
min-width: 100rpx; |
||||||
|
min-height: 100rpx; |
||||||
|
/* #ifndef APP-NVUE */ |
||||||
|
display: block; |
||||||
|
/* #endif */ |
||||||
|
position: relative; |
||||||
|
} |
||||||
|
|
||||||
|
.u-drawer-content-visible.u-drawer-center { |
||||||
|
transform: scale(1); |
||||||
|
opacity: 1; |
||||||
|
} |
||||||
|
|
||||||
|
.u-animation-zoom { |
||||||
|
transform: scale(1.15); |
||||||
|
} |
||||||
|
|
||||||
|
.u-drawer-content-visible { |
||||||
|
transform: translate3D(0px, 0px, 0px) !important; |
||||||
|
} |
||||||
|
|
||||||
|
.u-close { |
||||||
|
position: absolute; |
||||||
|
z-index: 3; |
||||||
|
} |
||||||
|
|
||||||
|
.u-close--top-left { |
||||||
|
top: 30rpx; |
||||||
|
left: 30rpx; |
||||||
|
} |
||||||
|
|
||||||
|
.u-close--top-right { |
||||||
|
top: 30rpx; |
||||||
|
right: 30rpx; |
||||||
|
} |
||||||
|
|
||||||
|
.u-close--bottom-left { |
||||||
|
bottom: 30rpx; |
||||||
|
left: 30rpx; |
||||||
|
} |
||||||
|
|
||||||
|
.u-close--bottom-right { |
||||||
|
right: 30rpx; |
||||||
|
bottom: 30rpx; |
||||||
|
} |
||||||
|
</style> |
@ -0,0 +1,155 @@ |
|||||||
|
## 导入即用 全端支持 |
||||||
|
|
||||||
|
### 有问题 + wx : zy597172583 标注来意 可评论 看到及时回复 |
||||||
|
1.使用方式 |
||||||
|
|
||||||
|
```javascript |
||||||
|
<template> |
||||||
|
<filter-popup :data="filterData" :form.sync="filterForm" v-model="popup.filter" title="全部筛选" height="1104rpx" @finsh="subFinsh"></filter-popup> |
||||||
|
</template> |
||||||
|
<script> |
||||||
|
import FilterPopup from "@/components/filter-popup/filter-popup"; |
||||||
|
export default { |
||||||
|
components: { |
||||||
|
FilterPopup, |
||||||
|
}, |
||||||
|
data() { |
||||||
|
return { |
||||||
|
//筛选表单数据 |
||||||
|
filterData: [ |
||||||
|
{ |
||||||
|
children: false,//是否有子项 |
||||||
|
title: "意向度", |
||||||
|
key: "intention_type", //键名 接收对象名字 |
||||||
|
keyValue: "value", //获取的值是哪个 |
||||||
|
isRadio: true, //是否单选 否则多选 |
||||||
|
data: [ |
||||||
|
{ |
||||||
|
title: "一般意向", |
||||||
|
id: 1, |
||||||
|
value: 1, |
||||||
|
}, |
||||||
|
{ |
||||||
|
title: "中意向度", |
||||||
|
id: 2, |
||||||
|
value: 2, |
||||||
|
}, |
||||||
|
{ |
||||||
|
title: "高意向度", |
||||||
|
id: 3, |
||||||
|
value: 3, |
||||||
|
}, |
||||||
|
], |
||||||
|
}, |
||||||
|
{ |
||||||
|
children: false,//是否有子项 |
||||||
|
title: "手机号码", |
||||||
|
key: "is_bind_phone", //键名 接收对象名字 |
||||||
|
keyValue: "value", //获取的值是哪个 |
||||||
|
isRadio: true, //是否单选 否则多选 |
||||||
|
data: [ |
||||||
|
{ |
||||||
|
title: "未绑定", |
||||||
|
value: 0, |
||||||
|
}, |
||||||
|
{ |
||||||
|
title: "已绑定", |
||||||
|
value: 1, |
||||||
|
}, |
||||||
|
], |
||||||
|
}, |
||||||
|
{ |
||||||
|
children: false,//是否有子项 |
||||||
|
title: "企微好友", |
||||||
|
key: "is_work_customer", //键名 接收对象名字 |
||||||
|
keyValue: "value", //获取的值是哪个 |
||||||
|
isRadio: true, //是否单选 否则多选 |
||||||
|
data: [ |
||||||
|
{ |
||||||
|
title: "未添加", |
||||||
|
value: 0, |
||||||
|
}, |
||||||
|
{ |
||||||
|
title: "已添加", |
||||||
|
value: 1, |
||||||
|
}, |
||||||
|
], |
||||||
|
}, |
||||||
|
{ |
||||||
|
children: true,//是否有子项 |
||||||
|
isRadio: false, //是否单选 |
||||||
|
title: "标签内容", |
||||||
|
key: "label", //键名 接收对象名字 |
||||||
|
keyValue: "id", //获取的值是哪个 |
||||||
|
data: [ |
||||||
|
{ |
||||||
|
title: "客户重要程度", |
||||||
|
id: 22, |
||||||
|
children: [ |
||||||
|
{ |
||||||
|
title: "一般意向2", |
||||||
|
id: 32, |
||||||
|
value: 1, |
||||||
|
}, |
||||||
|
{ |
||||||
|
title: "一般意向3", |
||||||
|
id: 12, |
||||||
|
value: 1, |
||||||
|
}, |
||||||
|
], |
||||||
|
}, |
||||||
|
{ |
||||||
|
title: "客户重要程度2", |
||||||
|
id: 122, |
||||||
|
children: [ |
||||||
|
{ |
||||||
|
title: "一般意向2", |
||||||
|
id: 43, |
||||||
|
value: 1, |
||||||
|
}, |
||||||
|
{ |
||||||
|
title: "一般意向3", |
||||||
|
id: 23, |
||||||
|
value: 1, |
||||||
|
}, |
||||||
|
], |
||||||
|
}, |
||||||
|
], |
||||||
|
}, |
||||||
|
], //筛选数据 |
||||||
|
filterForm: {}, //选中的表单 |
||||||
|
}; |
||||||
|
}, |
||||||
|
} |
||||||
|
``` |
||||||
|
|
||||||
|
2.组件props |
||||||
|
|
||||||
|
| 参数名 | 类型 | 介绍 | |
||||||
|
| ---------- | ------- | ------------------------------------------------- | |
||||||
|
| form | Object | .sync双向绑定的表单值 , 可传入显示初始哪些被选中 | |
||||||
|
| data | Array | 动态渲染选项的数据数组 | |
||||||
|
| title | String | 标题 | |
||||||
|
| height | String | 弹出层高度 单位 rpx px upx 百分比 vw等 | |
||||||
|
| themeColor | String | 组件主体颜色 默认:\#0066ff | |
||||||
|
| mask | Boolean | 是否显示弹出遮盖层 | |
||||||
|
|
||||||
|
3.data 参数 |
||||||
|
|
||||||
|
| 参数名 | 类型 | 是否必填 | 介绍 | |
||||||
|
| -------- | ------- | -------- | ------------------------------------------------------------ | |
||||||
|
| children | Boolean | 是 | 是否有子项 | |
||||||
|
| data | Array | 是 | 渲染出来的选项数据 | |
||||||
|
| isRadio | Boolean | 是 | 是否单选 单个选项指定,单选还是多选 | |
||||||
|
| title | String | 是 | 标签内容标题 | |
||||||
|
| key | String | 是 | 接收对象名字 会作为@finsh返回对象的键名 | |
||||||
|
| keyValue | String | 是 | 获取的值是哪个 自定义指定获取哪个键值 value还是id或者自己定义的 | |
||||||
|
|
||||||
|
4.事件 |
||||||
|
|
||||||
|
| 事件名 | 返回参数 | 简介 | |
||||||
|
| ------ | -------- | ----------------------------------------- | |
||||||
|
| finsh | Object | 点击确定时触发 返回参数为选中值的对象数组 | |
||||||
|
| close | 无 | 组件点击关闭时触发 | |
||||||
|
|
||||||
|
![image-20210730095456900](https://yzhsaas-cdn.qietongvip.com/asd.png) |
@ -0,0 +1,466 @@ |
|||||||
|
<template> |
||||||
|
<popup |
||||||
|
:mask="mask" |
||||||
|
border-radius="50" |
||||||
|
v-model="acceptValue" |
||||||
|
mode="bottom" |
||||||
|
class="filter-popup" |
||||||
|
:height="height" |
||||||
|
@close="close" |
||||||
|
:style="{ '--color': themeColor }" |
||||||
|
:mask-custom-style="{ background: 'rgba(0, 0, 0, 0.7)' }" |
||||||
|
> |
||||||
|
<view class="top-title flex-row-sb" v-if="showTop"> |
||||||
|
<view></view> <view class="popup-title flex-row-c-c">{{ title }}</view |
||||||
|
><text class="saasIcon flex-row-c-c" @click="close"></text> |
||||||
|
</view> |
||||||
|
|
||||||
|
<scroll-view class="select-scroll" scroll-y :style="{ height: `calc( ${height} - 120rpx - 152rpx )` }"> |
||||||
|
<view class="select-main"> |
||||||
|
<view class="select-item" v-for="(item, index) in data" :key="index"> |
||||||
|
<view class="title"> {{ item.title }} </view> |
||||||
|
<view class="tag-list" v-if="!item.children"> |
||||||
|
<view |
||||||
|
class="tag-item" |
||||||
|
:class="[acceptForm[item.key].includes(item2.value) ? 'select-on' : '']" |
||||||
|
v-for="(item2, index2) in item.data" |
||||||
|
:key="index2" |
||||||
|
@click="selectTagBuyValueOrId(item2, item.key, item.keyValue, item.isRadio)" |
||||||
|
> |
||||||
|
{{ item2.title }} |
||||||
|
</view> |
||||||
|
</view> |
||||||
|
<!-- 有childer --> |
||||||
|
<view class="select-childer" v-else v-for="item2 in item.data" :key="item2.id"> |
||||||
|
<view class="childer-title flex-row--c">{{ item2.title }}</view> |
||||||
|
<view class="tag-list"> |
||||||
|
<view |
||||||
|
class="tag-item" |
||||||
|
:class="[acceptForm[item.key].includes(item3.id) ? 'select-on' : '']" |
||||||
|
v-for="item3 in item2.children" |
||||||
|
:key="item3.id" |
||||||
|
@click="selectTagBuyValueOrId(item3, item.key, item.keyValue, item.isRadio)" |
||||||
|
> |
||||||
|
{{ item3.title }} |
||||||
|
</view> |
||||||
|
</view> |
||||||
|
</view> |
||||||
|
</view> |
||||||
|
</view> |
||||||
|
</scroll-view> |
||||||
|
|
||||||
|
<view class="filter-button flex-row-c"> |
||||||
|
<view class="btn flex-row"> |
||||||
|
<view class="btn-1 flex-row-c-c" @click="reset">重置</view> |
||||||
|
<view class="btn-2 flex-row-c-c" @click="finsh">完成</view> |
||||||
|
</view> |
||||||
|
</view> |
||||||
|
</popup> |
||||||
|
</template> |
||||||
|
|
||||||
|
<script> |
||||||
|
import Popup from './components/popup.vue'; |
||||||
|
export default { |
||||||
|
components:{ |
||||||
|
Popup |
||||||
|
}, |
||||||
|
name: "filter-popup", |
||||||
|
props: { |
||||||
|
//选中的表单 |
||||||
|
form: { |
||||||
|
type: Object, |
||||||
|
default: () => {}, |
||||||
|
}, |
||||||
|
//主题颜色 |
||||||
|
themeColor: { |
||||||
|
type: String, |
||||||
|
default: "#0066ff", |
||||||
|
}, |
||||||
|
//渲染数据 |
||||||
|
data: { |
||||||
|
type: Array, |
||||||
|
default: () => [], |
||||||
|
}, |
||||||
|
//标题 |
||||||
|
title: { |
||||||
|
type: String, |
||||||
|
default: "请选择", |
||||||
|
}, |
||||||
|
value: { |
||||||
|
type: Boolean, |
||||||
|
default: false, |
||||||
|
}, |
||||||
|
mask: { |
||||||
|
type: Boolean, |
||||||
|
default: true, |
||||||
|
}, |
||||||
|
height: { |
||||||
|
type: String, |
||||||
|
default: "600rpx", |
||||||
|
}, |
||||||
|
//是否显示退出按钮 |
||||||
|
showTop: { |
||||||
|
type: Boolean, |
||||||
|
default: true, |
||||||
|
}, |
||||||
|
}, |
||||||
|
computed: { |
||||||
|
// 接收表单 |
||||||
|
acceptForm: { |
||||||
|
get() { |
||||||
|
this.originForm = JSON.parse(JSON.stringify(this.form)) |
||||||
|
if (Object.keys(this.form).length) { |
||||||
|
return this.form; |
||||||
|
} else { |
||||||
|
let obj = {}; |
||||||
|
this.data.forEach((item) => { |
||||||
|
obj[item.key] = []; |
||||||
|
}); |
||||||
|
return obj; |
||||||
|
} |
||||||
|
}, |
||||||
|
set(nval) { |
||||||
|
// console.log("set Form :>> ", nval); |
||||||
|
this.$emit("update:form", nval); |
||||||
|
}, |
||||||
|
}, |
||||||
|
acceptValue: { |
||||||
|
get() { |
||||||
|
return this.value; |
||||||
|
}, |
||||||
|
set(nval) { |
||||||
|
this.$emit("input", nval); |
||||||
|
}, |
||||||
|
}, |
||||||
|
}, |
||||||
|
data() { |
||||||
|
return { |
||||||
|
originForm: {} |
||||||
|
} |
||||||
|
}, |
||||||
|
methods: { |
||||||
|
//选择存value 还是id |
||||||
|
selectTagBuyValueOrId(item, key, keyValue, isRadio) { |
||||||
|
//如果是单选 |
||||||
|
if (isRadio) { |
||||||
|
if (keyValue == "value") { |
||||||
|
if (this.acceptForm[key].some((value) => value === item.value)) { |
||||||
|
this.acceptForm[key] = this.acceptForm[key].filter((value) => value !== item.value); |
||||||
|
return; |
||||||
|
} |
||||||
|
this.acceptForm[key] = []; |
||||||
|
this.acceptForm[key].push(item.value); |
||||||
|
} else { |
||||||
|
if (this.acceptForm[key].some((id) => id === item.id)) { |
||||||
|
this.acceptForm[key] = this.acceptForm[key].filter((id) => id !== item.id); |
||||||
|
return; |
||||||
|
} |
||||||
|
this.acceptForm[key] = []; |
||||||
|
this.acceptForm[key].push(item.id); |
||||||
|
} |
||||||
|
} else { |
||||||
|
if (keyValue == "value") { |
||||||
|
this.acceptForm[key].some((value) => value === item.value) |
||||||
|
? (this.acceptForm[key] = this.acceptForm[key].filter((value) => value !== item.value)) |
||||||
|
: this.acceptForm[key].push(item.value); |
||||||
|
} else { |
||||||
|
this.acceptForm[key].some((id) => id === item.id) |
||||||
|
? (this.acceptForm[key] = this.acceptForm[key].filter((id) => id !== item.id)) |
||||||
|
: this.acceptForm[key].push(item.id); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
this.acceptForm = this.acceptForm; |
||||||
|
}, |
||||||
|
// 点击完成 |
||||||
|
finsh() { |
||||||
|
this.$emit("finsh", this.acceptForm); |
||||||
|
this.$emit("input", false); |
||||||
|
}, |
||||||
|
close() { |
||||||
|
this.$emit("input", false); |
||||||
|
this.$emit("close"); |
||||||
|
}, |
||||||
|
//重置 |
||||||
|
reset() { |
||||||
|
this.acceptForm = {} |
||||||
|
}, |
||||||
|
}, |
||||||
|
}; |
||||||
|
</script> |
||||||
|
<style lang="scss" scoped> |
||||||
|
@font-face { |
||||||
|
font-family: 'iconfont'; /* Project id 2729410 */ |
||||||
|
src: url('https://at.alicdn.com/t/font_2729410_3nhq3ibbcqg.woff2?t=1628330097695') format('woff2'), |
||||||
|
url('https://at.alicdn.com/t/font_2729410_3nhq3ibbcqg.woff?t=1628330097695') format('woff'), |
||||||
|
url('https://at.alicdn.com/t/font_2729410_3nhq3ibbcqg.ttf?t=1628330097695') format('truetype'); |
||||||
|
} |
||||||
|
.saasIcon { |
||||||
|
font-family: "iconfont" !important; |
||||||
|
font-style: normal; |
||||||
|
-webkit-font-smoothing: antialiased; |
||||||
|
-webkit-text-stroke-width: 0.2px; |
||||||
|
-moz-osx-font-smoothing: grayscale; |
||||||
|
} |
||||||
|
.filter-popup { |
||||||
|
color: #000000; |
||||||
|
.top-title { |
||||||
|
font-weight: bold; |
||||||
|
height: 90rpx; |
||||||
|
margin-left: 70rpx; |
||||||
|
font-size: 30rpx; |
||||||
|
margin-top: 20rpx; |
||||||
|
.popup-title { |
||||||
|
height: 100%; |
||||||
|
} |
||||||
|
.saasIcon { |
||||||
|
// width: 150rpx; |
||||||
|
height: 100%; |
||||||
|
padding-right: 70rpx; |
||||||
|
} |
||||||
|
} |
||||||
|
.select-scroll { |
||||||
|
} |
||||||
|
.select-main { |
||||||
|
padding: 0 32rpx; |
||||||
|
.select-item { |
||||||
|
.title { |
||||||
|
font-weight: bold; |
||||||
|
font-size: 28rpx; |
||||||
|
color: #000000; |
||||||
|
padding-top: 30rpx; |
||||||
|
} |
||||||
|
.tag-list { |
||||||
|
display: flex; |
||||||
|
flex-wrap: wrap; |
||||||
|
margin-left: -12rpx; |
||||||
|
.tag-item { |
||||||
|
margin-top: 20rpx; |
||||||
|
padding: 10rpx 40rpx; |
||||||
|
font-size: 26rpx; |
||||||
|
background: #f5f5f5; |
||||||
|
color: #484848; |
||||||
|
border-radius: 36rpx; |
||||||
|
margin-left: 12rpx; |
||||||
|
&.select-on { |
||||||
|
background: var(--color); |
||||||
|
color: #fff; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
.select-childer { |
||||||
|
.childer-title { |
||||||
|
color: #484848; |
||||||
|
font-size: 28rpx; |
||||||
|
border-bottom: 1px solid #f5f5f5; |
||||||
|
height: 80rpx; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
.filter-button { |
||||||
|
width: 100%; |
||||||
|
height: 152rpx; |
||||||
|
background: #ffffff; |
||||||
|
box-shadow: 0px -3px 12px rgba(0, 0, 0, 0.06); |
||||||
|
position: fixed; |
||||||
|
bottom: 0; |
||||||
|
.btn { |
||||||
|
border-radius: 100rpx; |
||||||
|
margin-top: 26rpx; |
||||||
|
width: 680rpx; |
||||||
|
height: 80rpx; |
||||||
|
color: #ffffff; |
||||||
|
font-size: 28rpx; |
||||||
|
overflow: hidden; |
||||||
|
.btn-1 { |
||||||
|
flex: 1; |
||||||
|
background: linear-gradient(271deg, #2698fb 0%, #84c6ff 100%); |
||||||
|
} |
||||||
|
.btn-2 { |
||||||
|
flex: 1; |
||||||
|
background: linear-gradient(90deg, #0066ff 0%, #1371ff 100%); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// 自定义css |
||||||
|
.flex-row { |
||||||
|
display: flex; |
||||||
|
} |
||||||
|
|
||||||
|
.flex-row-c { |
||||||
|
display: flex; |
||||||
|
justify-content: center; |
||||||
|
} |
||||||
|
|
||||||
|
.flex-row--c { |
||||||
|
display: flex; |
||||||
|
align-items: center; |
||||||
|
} |
||||||
|
|
||||||
|
.flex-row-c-c { |
||||||
|
display: flex; |
||||||
|
justify-content: center; |
||||||
|
align-items: center; |
||||||
|
} |
||||||
|
|
||||||
|
.flex-row-sb-c { |
||||||
|
display: flex; |
||||||
|
justify-content: space-between; |
||||||
|
align-items: center; |
||||||
|
} |
||||||
|
|
||||||
|
.flex-row-sb-t { |
||||||
|
display: flex; |
||||||
|
justify-content: space-between; |
||||||
|
align-items: flex-start; |
||||||
|
} |
||||||
|
|
||||||
|
.flex-row-sb-b { |
||||||
|
display: flex; |
||||||
|
justify-content: space-between; |
||||||
|
align-items: flex-end; |
||||||
|
} |
||||||
|
|
||||||
|
.flex-row-c-sb { |
||||||
|
display: flex; |
||||||
|
justify-content: center; |
||||||
|
align-items: space-between; |
||||||
|
} |
||||||
|
|
||||||
|
.flex-row-sb { |
||||||
|
display: flex; |
||||||
|
justify-content: space-between; |
||||||
|
} |
||||||
|
|
||||||
|
.flex-row-l { |
||||||
|
display: flex; |
||||||
|
justify-content: flex-start; |
||||||
|
} |
||||||
|
|
||||||
|
.flex-row-l-c { |
||||||
|
display: flex; |
||||||
|
justify-content: flex-start; |
||||||
|
align-items: center; |
||||||
|
} |
||||||
|
|
||||||
|
.flex-row-c-t { |
||||||
|
display: flex; |
||||||
|
justify-content: center; |
||||||
|
align-items: flex-start; |
||||||
|
} |
||||||
|
|
||||||
|
.flex-row-r-c { |
||||||
|
display: flex; |
||||||
|
justify-content: flex-end; |
||||||
|
align-items: center; |
||||||
|
} |
||||||
|
|
||||||
|
.flex-row-r { |
||||||
|
display: flex; |
||||||
|
justify-content: flex-end; |
||||||
|
} |
||||||
|
|
||||||
|
.flex-row--b { |
||||||
|
display: flex; |
||||||
|
align-items: flex-end; |
||||||
|
} |
||||||
|
|
||||||
|
.flex-col { |
||||||
|
display: flex; |
||||||
|
flex-direction: column; |
||||||
|
} |
||||||
|
|
||||||
|
.flex-col-c { |
||||||
|
display: flex; |
||||||
|
flex-direction: column; |
||||||
|
justify-content: center; |
||||||
|
} |
||||||
|
|
||||||
|
.flex-col--c { |
||||||
|
display: flex; |
||||||
|
flex-direction: column; |
||||||
|
align-items: center; |
||||||
|
} |
||||||
|
|
||||||
|
.flex-col-c-c { |
||||||
|
display: flex; |
||||||
|
flex-direction: column; |
||||||
|
justify-content: center; |
||||||
|
align-items: center; |
||||||
|
} |
||||||
|
|
||||||
|
.flex-col-sb-c { |
||||||
|
display: flex; |
||||||
|
flex-direction: column; |
||||||
|
justify-content: space-between; |
||||||
|
align-items: center; |
||||||
|
} |
||||||
|
|
||||||
|
.flex-col-c-sb { |
||||||
|
display: flex; |
||||||
|
flex-direction: column; |
||||||
|
justify-content: center; |
||||||
|
align-items: space-between; |
||||||
|
} |
||||||
|
|
||||||
|
.flex-col-sb { |
||||||
|
display: flex; |
||||||
|
flex-direction: column; |
||||||
|
justify-content: space-between; |
||||||
|
} |
||||||
|
|
||||||
|
.flex-col-t-c { |
||||||
|
display: flex; |
||||||
|
flex-direction: column; |
||||||
|
justify-content: flex-start; |
||||||
|
align-items: center; |
||||||
|
} |
||||||
|
|
||||||
|
.flex-col-c-l { |
||||||
|
display: flex; |
||||||
|
flex-direction: column; |
||||||
|
justify-content: center; |
||||||
|
align-items: flex-start; |
||||||
|
} |
||||||
|
|
||||||
|
.flex-col-t { |
||||||
|
display: flex; |
||||||
|
flex-direction: column; |
||||||
|
justify-content: flex-start; |
||||||
|
} |
||||||
|
|
||||||
|
.flex-col-b { |
||||||
|
display: flex; |
||||||
|
flex-direction: column; |
||||||
|
justify-content: flex-end; |
||||||
|
} |
||||||
|
|
||||||
|
.flex-col-b-c { |
||||||
|
display: flex; |
||||||
|
flex-direction: column; |
||||||
|
justify-content: flex-end; |
||||||
|
align-items: center; |
||||||
|
} |
||||||
|
|
||||||
|
.flex-col-c-l { |
||||||
|
display: flex; |
||||||
|
flex-direction: column; |
||||||
|
justify-content: center; |
||||||
|
align-items: flex-end; |
||||||
|
} |
||||||
|
|
||||||
|
.flex-col--l { |
||||||
|
display: flex; |
||||||
|
flex-direction: column; |
||||||
|
align-items: flex-start; |
||||||
|
} |
||||||
|
|
||||||
|
.flex-col--r { |
||||||
|
display: flex; |
||||||
|
flex-direction: column; |
||||||
|
align-items: flex-end; |
||||||
|
} |
||||||
|
} |
||||||
|
</style> |
@ -0,0 +1,140 @@ |
|||||||
|
<template> |
||||||
|
<view class="uni-section"> |
||||||
|
<view class="uni-section-header" nvue> |
||||||
|
<view v-if="type" class="uni-section__head"> |
||||||
|
<view :class="type" class="uni-section__head-tag"/> |
||||||
|
</view> |
||||||
|
<view class="uni-section__content"> |
||||||
|
<text :class="{'distraction':!subTitle}" :style="{color:color}" class="uni-section__content-title">{{ title }}</text> |
||||||
|
<text v-if="subTitle" class="uni-section__content-sub">{{ subTitle }}</text> |
||||||
|
</view> |
||||||
|
</view> |
||||||
|
<view :style="{padding: padding ? '10px' : ''}"> |
||||||
|
<slot/> |
||||||
|
</view> |
||||||
|
</view> |
||||||
|
</template> |
||||||
|
|
||||||
|
<script> |
||||||
|
|
||||||
|
/** |
||||||
|
* Section 标题栏 |
||||||
|
* @description 标题栏 |
||||||
|
* @property {String} type = [line|circle] 标题装饰类型 |
||||||
|
* @value line 竖线 |
||||||
|
* @value circle 圆形 |
||||||
|
* @property {String} title 主标题 |
||||||
|
* @property {String} subTitle 副标题 |
||||||
|
*/ |
||||||
|
|
||||||
|
export default { |
||||||
|
name: 'UniSection', |
||||||
|
emits:['click'], |
||||||
|
props: { |
||||||
|
type: { |
||||||
|
type: String, |
||||||
|
default: '' |
||||||
|
}, |
||||||
|
title: { |
||||||
|
type: String, |
||||||
|
default: '' |
||||||
|
}, |
||||||
|
color:{ |
||||||
|
type: String, |
||||||
|
default: '#333' |
||||||
|
}, |
||||||
|
subTitle: { |
||||||
|
type: String, |
||||||
|
default: '' |
||||||
|
}, |
||||||
|
padding: { |
||||||
|
type: Boolean, |
||||||
|
default: false |
||||||
|
} |
||||||
|
}, |
||||||
|
data() { |
||||||
|
return {} |
||||||
|
}, |
||||||
|
watch: { |
||||||
|
title(newVal) { |
||||||
|
if (uni.report && newVal !== '') { |
||||||
|
uni.report('title', newVal) |
||||||
|
} |
||||||
|
} |
||||||
|
}, |
||||||
|
methods: { |
||||||
|
onClick() { |
||||||
|
this.$emit('click') |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
</script> |
||||||
|
<style lang="scss" > |
||||||
|
$uni-primary: #2979ff !default; |
||||||
|
|
||||||
|
.uni-section { |
||||||
|
background-color: #fff; |
||||||
|
// overflow: hidden; |
||||||
|
margin-top: 10px; |
||||||
|
} |
||||||
|
.uni-section-header { |
||||||
|
position: relative; |
||||||
|
/* #ifndef APP-NVUE */ |
||||||
|
display: flex; |
||||||
|
/* #endif */ |
||||||
|
flex-direction: row; |
||||||
|
align-items: center; |
||||||
|
padding: 12px 10px; |
||||||
|
// height: 50px; |
||||||
|
font-weight: normal; |
||||||
|
} |
||||||
|
.uni-section__head { |
||||||
|
flex-direction: row; |
||||||
|
justify-content: center; |
||||||
|
align-items: center; |
||||||
|
margin-right: 10px; |
||||||
|
} |
||||||
|
|
||||||
|
.line { |
||||||
|
height: 12px; |
||||||
|
background-color: $uni-primary; |
||||||
|
border-radius: 10px; |
||||||
|
width: 4px; |
||||||
|
} |
||||||
|
|
||||||
|
.circle { |
||||||
|
width: 8px; |
||||||
|
height: 8px; |
||||||
|
border-top-right-radius: 50px; |
||||||
|
border-top-left-radius: 50px; |
||||||
|
border-bottom-left-radius: 50px; |
||||||
|
border-bottom-right-radius: 50px; |
||||||
|
background-color: $uni-primary; |
||||||
|
} |
||||||
|
|
||||||
|
.uni-section__content { |
||||||
|
/* #ifndef APP-NVUE */ |
||||||
|
display: flex; |
||||||
|
/* #endif */ |
||||||
|
flex-direction: column; |
||||||
|
flex: 1; |
||||||
|
color: #333; |
||||||
|
} |
||||||
|
|
||||||
|
.uni-section__content-title { |
||||||
|
font-size: 14px; |
||||||
|
color: $uni-primary; |
||||||
|
} |
||||||
|
|
||||||
|
.distraction { |
||||||
|
flex-direction: row; |
||||||
|
align-items: center; |
||||||
|
} |
||||||
|
|
||||||
|
.uni-section__content-sub { |
||||||
|
font-size: 12px; |
||||||
|
color: #999; |
||||||
|
line-height: 16px; |
||||||
|
margin-top: 2px; |
||||||
|
} |
||||||
|
</style> |
@ -0,0 +1,10 @@ |
|||||||
|
/** |
||||||
|
/** |
||||||
|
* 产品 配置文件 |
||||||
|
* @author yujialong |
||||||
|
*/ |
||||||
|
|
||||||
|
export default { |
||||||
|
normalIcon: 'https://huoran.oss-cn-shenzhen.aliyuncs.com/20220609/png/1534733700683030528.png', // 通用图标
|
||||||
|
dataIcon: 'https://huoran.oss-cn-shenzhen.aliyuncs.com/20220627/png/1541256164447641600.png' // 数据图标
|
||||||
|
} |
@ -0,0 +1,21 @@ |
|||||||
|
/** |
||||||
|
/** |
||||||
|
* 请求配置文件 |
||||||
|
* @author yujialong |
||||||
|
*/ |
||||||
|
|
||||||
|
export default { |
||||||
|
baseURL: 'https://huorantech.cn/', |
||||||
|
// baseURL: 'http://192.168.31.137:9000/',
|
||||||
|
// baseURL: 'http://121.37.12.51/',
|
||||||
|
headers: { |
||||||
|
'Content-Type': 'application/json;charset=UTF-8' |
||||||
|
}, |
||||||
|
data: {}, |
||||||
|
method: 'POST', |
||||||
|
responseType: 'json', // 响应数据类型
|
||||||
|
withCredentials: false, // 携带cookie
|
||||||
|
// ======================== 以下为注入axios的配置项 =============================
|
||||||
|
showLoading: true, // 是否显示加载动画
|
||||||
|
isFormData: false // 是否序列化表单数据
|
||||||
|
} |
@ -0,0 +1,16 @@ |
|||||||
|
/** |
||||||
|
* @description 鉴权指令 |
||||||
|
* 当传入的权限当前用户没有时,会移除该组件 |
||||||
|
* 用例:<Tag v-auth>text</Tag> 或者:<Tag v-auth="'user:编辑'">text</Tag> |
||||||
|
* */ |
||||||
|
export default { |
||||||
|
inserted(el, binding, vnode) { |
||||||
|
const btnText = el.innerText |
||||||
|
const btnPermissions = uni.getStorageSync('auth') |
||||||
|
if (btnText && btnPermissions && btnPermissions.length) { |
||||||
|
const isPermission = btnPermissions.includes(btnText) |
||||||
|
// 如果按钮集合里没有该权限,就把该按钮给去除
|
||||||
|
!isPermission && el.parentNode && el.parentNode.removeChild(el) |
||||||
|
} |
||||||
|
}, |
||||||
|
}; |
@ -0,0 +1,12 @@ |
|||||||
|
/** |
||||||
|
* 插件 |
||||||
|
* */ |
||||||
|
|
||||||
|
import auth from './auth' |
||||||
|
|
||||||
|
export default { |
||||||
|
async install(Vue, options) { |
||||||
|
// 指令
|
||||||
|
Vue.directive('auth', auth) |
||||||
|
} |
||||||
|
}; |
@ -0,0 +1,14 @@ |
|||||||
|
<!DOCTYPE html> |
||||||
|
<html lang="en"> |
||||||
|
<head> |
||||||
|
<meta charset="UTF-8" /> |
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" /> |
||||||
|
<title></title> |
||||||
|
<!--preload-links--> |
||||||
|
<!--app-context--> |
||||||
|
</head> |
||||||
|
<body> |
||||||
|
<div id="app"><!--app-html--></div> |
||||||
|
<script type="module" src="/main.js"></script> |
||||||
|
</body> |
||||||
|
</html> |
@ -0,0 +1,35 @@ |
|||||||
|
var crypto = require('crypto') |
||||||
|
|
||||||
|
function WXBizDataCrypt(appId, sessionKey) { |
||||||
|
this.appId = appId |
||||||
|
this.sessionKey = sessionKey |
||||||
|
} |
||||||
|
|
||||||
|
WXBizDataCrypt.prototype.decryptData = function (encryptedData, iv) { |
||||||
|
// base64 decode
|
||||||
|
var sessionKey = new Buffer(this.sessionKey, 'base64') |
||||||
|
encryptedData = new Buffer(encryptedData, 'base64') |
||||||
|
iv = new Buffer(iv, 'base64') |
||||||
|
|
||||||
|
try { |
||||||
|
// 解密
|
||||||
|
var decipher = crypto.createDecipheriv('aes-128-cbc', sessionKey, iv) |
||||||
|
// 设置自动 padding 为 true,删除填充补位
|
||||||
|
decipher.setAutoPadding(true) |
||||||
|
var decoded = decipher.update(encryptedData, 'binary', 'utf8') |
||||||
|
decoded += decipher.final('utf8') |
||||||
|
|
||||||
|
decoded = JSON.parse(decoded) |
||||||
|
|
||||||
|
} catch (err) { |
||||||
|
throw new Error('Illegal Buffer') |
||||||
|
} |
||||||
|
|
||||||
|
if (decoded.watermark.appid !== this.appId) { |
||||||
|
throw new Error('Illegal Buffer') |
||||||
|
} |
||||||
|
|
||||||
|
return decoded |
||||||
|
} |
||||||
|
|
||||||
|
module.exports = WXBizDataCrypt |
@ -0,0 +1,107 @@ |
|||||||
|
import Product from '@/config/product' |
||||||
|
|
||||||
|
const files = [ |
||||||
|
'https://huorantech.cn/%E7%94%A8%E6%88%B7%E6%9C%8D%E5%8A%A1%E5%8D%8F%E8%AE%AE.docx', // 用户服务协议
|
||||||
|
'https://huorantech.cn/%E7%94%A8%E6%88%B7%E9%9A%90%E7%A7%81%E5%8D%8F%E8%AE%AE.docx', // 用户隐私协议
|
||||||
|
'https://huorantech.cn/%E4%BA%BA%E5%B7%A5%E6%99%BA%E8%83%BD%E5%AE%9E%E9%AA%8C%E5%AE%A4%E5%BB%BA%E8%AE%BE%E6%96%B9%E6%A1%88-2020.1.docx', // 人工智能
|
||||||
|
'https://huorantech.cn/%E5%A4%A7%E6%95%B0%E6%8D%AE%E7%AE%A1%E7%90%86%E4%B8%8E%E5%BA%94%E7%94%A8%E4%B8%93%E4%B8%9A%E5%BB%BA%E8%AE%BE%E6%96%B9%E6%A1%88.docx', // 大数据
|
||||||
|
'https://huorantech.cn/%E9%87%91%E8%9E%8D%E7%A7%91%E6%8A%80%E5%AE%9E%E9%AA%8C%E5%AE%A4%E5%BB%BA%E8%AE%BE%E6%96%B9%E6%A1%88V2.0.docx', // 金融科技
|
||||||
|
] |
||||||
|
export default { |
||||||
|
// 路由跳转
|
||||||
|
to(url) { |
||||||
|
uni.navigateTo({ |
||||||
|
url |
||||||
|
}) |
||||||
|
}, |
||||||
|
// 成功提示
|
||||||
|
sucMsg(title, duration = 1500) { |
||||||
|
uni.showToast({ |
||||||
|
title, |
||||||
|
duration |
||||||
|
}) |
||||||
|
}, |
||||||
|
// 错误提示
|
||||||
|
errMsg(title, duration = 1500) { |
||||||
|
uni.showToast({ |
||||||
|
title, |
||||||
|
icon: 'none', |
||||||
|
duration |
||||||
|
}) |
||||||
|
}, |
||||||
|
// 如果非数字,则返回0
|
||||||
|
handleNaN(val) { |
||||||
|
return isNaN(val) ? 0 : val |
||||||
|
}, |
||||||
|
// 小于10,返回0+传入值
|
||||||
|
preZero(val) { |
||||||
|
return val < 10 ? '0' + val : val |
||||||
|
}, |
||||||
|
//返回格式化时间,传参例如:"yyyy-MM-dd hh:mm:ss"
|
||||||
|
formatDate(date, fmt = 'yyyy-MM-dd hh:mm:ss') { |
||||||
|
var date = date ? date : new Date() |
||||||
|
var o = {
|
||||||
|
"M+" : date.getMonth()+1, //月份
|
||||||
|
"d+" : date.getDate(), //日
|
||||||
|
"h+" : date.getHours(), //小时
|
||||||
|
"m+" : date.getMinutes(), //分
|
||||||
|
"s+" : date.getSeconds(), //秒
|
||||||
|
"q+" : Math.floor((date.getMonth()+3)/3), //季度
|
||||||
|
"S" : date.getMilliseconds() //毫秒
|
||||||
|
} |
||||||
|
if(/(y+)/.test(fmt)) { |
||||||
|
fmt=fmt.replace(RegExp.$1, (date.getFullYear()+"").substr(4 - RegExp.$1.length)) |
||||||
|
} |
||||||
|
for(var k in o) { |
||||||
|
if(new RegExp("("+ k +")").test(fmt)){ |
||||||
|
fmt = fmt.replace(RegExp.$1, (RegExp.$1.length==1) ? (o[k]) : (("00"+ o[k]).substr((""+ o[k]).length))) |
||||||
|
} |
||||||
|
} |
||||||
|
return fmt |
||||||
|
}, |
||||||
|
// 获取商务经理id
|
||||||
|
getBmId(val) { |
||||||
|
return uni.getStorageSync('team').partnerId |
||||||
|
}, |
||||||
|
// 获取商务经理名称
|
||||||
|
getBmName(val) { |
||||||
|
return uni.getStorageSync('team').partnerClassificationName |
||||||
|
}, |
||||||
|
// 返回图标。如果有图标,则直接返回,否则判断是否是数据产品,即productType=2,如果是,则取数据图标,否则则显示通用图标,这两个图标都在config/product.js里有配置
|
||||||
|
getIcon(e) { |
||||||
|
return e.miniProgramPictureAddress || (e.productType === 2 ? Product.dataIcon : Product.normalIcon) |
||||||
|
}, |
||||||
|
// 预览文档
|
||||||
|
openFile(id) { |
||||||
|
uni.showLoading({ |
||||||
|
title: '加载中', |
||||||
|
mask: true |
||||||
|
}) |
||||||
|
// 下载文件资源到本地
|
||||||
|
uni.downloadFile({ |
||||||
|
url: files[id], |
||||||
|
success: function(res) { |
||||||
|
uni.hideLoading(); |
||||||
|
uni.showLoading({ |
||||||
|
title: '正在打开', |
||||||
|
mask: true |
||||||
|
}) |
||||||
|
// 新开页面打开文档,支持格式:doc, xls, ppt, pdf, docx, xlsx, pptx。
|
||||||
|
uni.openDocument({ |
||||||
|
filePath: res.tempFilePath, |
||||||
|
fileType: 'docx', // 文件类型,指定文件类型打开文件,有效值 doc, xls, ppt, pdf, docx, xlsx, pptx
|
||||||
|
showMenu: true, // 允许出现分享功能
|
||||||
|
success: res => { |
||||||
|
uni.hideLoading() |
||||||
|
}, |
||||||
|
fail: openError => { |
||||||
|
uni.hideLoading() |
||||||
|
} |
||||||
|
}) |
||||||
|
}, |
||||||
|
fail: function(err) { |
||||||
|
uni.hideLoading() |
||||||
|
} |
||||||
|
}) |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,39 @@ |
|||||||
|
|
||||||
|
// #ifndef VUE3
|
||||||
|
import Vue from 'vue' |
||||||
|
import App from './App' |
||||||
|
import util from '@/libs/util' |
||||||
|
import plugins from '@/directives' |
||||||
|
|
||||||
|
Vue.config.productionTip = false |
||||||
|
Vue.prototype.$util = util |
||||||
|
Vue.use(plugins) |
||||||
|
|
||||||
|
App.mpType = 'app' |
||||||
|
|
||||||
|
// 权限控制
|
||||||
|
Vue.prototype.auth = function(text){ |
||||||
|
const auth = uni.getStorageSync('auth') |
||||||
|
if (text && auth && auth.length) { |
||||||
|
const isPermission = auth.includes(text) |
||||||
|
return auth.includes(text) |
||||||
|
} |
||||||
|
// return true
|
||||||
|
} |
||||||
|
|
||||||
|
const app = new Vue({ |
||||||
|
...App |
||||||
|
}) |
||||||
|
app.$mount() |
||||||
|
// #endif
|
||||||
|
|
||||||
|
// #ifdef VUE3
|
||||||
|
import { createSSRApp } from 'vue' |
||||||
|
import App from './App.vue' |
||||||
|
export function createApp() { |
||||||
|
const app = createSSRApp(App) |
||||||
|
return { |
||||||
|
app |
||||||
|
} |
||||||
|
} |
||||||
|
// #endif
|
@ -0,0 +1,60 @@ |
|||||||
|
{ |
||||||
|
"name" : "或然crm", |
||||||
|
"appid" : "__UNI__2E89BA6", |
||||||
|
"description" : "", |
||||||
|
"versionName" : "1.0.0", |
||||||
|
"versionCode" : "100", |
||||||
|
"transformPx" : false, |
||||||
|
"app-plus" : { |
||||||
|
/* 5+App特有相关 */ |
||||||
|
"usingComponents" : true, |
||||||
|
"nvueCompiler" : "uni-app", |
||||||
|
"splashscreen" : { |
||||||
|
"alwaysShowBeforeRender" : true, |
||||||
|
"waiting" : true, |
||||||
|
"autoclose" : true, |
||||||
|
"delay" : 0 |
||||||
|
}, |
||||||
|
"modules" : {}, |
||||||
|
/* 模块配置 */ |
||||||
|
"distribute" : { |
||||||
|
/* 应用发布信息 */ |
||||||
|
"android" : { |
||||||
|
/* android打包配置 */ |
||||||
|
"permissions" : [ |
||||||
|
"<uses-permission android:name=\"android.permission.CHANGE_NETWORK_STATE\"/>", |
||||||
|
"<uses-permission android:name=\"android.permission.MOUNT_UNMOUNT_FILESYSTEMS\"/>", |
||||||
|
"<uses-permission android:name=\"android.permission.VIBRATE\"/>", |
||||||
|
"<uses-permission android:name=\"android.permission.READ_LOGS\"/>", |
||||||
|
"<uses-permission android:name=\"android.permission.ACCESS_WIFI_STATE\"/>", |
||||||
|
"<uses-feature android:name=\"android.hardware.camera.autofocus\"/>", |
||||||
|
"<uses-permission android:name=\"android.permission.ACCESS_NETWORK_STATE\"/>", |
||||||
|
"<uses-permission android:name=\"android.permission.CAMERA\"/>", |
||||||
|
"<uses-permission android:name=\"android.permission.GET_ACCOUNTS\"/>", |
||||||
|
"<uses-permission android:name=\"android.permission.READ_PHONE_STATE\"/>", |
||||||
|
"<uses-permission android:name=\"android.permission.CHANGE_WIFI_STATE\"/>", |
||||||
|
"<uses-permission android:name=\"android.permission.WAKE_LOCK\"/>", |
||||||
|
"<uses-permission android:name=\"android.permission.FLASHLIGHT\"/>", |
||||||
|
"<uses-feature android:name=\"android.hardware.camera\"/>", |
||||||
|
"<uses-permission android:name=\"android.permission.WRITE_SETTINGS\"/>" |
||||||
|
] |
||||||
|
}, |
||||||
|
"ios" : {}, |
||||||
|
/* ios打包配置 */ |
||||||
|
"sdkConfigs" : {} |
||||||
|
} |
||||||
|
}, |
||||||
|
/* SDK配置 */ |
||||||
|
"quickapp" : {}, |
||||||
|
/* 快应用特有相关 */ |
||||||
|
"mp-weixin" : { |
||||||
|
"appid" : "wx88cd6037d54f230a", |
||||||
|
"setting" : { |
||||||
|
"urlCheck" : false, |
||||||
|
"es6" : true, |
||||||
|
"minified" : true |
||||||
|
}, |
||||||
|
"usingComponents" : true |
||||||
|
}, |
||||||
|
"vueVersion" : "2" |
||||||
|
} |
@ -0,0 +1,329 @@ |
|||||||
|
<template> |
||||||
|
<view class="page"> |
||||||
|
<uni-card :is-shadow="false" :border="false" padding="0" is-full> |
||||||
|
<uni-search-bar class="search" radius="5" placeholder="请输入产品名称" clearButton="auto" cancelButton="none" v-model="keyword" /> |
||||||
|
</uni-card> |
||||||
|
|
||||||
|
<ul class="tab"> |
||||||
|
<li v-for="(tab, i) in tabs" :class="{active: curTab === tab.id}" @click="tabChange(tab)">{{ tab.name }}</li> |
||||||
|
</ul> |
||||||
|
|
||||||
|
<ul class="list"> |
||||||
|
<li v-for="(item, i) in list"> |
||||||
|
<uni-data-checkbox v-if="item.check" class="check" multiple :value="[1]" :localdata="item.checkData" @change="e => checkChange(e, i)"></uni-data-checkbox> |
||||||
|
<uni-data-checkbox v-else class="check" multiple v-model="item.check" :localdata="item.checkData" @change="e => checkChange(e, i)"></uni-data-checkbox> |
||||||
|
<image class="icon" :src="$util.getIcon(item)" mode="widthFix"></image> |
||||||
|
{{ item.productName }} |
||||||
|
</li> |
||||||
|
</ul> |
||||||
|
<uni-load-more :status="status" /> |
||||||
|
|
||||||
|
<view class="btn-wrap"> |
||||||
|
<uni-data-checkbox class="check" multiple v-model="checkAll" :localdata="checkAllData" @change="allChange"></uni-data-checkbox> |
||||||
|
<view class="btn" @click="submit">确定({{ checked.length }})</view> |
||||||
|
</view> |
||||||
|
</view> |
||||||
|
</template> |
||||||
|
|
||||||
|
<script> |
||||||
|
import { AppletsDataProductList } from '@/apis/modules/product.js' |
||||||
|
import { renew } from '@/apis/modules/order.js' |
||||||
|
export default { |
||||||
|
data() { |
||||||
|
return { |
||||||
|
orderType: 1, |
||||||
|
customerId: '', |
||||||
|
curTab: '', |
||||||
|
tabs: [ |
||||||
|
{ |
||||||
|
name: '全部', |
||||||
|
id: '' |
||||||
|
}, |
||||||
|
{ |
||||||
|
name: '实训课程', |
||||||
|
id: 1 |
||||||
|
}, |
||||||
|
{ |
||||||
|
name: '理论课程', |
||||||
|
id: 0 |
||||||
|
}, |
||||||
|
{ |
||||||
|
name: '数据产品', |
||||||
|
id: 2 |
||||||
|
} |
||||||
|
], |
||||||
|
reachBottom: 0, // 是否是上拉加载。0->否,1->是,-1->加载完所有数据 |
||||||
|
status: 'more', // 上拉加载状态 more|loading|noMore |
||||||
|
searchTimer: null, |
||||||
|
orderStatus: '', |
||||||
|
productStatus: '', |
||||||
|
keyword: '', |
||||||
|
list: [], |
||||||
|
listAll: [], |
||||||
|
page: 1, |
||||||
|
pageSize: 10, |
||||||
|
check: [1], |
||||||
|
noCheck: [], |
||||||
|
checkData: [{ |
||||||
|
text: '', |
||||||
|
value: 1 |
||||||
|
}], |
||||||
|
checkAll: [], |
||||||
|
checkAllData: [{ |
||||||
|
text: '全部', |
||||||
|
value: 1 |
||||||
|
}], |
||||||
|
checked: uni.getStorageSync('courses') || [], // 已经勾选的集合 |
||||||
|
courses: uni.getStorageSync('courses') || [] |
||||||
|
} |
||||||
|
}, |
||||||
|
watch: { |
||||||
|
keyword () { |
||||||
|
clearTimeout(this.searchTimer) |
||||||
|
this.searchTimer = setTimeout(() => { |
||||||
|
this.initList() |
||||||
|
}, 500) |
||||||
|
} |
||||||
|
}, |
||||||
|
// 下拉刷新 |
||||||
|
onPullDownRefresh() { |
||||||
|
this.initList() |
||||||
|
setTimeout(() => { |
||||||
|
uni.stopPullDownRefresh() |
||||||
|
}, 1500) |
||||||
|
}, |
||||||
|
// 上拉加载 |
||||||
|
onReachBottom() { |
||||||
|
if (this.reachBottom >= 0) { |
||||||
|
this.reachBottom = 1 |
||||||
|
this.status = 'loading' |
||||||
|
this.getList() |
||||||
|
} |
||||||
|
}, |
||||||
|
onShow() { |
||||||
|
const pages = getCurrentPages() |
||||||
|
const { options } = pages[pages.length - 1] |
||||||
|
this.orderType = options.orderType |
||||||
|
this.customerId = options.customerId |
||||||
|
this.getList() |
||||||
|
}, |
||||||
|
methods: { |
||||||
|
// 获取课程列表 |
||||||
|
getList() { |
||||||
|
uni.showLoading({ |
||||||
|
title: '加载中' |
||||||
|
}) |
||||||
|
AppletsDataProductList({ |
||||||
|
sort: 'desc', |
||||||
|
keywords: this.keyword, |
||||||
|
productType: this.curTab, |
||||||
|
pageNum: this.page, |
||||||
|
pageSize: this.pageSize |
||||||
|
}).then(({ data }) => { |
||||||
|
const { records } = data |
||||||
|
const list = this.courses |
||||||
|
const all = this.checkAll.length // 是否勾选了全选 |
||||||
|
const pageChange = this.reachBottom > 0 // 是否是翻页 |
||||||
|
const { checked } = this // 已选数据 |
||||||
|
// 添加选择框字段 |
||||||
|
records.map(e => { |
||||||
|
const checkData = { |
||||||
|
text: '', |
||||||
|
value: 1 |
||||||
|
} |
||||||
|
e.check = (all && pageChange) || checked.find(n => n.id === e.id && n.productType === e.productType) ? 1 : 0 |
||||||
|
// 筛选已经勾选的产品 |
||||||
|
if (list.find(n => n.dataOrCourseId == e.id && n.productType == e.productType)) { |
||||||
|
// 已经选择了的则禁止选择,并且直接选中 |
||||||
|
checkData.disable = true |
||||||
|
e.check = 1 |
||||||
|
} |
||||||
|
e.checkData = [checkData] |
||||||
|
}) |
||||||
|
|
||||||
|
// 未加载完所有数据,并且不是筛选,则拼接list,否则直接赋值 |
||||||
|
this.list = pageChange ? [...this.list, ...records] : records |
||||||
|
this.page++ // 每次获取了数据后page+1 |
||||||
|
const noMore = this.list.length === data.total // 是否加载完所有数据 |
||||||
|
this.status = noMore ? 'noMore' : 'more' // 加载完了则设置为noMore |
||||||
|
this.reachBottom = noMore ? -1 : 0 // 加载完了则设置为-1 |
||||||
|
uni.hideLoading() |
||||||
|
}).catch(e => { |
||||||
|
uni.hideLoading() |
||||||
|
}) |
||||||
|
}, |
||||||
|
initList() { |
||||||
|
this.page = 1 |
||||||
|
this.reachBottom = 0 |
||||||
|
this.getList() |
||||||
|
}, |
||||||
|
// tab切换 |
||||||
|
tabChange(tab) { |
||||||
|
this.curTab = tab.id |
||||||
|
this.initList() |
||||||
|
}, |
||||||
|
// 选择框回调 |
||||||
|
checkChange(e, i) { |
||||||
|
const { checked } = this |
||||||
|
const item = this.list[i] |
||||||
|
const { id, productType } = item |
||||||
|
const include = checked.findIndex(e => e.id === id && e.productType === productType) |
||||||
|
// 选中的情况下,该产品如果没有push到已选数组里,则push |
||||||
|
if (e.detail.value.length) { |
||||||
|
include === -1 && checked.push(item) |
||||||
|
} else { |
||||||
|
// 取消选中的情况下,如果已选数组里存在该产品,则移除 |
||||||
|
if (include !== -1) { |
||||||
|
checked.splice(include, 1) |
||||||
|
this.checkAll = [] |
||||||
|
} |
||||||
|
} |
||||||
|
}, |
||||||
|
// 全选 |
||||||
|
allChange(e) { |
||||||
|
const isCheck = !!e.detail.value.length // 是否选中 |
||||||
|
const { checked, list } = this |
||||||
|
list.map(e => { |
||||||
|
e.check = isCheck ? 1 : 0 |
||||||
|
const { id, productType } = e |
||||||
|
const include = checked.findIndex(n => n.id === id && n.productType === productType) |
||||||
|
// 选中的情况下,该产品如果没有push到已选数组里,则push |
||||||
|
if (isCheck) { |
||||||
|
include === -1 && checked.push(e) |
||||||
|
} else { |
||||||
|
// 取消选中的情况下,如果已选数组里存在该产品,则移除 |
||||||
|
include === -1 || checked.splice(include, 1) |
||||||
|
} |
||||||
|
}) |
||||||
|
}, |
||||||
|
// 生成产品参数 |
||||||
|
createParam(e) { |
||||||
|
const { orderType } = this |
||||||
|
const trial = orderType == 2 // 是否是试用 |
||||||
|
return { |
||||||
|
dataOrCourseId: e.id, // id |
||||||
|
productName: e.productName, // 名称 |
||||||
|
periodOfUse: '', // 使用期限 |
||||||
|
startTime: this.$util.formatDate(new Date(), 'yyyy-MM-dd'), // 开始 |
||||||
|
endTime: '', // 终止 |
||||||
|
remainingPeriod: '', // 剩余期限 |
||||||
|
marketValue: '', // 市场价 |
||||||
|
marketPrice: e.marketPrice, // 市场单价 |
||||||
|
finalPrice: trial ? 0 : '', // 成交价 |
||||||
|
finalValue: trial ? 0 : '', // 成交单价(数据产品特有) |
||||||
|
discountRate: trial ? '0%' : '', // 折扣率 |
||||||
|
accountNum: e.productType === 2 ? '' : 1, // 账号数 |
||||||
|
totalAmount: '', // 总价 |
||||||
|
isEnable: 1, // 启用否:1启用,0禁用 |
||||||
|
ship: 0, // 发货否(0未发货,1已发货,默认不发货) |
||||||
|
authority: e.productType === 2 ? 0 : 1, // 区分权限 0为数据平台权限,1为课程权限 |
||||||
|
productType: e.productType, // 课程分类 (0->理论 1-实训 2 数据产品) |
||||||
|
options: 2, |
||||||
|
miniProgramPictureAddress: e.miniProgramPictureAddress, // 图标 |
||||||
|
settlementPrice: trial ? 0 : '', // 结算价 |
||||||
|
settlementMethod: e.settlementMethod, // 结算方式,0为单价,1为分成 |
||||||
|
settlementPriceUnit: e.settlementPrice, // 结算单价 |
||||||
|
businessProportion: e.businessProportion, // 商务占比 |
||||||
|
serviceFee: 0 // 平台服务费(前端计算后展示,不入库) |
||||||
|
} |
||||||
|
}, |
||||||
|
// 判断是否为客户已有的课程 |
||||||
|
handleRenew(authority, customerId, productId, result, resolve, reject) { |
||||||
|
renew({ |
||||||
|
authority, |
||||||
|
customerId, |
||||||
|
productId |
||||||
|
}).then(({ orderOthers }) => { |
||||||
|
result.map(e => { |
||||||
|
const item = orderOthers.find(n => n.dataOrCourseId == e.dataOrCourseId && n.authority == authority && e.authority == authority) |
||||||
|
if (item) { |
||||||
|
let date = new Date(item.endTime) |
||||||
|
date = new Date(date.setDate(date.getDate() + 1)) |
||||||
|
e.startTime = this.$util.formatDate(date, 'yyyy-MM-dd') |
||||||
|
} |
||||||
|
}) |
||||||
|
resolve() |
||||||
|
}).catch(e => { |
||||||
|
reject() |
||||||
|
}) |
||||||
|
}, |
||||||
|
// 确定 |
||||||
|
submit() { |
||||||
|
const list = this.checked // 已选产品 |
||||||
|
if (list.length) { |
||||||
|
const result = this.courses |
||||||
|
const courseIds = [] |
||||||
|
const dataIds = [] |
||||||
|
const { customerId } = this |
||||||
|
list.map(e => { |
||||||
|
// 新勾选的产品,则获取到id,下面要调用, |
||||||
|
if (!result.find(n => (n.dataOrCourseId == e.id || n.dataOrCourseId == e.dataOrCourseId) && ((n.authority && e.productType != 2) || (!n.authority && e.productType == 2)))) { |
||||||
|
e.productType === 2 ? dataIds.push(e.id) : courseIds.push(e.id) |
||||||
|
result.push(this.createParam(e)) |
||||||
|
} |
||||||
|
}) |
||||||
|
const promises = [] |
||||||
|
// 课程和数据的分别调接口 |
||||||
|
dataIds.length && promises.push(new Promise((resolve, reject) => { |
||||||
|
this.handleRenew(0, customerId, dataIds, result, resolve, reject) |
||||||
|
})) |
||||||
|
courseIds.length && promises.push(new Promise((resolve, reject) => { |
||||||
|
this.handleRenew(1, customerId, courseIds, result, resolve, reject) |
||||||
|
})) |
||||||
|
Promise.all(promises).then(_ => { |
||||||
|
uni.setStorageSync('courses', result) // 把选中的产品添加至缓存 |
||||||
|
uni.redirectTo({ |
||||||
|
url: `../editCourse/editCourse?customerId=${customerId}&orderType=${this.orderType}` |
||||||
|
}) |
||||||
|
}) |
||||||
|
} else { |
||||||
|
this.$util.errMsg('请选择产品!') |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
</script> |
||||||
|
|
||||||
|
<style scoped lang="scss"> |
||||||
|
.page { |
||||||
|
padding-bottom: 130rpx; |
||||||
|
} |
||||||
|
.list { |
||||||
|
li { |
||||||
|
display: flex; |
||||||
|
align-items: center; |
||||||
|
padding: 30rpx 24rpx; |
||||||
|
margin: 16rpx 24rpx; |
||||||
|
font-size: 30rpx; |
||||||
|
color: #333; |
||||||
|
background-color: #fff; |
||||||
|
border-radius: 16rpx; |
||||||
|
} |
||||||
|
.icon { |
||||||
|
width: 80rpx; |
||||||
|
margin: 0 20rpx; |
||||||
|
} |
||||||
|
} |
||||||
|
/deep/.check { |
||||||
|
.checklist-box { |
||||||
|
margin: 0 !important; |
||||||
|
} |
||||||
|
.checkbox__inner { |
||||||
|
width: 40rpx !important; |
||||||
|
height: 40rpx !important; |
||||||
|
border-radius: 50% !important; |
||||||
|
} |
||||||
|
.checkbox__inner-icon { |
||||||
|
top: 8rpx !important; |
||||||
|
left: 14rpx !important; |
||||||
|
} |
||||||
|
} |
||||||
|
.btn-wrap { |
||||||
|
position: fixed; |
||||||
|
justify-content: space-between; |
||||||
|
.btn { |
||||||
|
width: 340rpx; |
||||||
|
margin-left: 27rpx; |
||||||
|
} |
||||||
|
} |
||||||
|
</style> |
@ -0,0 +1,266 @@ |
|||||||
|
<template> |
||||||
|
<view> |
||||||
|
<view class="filter"> |
||||||
|
<uni-search-bar class="search" radius="30" placeholder="请输入订单号、内容" v-model="keyword" clearButton="auto" cancelButton="none" /> |
||||||
|
<uni-icons class="icon" custom-prefix="iconfont" type="icon-filter" size="22" color="#007eff" @click="popup = true"></uni-icons> |
||||||
|
</view> |
||||||
|
|
||||||
|
<template v-if="list.length"> |
||||||
|
<view class="list"> |
||||||
|
<uni-swipe-action> |
||||||
|
<uni-swipe-action-item |
||||||
|
v-for="item in list" |
||||||
|
:threshold="0" |
||||||
|
:right-options="delOption" |
||||||
|
@click="del(item)" |
||||||
|
> |
||||||
|
<view class="item" @click="toDetail(item)"> |
||||||
|
<view class="c-name">{{ item.orderNumber }}</view> |
||||||
|
<view class="info"> |
||||||
|
<view class="left"> |
||||||
|
<view v-if="curTab" class="line"> |
||||||
|
<text class="name">商务经理:</text> |
||||||
|
<text class="val">{{ item.businessManagerName }}</text> |
||||||
|
</view> |
||||||
|
<view class="line"> |
||||||
|
<text class="name">客户名称:</text> |
||||||
|
<text class="val">{{ item.customerName }}</text> |
||||||
|
</view> |
||||||
|
<view class="line"> |
||||||
|
<text class="name">订单金额:</text> |
||||||
|
<text class="val">{{ item.orderAmount }}元</text> |
||||||
|
</view> |
||||||
|
<view class="line"> |
||||||
|
<text class="name">订单内容:</text> |
||||||
|
<view class="val ell-wrap"> |
||||||
|
<view :class="{ell: !item.toggle}">{{ item.productName }}</view> |
||||||
|
<view v-if="item.productName.length > 14" class="toggle" @click.stop="toggle(item)">{{ item.toggle ? '收起' : '展开' }}</view> |
||||||
|
</view> |
||||||
|
</view> |
||||||
|
<view class="line"> |
||||||
|
<text class="name">下单日期:</text> |
||||||
|
<text class="val">{{ item.createTime }}</text> |
||||||
|
</view> |
||||||
|
</view> |
||||||
|
<view :class="['type', 'type' + item.orderStatus]"> |
||||||
|
{{ filterData[0].data.find(e => e.value === item.orderStatus).title }} |
||||||
|
</view> |
||||||
|
</view> |
||||||
|
</view> |
||||||
|
</uni-swipe-action-item> |
||||||
|
</uni-swipe-action> |
||||||
|
</view> |
||||||
|
<uni-load-more :status="status" /> |
||||||
|
</template> |
||||||
|
<empty v-else></empty> |
||||||
|
|
||||||
|
<uni-icons class="plus" type="plus-filled" size="60" color="#007eff" @click="$util.to(`../orderDetail/orderDetail?customerId=${customerId}`)"></uni-icons> |
||||||
|
<filter-popup :data="filterData" :form.sync="filterForm" v-model="popup" title="全部筛选" height="1104rpx" @finsh="subFinsh"></filter-popup> |
||||||
|
</view> |
||||||
|
</template> |
||||||
|
|
||||||
|
<script> |
||||||
|
import { miniProgramOrderRecord, del } from '@/apis/modules/order.js' |
||||||
|
export default { |
||||||
|
data() { |
||||||
|
return { |
||||||
|
customerId: '', |
||||||
|
customerName: '', |
||||||
|
popup: false, |
||||||
|
//筛选表单数据 |
||||||
|
filterData: [ |
||||||
|
{ |
||||||
|
children: false,//是否有子项 |
||||||
|
title: "订单状态", |
||||||
|
key: "orderStatus", //键名 接收对象名字 |
||||||
|
keyValue: "value", //获取的值是哪个 |
||||||
|
isRadio: true, //是否单选 否则多选 |
||||||
|
data: [ |
||||||
|
{ |
||||||
|
title: "待发货", |
||||||
|
value: 0 |
||||||
|
}, |
||||||
|
{ |
||||||
|
title: "已完成", |
||||||
|
value: 1 |
||||||
|
}, |
||||||
|
], |
||||||
|
} |
||||||
|
], |
||||||
|
reachBottom: 0, // 是否是上拉加载。0->否,1->是,-1->加载完所有数据 |
||||||
|
status: 'more', // 上拉加载状态 more|loading|noMore |
||||||
|
filterForm: {}, |
||||||
|
searchTimer: null, |
||||||
|
orderStatus: '', |
||||||
|
keyword: '', |
||||||
|
list: [], |
||||||
|
page: 1, |
||||||
|
pageSize: 10, |
||||||
|
delOption: [{ |
||||||
|
text: '删除', |
||||||
|
style: { |
||||||
|
backgroundColor: '#F56C6C' |
||||||
|
} |
||||||
|
}] |
||||||
|
} |
||||||
|
}, |
||||||
|
watch: { |
||||||
|
keyword () { |
||||||
|
clearTimeout(this.searchTimer) |
||||||
|
this.searchTimer = setTimeout(() => { |
||||||
|
this.initList() |
||||||
|
}, 500) |
||||||
|
} |
||||||
|
}, |
||||||
|
// 上拉加载 |
||||||
|
onReachBottom() { |
||||||
|
if (this.reachBottom >= 0) { |
||||||
|
this.reachBottom = 1 |
||||||
|
this.status = 'loading' |
||||||
|
this.getList() |
||||||
|
} |
||||||
|
}, |
||||||
|
// 下拉刷新 |
||||||
|
onPullDownRefresh() { |
||||||
|
this.getList() |
||||||
|
setTimeout(() => { |
||||||
|
uni.stopPullDownRefresh() |
||||||
|
}, 1500) |
||||||
|
}, |
||||||
|
onShow() { |
||||||
|
const pages = getCurrentPages() |
||||||
|
const { options } = pages[pages.length - 1] |
||||||
|
this.customerId = options.customerId |
||||||
|
this.customerName = options.name |
||||||
|
this.initList() |
||||||
|
}, |
||||||
|
methods: { |
||||||
|
getList() { |
||||||
|
uni.showLoading({ |
||||||
|
title: '加载中' |
||||||
|
}) |
||||||
|
const team = uni.getStorageSync('team') |
||||||
|
const { orderStatus } = this |
||||||
|
miniProgramOrderRecord({ |
||||||
|
businessManagerId: this.$util.getBmId(), |
||||||
|
teamId: team.id, |
||||||
|
customerId: +this.customerId, |
||||||
|
orderStatus: orderStatus === '' ? null : orderStatus, |
||||||
|
isAdmin: +team.isTeam, // 是否是管理员(0否 1是) |
||||||
|
pageNum: this.page, |
||||||
|
pageSize: this.pageSize, |
||||||
|
keywords: this.keyword |
||||||
|
}).then(({ data }) => { |
||||||
|
const { records } = data |
||||||
|
records.map(e => { |
||||||
|
e.toggle = e.productName.length < 14 // 超过了14个字才需要显示展开按钮 |
||||||
|
}) |
||||||
|
this.list = this.reachBottom > 0 ? [...this.list, ...records] : records |
||||||
|
this.page++ // 每次获取了数据后page+1 |
||||||
|
const noMore = this.list.length === data.total // 是否加载完所有数据 |
||||||
|
this.status = noMore ? 'noMore' : 'more' // 加载完了则设置为noMore |
||||||
|
this.reachBottom = noMore ? -1 : 0 // 加载完了则设置为-1 |
||||||
|
uni.hideLoading() |
||||||
|
}).catch(e => { |
||||||
|
uni.hideLoading() |
||||||
|
}) |
||||||
|
}, |
||||||
|
initList() { |
||||||
|
this.page = 1 |
||||||
|
this.reachBottom = 0 |
||||||
|
this.getList() |
||||||
|
}, |
||||||
|
// 展开 |
||||||
|
toggle(item) { |
||||||
|
item.toggle = !item.toggle |
||||||
|
}, |
||||||
|
// 筛选确定回调 |
||||||
|
subFinsh(val) { |
||||||
|
const { orderStatus } = val |
||||||
|
this.orderStatus = orderStatus.length ? orderStatus[0] : '' |
||||||
|
this.initList() |
||||||
|
}, |
||||||
|
// 跳转详情 |
||||||
|
toDetail(item) { |
||||||
|
this.$util.to(`../orderDetail/orderDetail?orderId=${item.orderId}&show=1`) |
||||||
|
}, |
||||||
|
// 删除 |
||||||
|
del(e) { |
||||||
|
const that = this |
||||||
|
uni.showModal({ |
||||||
|
title: '提示', |
||||||
|
content: '确定要删除吗?', |
||||||
|
success(res) { |
||||||
|
if (res.confirm) { |
||||||
|
del({ |
||||||
|
ids: [e.orderId] |
||||||
|
}).then(res => { |
||||||
|
that.$util.sucMsg('删除成功') |
||||||
|
that.getList() |
||||||
|
}).catch(res => {}) |
||||||
|
} |
||||||
|
} |
||||||
|
}) |
||||||
|
}, |
||||||
|
} |
||||||
|
} |
||||||
|
</script> |
||||||
|
|
||||||
|
<style scoped lang="scss"> |
||||||
|
.list { |
||||||
|
margin-top: 20rpx; |
||||||
|
background-color: #fff; |
||||||
|
.item { |
||||||
|
padding: 20rpx 40rpx; |
||||||
|
border-bottom: 1px solid #f1f1f1; |
||||||
|
} |
||||||
|
.c-name { |
||||||
|
font-size: 30rpx; |
||||||
|
color: #333; |
||||||
|
} |
||||||
|
.info { |
||||||
|
display: flex; |
||||||
|
justify-content: space-between; |
||||||
|
align-items: center; |
||||||
|
margin-top: 10rpx; |
||||||
|
} |
||||||
|
.left { |
||||||
|
max-width: 70%; |
||||||
|
} |
||||||
|
.line { |
||||||
|
display: flex; |
||||||
|
padding: 10rpx 0; |
||||||
|
} |
||||||
|
.name { |
||||||
|
margin-right: 10rpx; |
||||||
|
white-space: nowrap; |
||||||
|
font-size: 28rpx; |
||||||
|
color: #999; |
||||||
|
} |
||||||
|
.val { |
||||||
|
max-width: 88%; |
||||||
|
font-size: 28rpx; |
||||||
|
color: #333; |
||||||
|
} |
||||||
|
.ell { |
||||||
|
white-space: nowrap; |
||||||
|
text-overflow: ellipsis; |
||||||
|
overflow: hidden; |
||||||
|
} |
||||||
|
.toggle { |
||||||
|
margin-top: 10rpx; |
||||||
|
white-space: nowrap; |
||||||
|
font-size: 24rpx; |
||||||
|
color: #0e92ef; |
||||||
|
} |
||||||
|
.type { |
||||||
|
margin-left: 20rpx; |
||||||
|
font-size: 28rpx; |
||||||
|
color: #ff7b2d; |
||||||
|
white-space: nowrap; |
||||||
|
} |
||||||
|
.type1 { |
||||||
|
color: #bdbdbd; |
||||||
|
} |
||||||
|
} |
||||||
|
</style> |
@ -0,0 +1,420 @@ |
|||||||
|
<template> |
||||||
|
<view class="page"> |
||||||
|
<template v-for="c in courses"> |
||||||
|
<view v-if="c.list.length" class="block"> |
||||||
|
<view class="l-title">{{ c.name }}</view> |
||||||
|
<uni-icons class="arrow" type="top" size="20" color="#007EFF" @click="toggle(c)"></uni-icons> |
||||||
|
<view v-show="!c.shrink"> |
||||||
|
<view v-for="(item, i) in c.list"> |
||||||
|
<view class="pro-name"> |
||||||
|
<view class="left"> |
||||||
|
<image class="icon" :src="$util.getIcon(item)" mode="widthFix"></image> |
||||||
|
{{ item.productName }} |
||||||
|
</view> |
||||||
|
<uni-icons class="del" type="trash" size="25" color="#ADADAD" @click="delCourse(c, i)"></uni-icons> |
||||||
|
</view> |
||||||
|
<view class="form-list"> |
||||||
|
<view class="line"> |
||||||
|
<view class="name">产品类型</view> |
||||||
|
<view class="val">{{ productTypes.find(e => e.id === item.productType).name }}</view> |
||||||
|
</view> |
||||||
|
<view :class="['line req', {err: err === 'periodOfUse' + item.dataOrCourseId + item.authority}]"> |
||||||
|
<view class="name">使用期限</view> |
||||||
|
<input class="period" type="number" v-model="item.periodOfUse" placeholder="请输入" @input="calcDate(item, !item.authority)" @change="handleErr(item, 'periodOfUse')"> |
||||||
|
<view class="val unit" @click="selectUnit(item)"> |
||||||
|
<text>{{ units.find(e => e.id === item.options).text }}</text> |
||||||
|
<image class="icon" src="@/static/image/arrow-down.png" mode="widthFix"></image> |
||||||
|
</view> |
||||||
|
</view> |
||||||
|
<view :class="['line req', {err: err === 'startTime' + item.dataOrCourseId + item.authority}]"> |
||||||
|
<view class="name">起止日期</view> |
||||||
|
<uni-datetime-picker type="date" v-model="item.startTime" :border="false" @change="calcDate(item)"> |
||||||
|
<view :class="['ph', {val: item.startTime}]"> |
||||||
|
{{ item.endTime ? item.startTime + ' - ' + item.endTime : item.startTime}} |
||||||
|
</view> |
||||||
|
</uni-datetime-picker> |
||||||
|
</view> |
||||||
|
<view :class="['line req', {err: err === 'accountNum' + item.dataOrCourseId + item.authority}]"> |
||||||
|
<view class="name">数量</view> |
||||||
|
<view v-if="item.authority" class="val">1</view> |
||||||
|
<input v-else type="number" v-model="item.accountNum" placeholder="请输入账号数量" @input="calcFinalPrice(item)" @change="handleErr(item, 'accountNum')"> |
||||||
|
</view> |
||||||
|
<view class="line"> |
||||||
|
<view class="name">{{ item.authority ? '市场价' : '市场单价' }}</view> |
||||||
|
<view class="val">{{ item.marketValue }}元</view> |
||||||
|
</view> |
||||||
|
<view class="line"> |
||||||
|
<view class="name">结算价</view> |
||||||
|
<view class="val">{{ item.settlementPrice }}元</view> |
||||||
|
</view> |
||||||
|
<view class="line"> |
||||||
|
<view class="name">折扣率</view> |
||||||
|
<view class="val">{{ item.discountRate }}</view> |
||||||
|
</view> |
||||||
|
<view class="line"> |
||||||
|
<view class="name">平台服务费</view> |
||||||
|
<view class="val">{{ item.serviceFee }}元</view> |
||||||
|
</view> |
||||||
|
<view :class="['line req', {err: err === 'finalPrice' + item.dataOrCourseId + item.authority}]"> |
||||||
|
<view class="name">成交价</view> |
||||||
|
<view class="inline"> |
||||||
|
<input type="number" v-model="item.finalPrice" placeholder="请输入" @input="calcFinalValue(item)" @change="handleErr(item, 'finalPrice')"> |
||||||
|
元 |
||||||
|
</view> |
||||||
|
</view> |
||||||
|
</view> |
||||||
|
</view> |
||||||
|
</view> |
||||||
|
</view> |
||||||
|
</template> |
||||||
|
<view class="btn-wrap"> |
||||||
|
<view class="btn" @click="submit">确定</view> |
||||||
|
</view> |
||||||
|
</view> |
||||||
|
</template> |
||||||
|
|
||||||
|
<script> |
||||||
|
import { getOrderOtherTime } from '@/apis/modules/order.js' |
||||||
|
export default { |
||||||
|
data() { |
||||||
|
return { |
||||||
|
orderType: 1, |
||||||
|
customerId: '', |
||||||
|
timer: null, |
||||||
|
units: [{ |
||||||
|
text: '日', |
||||||
|
id: 0 |
||||||
|
}, { |
||||||
|
text: '月', |
||||||
|
id: 1 |
||||||
|
}, { |
||||||
|
text: '年', |
||||||
|
id: 2 |
||||||
|
}], |
||||||
|
unitText: ['日', '月', '年'], |
||||||
|
productTypes: [ |
||||||
|
{ |
||||||
|
name: '实训课程', |
||||||
|
id: 1 |
||||||
|
}, |
||||||
|
{ |
||||||
|
name: '理论课程', |
||||||
|
id: 0 |
||||||
|
}, |
||||||
|
{ |
||||||
|
name: '数据产品', |
||||||
|
id: 2 |
||||||
|
} |
||||||
|
], |
||||||
|
courses: {} , // 上一页缓存的产品 |
||||||
|
orderRepeat: [], |
||||||
|
repeatMsg: '', |
||||||
|
err: '' |
||||||
|
} |
||||||
|
}, |
||||||
|
onShow() { |
||||||
|
const pages = getCurrentPages() |
||||||
|
const { options } = pages[pages.length - 1] |
||||||
|
this.orderType = options.orderType |
||||||
|
this.customerId = options.customerId |
||||||
|
this.handleProduct() |
||||||
|
}, |
||||||
|
methods: { |
||||||
|
// 转换产品列表 |
||||||
|
handleProduct() { |
||||||
|
const list = uni.getStorageSync('courses') |
||||||
|
const courses = { |
||||||
|
practice: { |
||||||
|
shrink: false, |
||||||
|
name: '实训课程产品', |
||||||
|
list: [] |
||||||
|
}, |
||||||
|
theory: { |
||||||
|
shrink: false, |
||||||
|
name: '理论课程产品', |
||||||
|
list: [] |
||||||
|
}, |
||||||
|
data: { |
||||||
|
shrink: false, |
||||||
|
name: '数据产品', |
||||||
|
list: [] |
||||||
|
} |
||||||
|
} |
||||||
|
// 3个分类的课程分别push到不同数组(0->理论 1-实训 2 数据产品) |
||||||
|
list.map(e => { |
||||||
|
const type = e.productType |
||||||
|
!type ? |
||||||
|
courses.theory.list.push(e) : |
||||||
|
type === 1 ? |
||||||
|
courses.practice.list.push(e) : |
||||||
|
courses.data.list.push(e) |
||||||
|
|
||||||
|
}) |
||||||
|
this.courses = courses |
||||||
|
try { |
||||||
|
uni.removeStorageSync('courses') |
||||||
|
} catch (e) {} |
||||||
|
}, |
||||||
|
selectUnit(item) { |
||||||
|
const that = this |
||||||
|
uni.showActionSheet({ |
||||||
|
title: '标题', |
||||||
|
itemList: that.unitText, |
||||||
|
success: ({ tapIndex }) => { |
||||||
|
item.options = tapIndex |
||||||
|
that.calcDate(item) |
||||||
|
} |
||||||
|
}) |
||||||
|
}, |
||||||
|
showUnit(i) { |
||||||
|
this.$refs.unit[i].show() |
||||||
|
}, |
||||||
|
// 收缩产品 |
||||||
|
toggle(c) { |
||||||
|
c.shrink = !c.shrink |
||||||
|
}, |
||||||
|
// 删除课程 |
||||||
|
delCourse(c, i) { |
||||||
|
uni.showModal({ |
||||||
|
title: '提示', |
||||||
|
content: '确定要删除吗?', |
||||||
|
success(res) { |
||||||
|
res.confirm && c.list.splice(i, 1) |
||||||
|
} |
||||||
|
}) |
||||||
|
}, |
||||||
|
// 使用期限转换以及计算剩余天数 |
||||||
|
calcDate(row, fromData) { |
||||||
|
clearTimeout(this.timer) |
||||||
|
this.timer = setTimeout(() => { |
||||||
|
const { periodOfUse, options } = row |
||||||
|
let optionsData = 0 |
||||||
|
if (periodOfUse) { |
||||||
|
if (options == 1){ |
||||||
|
optionsData = periodOfUse === '12' ? 31536000000 : periodOfUse*30*24*60*60*1000 |
||||||
|
} else if (options == 2){ |
||||||
|
optionsData = periodOfUse*365*24*60*60*1000 |
||||||
|
} else { |
||||||
|
optionsData = periodOfUse*24*60*60*1000 |
||||||
|
} |
||||||
|
} |
||||||
|
let time = new Date(row.startTime).getTime() |
||||||
|
let endTime = time + optionsData |
||||||
|
row.endTime = time + optionsData |
||||||
|
let dt = new Date(endTime) |
||||||
|
row.endTime = (dt.getFullYear()) + "-" + (dt.getMonth() + 1) + "-" + (dt.getDate()) |
||||||
|
let endYear = endTime - time |
||||||
|
let endYears = endYear/1000/60/60/24 |
||||||
|
row.remainingPeriod = endYears |
||||||
|
const unit = row.options // 使用期限单位 |
||||||
|
const useUnit = row.periodOfUse // 使用期限 |
||||||
|
// 计算市场价 |
||||||
|
const price = row.marketPrice // 市场单价 |
||||||
|
// 结算单价是元/年,所以如果选择的不是年,要进行换算(日:/365,月:/12) |
||||||
|
row.marketValue = (!unit ? |
||||||
|
price / 365 * useUnit : |
||||||
|
unit === 1 ? |
||||||
|
price / 12 * useUnit : |
||||||
|
price * useUnit).toFixed(2) |
||||||
|
this.dealSettlePrice(row) |
||||||
|
// 只有改变了起止日期才需要调接口查询订单,该接口作用是把开始时间传过去,会返回一个提示或者时间,如果是时间,则把时间+1天,如果是提示,则无法保存 |
||||||
|
if (!fromData) { |
||||||
|
const cId = row.dataOrCourseId |
||||||
|
const date = new Date(row.startTime) |
||||||
|
const orderRepeat = this.orderRepeat |
||||||
|
getOrderOtherTime({ |
||||||
|
customerId: this.customerId, |
||||||
|
id: cId, |
||||||
|
startTime: this.$util.formatDate(date, 'yyyy-MM-dd'), |
||||||
|
endTime: row.endTime |
||||||
|
}).then(res => { |
||||||
|
orderRepeat.includes(cId) && orderRepeat.splice(orderRepeat.findIndex(e => e === cId), 1) |
||||||
|
if (res.endTime) { |
||||||
|
let time = new Date(res.endTime) |
||||||
|
time = new Date(time.setDate(time.getDate() + 1)) |
||||||
|
row.startTime = this.$util.formatDate(time, 'yyyy-MM-dd') |
||||||
|
} |
||||||
|
}).catch(res => { |
||||||
|
this.repeatMsg = res.message |
||||||
|
orderRepeat.includes(cId) || orderRepeat.push(cId) |
||||||
|
}) |
||||||
|
} |
||||||
|
// 折扣率 |
||||||
|
this.calcDiscount(row) |
||||||
|
}, 500) |
||||||
|
}, |
||||||
|
// 计算结算价及平台服务费 |
||||||
|
dealSettlePrice(row) { |
||||||
|
// 如果是试用,结算价和平台服务费都是0 |
||||||
|
if (this.orderType == 2) { |
||||||
|
row.settlementPrice = 0 |
||||||
|
row.serviceFee = 0 |
||||||
|
} else { |
||||||
|
const unit = row.options // 使用期限单位 |
||||||
|
const useUnit = row.periodOfUse // 使用期限 |
||||||
|
let sPrice = '' |
||||||
|
if (row.settlementMethod == 0) { |
||||||
|
// 结算单价。计算规则:结算单价(**元/年)*购买时长(单位年)*数量(课程为1,数据为账号数量) |
||||||
|
const priceUnit = row.settlementPriceUnit |
||||||
|
sPrice = ((!unit ? |
||||||
|
priceUnit / 365 * useUnit : |
||||||
|
unit === 1 ? |
||||||
|
priceUnit / 12 * useUnit : |
||||||
|
priceUnit * useUnit) * (row.authority ? |
||||||
|
1 : |
||||||
|
row.accountNum)).toFixed((2)) |
||||||
|
} else { |
||||||
|
// 比例分成。计算规则:成交价*商务分成比例 |
||||||
|
sPrice = (row.finalPrice * row.businessProportion / 100).toFixed((2)) |
||||||
|
} |
||||||
|
row.settlementPrice = this.$util.handleNaN(sPrice) |
||||||
|
// 平台服务费(结算价*10%) |
||||||
|
if (row.settlementPrice) { |
||||||
|
row.serviceFee = (row.settlementPrice * 0.1).toFixed(2) |
||||||
|
} |
||||||
|
} |
||||||
|
}, |
||||||
|
// 计算折扣率 |
||||||
|
calcDiscount(row) { |
||||||
|
const price = row.authority ? row.finalPrice : row.finalValue |
||||||
|
const { marketValue } = row |
||||||
|
// (原价-现价)÷原价 x100% |
||||||
|
if (price) row.discountRate = marketValue != 0 ? ((marketValue - price) / marketValue * 100).toFixed(2) + '%' : '0%' |
||||||
|
}, |
||||||
|
// 成交价修改后,计算成交单价,数据才需要 计算规则:成交价/账号数/时间(成交单价为元/账号/年,所以时间要换算成年的单位去计算) |
||||||
|
calcFinalValue(row) { |
||||||
|
clearTimeout(this.timer) |
||||||
|
this.timer = setTimeout(() => { |
||||||
|
const { authority, periodOfUse, options, accountNum, finalPrice } = row |
||||||
|
if (!authority && periodOfUse && accountNum && finalPrice) { |
||||||
|
row.finalValue = (finalPrice / accountNum / periodOfUse).toFixed(2) |
||||||
|
} |
||||||
|
// 折扣率 |
||||||
|
this.calcDiscount(row) |
||||||
|
this.dealSettlePrice(row) |
||||||
|
}, 500) |
||||||
|
}, |
||||||
|
// 计算成交价。计算规则:成交单价*账号数*时间(成交单价为元/账号/年,所以时间要换算成年的单位去计算) |
||||||
|
calcFinalPrice(row) { |
||||||
|
clearTimeout(this.timer) |
||||||
|
this.timer = setTimeout(() => { |
||||||
|
const { finalValue, accountNum, periodOfUse, finalPrice } = row |
||||||
|
if (periodOfUse) { |
||||||
|
if (accountNum) { |
||||||
|
// 有成交单价,则成交价=成交单价*账号数*时间 |
||||||
|
if (finalValue) { |
||||||
|
row.finalPrice = Math.round(finalValue * periodOfUse * accountNum) |
||||||
|
} else if (!finalValue && finalPrice) { |
||||||
|
// 有成交价,没有成交单价,则成交单价=成交价/账号数/时间 |
||||||
|
row.finalValue = (finalPrice / periodOfUse / accountNum).toFixed(2) |
||||||
|
this.calcDiscount(row) |
||||||
|
} |
||||||
|
} else if (finalValue && finalPrice && !row.authority) { |
||||||
|
// 有成交价、成交单价,没有数量,则数量=成交价/时间/成交单价 |
||||||
|
row.accountNum = Math.floor(finalPrice / periodOfUse / finalValue) |
||||||
|
} |
||||||
|
} |
||||||
|
this.dealSettlePrice(row) |
||||||
|
}, 500) |
||||||
|
}, |
||||||
|
// 处理错误提示 |
||||||
|
handleErr(e, val) { |
||||||
|
if (val + e.dataOrCourseId + e.authority === this.err) this.err = '' |
||||||
|
}, |
||||||
|
// 确定 |
||||||
|
submit() { |
||||||
|
const courses = this.courses |
||||||
|
const list = [] |
||||||
|
let msg = '' |
||||||
|
// 全部产品push到一个数组,方便校验 |
||||||
|
for (const i in courses) { |
||||||
|
list.push(...courses[i].list) |
||||||
|
} |
||||||
|
console.log(11, list) |
||||||
|
// 必填校验 |
||||||
|
for (const i in list) { |
||||||
|
const e = list[i] |
||||||
|
const suf = e.dataOrCourseId + '' + e.authority |
||||||
|
if (e.periodOfUse === '') { |
||||||
|
this.err = 'periodOfUse' + suf |
||||||
|
msg = '请输入使用期限!' |
||||||
|
break |
||||||
|
} |
||||||
|
if (!e.startTime) { |
||||||
|
this.err = 'startTime' + suf |
||||||
|
msg = '请选择起止日期!' |
||||||
|
break |
||||||
|
} |
||||||
|
if (e.accountNum === '') { |
||||||
|
this.err = 'accountNum' + suf |
||||||
|
msg = '请输入数量!' |
||||||
|
break |
||||||
|
} |
||||||
|
if (e.finalPrice === '') { |
||||||
|
this.err = 'finalPrice' + suf |
||||||
|
msg = '请输入成交价!' |
||||||
|
break |
||||||
|
} |
||||||
|
} |
||||||
|
console.log(33, this.err) |
||||||
|
if (msg) return this.$util.errMsg(msg) |
||||||
|
if (this.orderRepeat.length) return this.$util.errMsg(this.repeatMsg) // 有重复订单不能提交 |
||||||
|
uni.setStorageSync('courses', this.courses) |
||||||
|
uni.navigateBack() |
||||||
|
}, |
||||||
|
} |
||||||
|
} |
||||||
|
</script> |
||||||
|
|
||||||
|
<style scoped lang="scss"> |
||||||
|
.page { |
||||||
|
padding-bottom: 130rpx; |
||||||
|
-webkit-overflow-scrolling: touch; |
||||||
|
} |
||||||
|
.block { |
||||||
|
position: relative; |
||||||
|
padding: 0; |
||||||
|
.l-title { |
||||||
|
margin: 0 24rpx; |
||||||
|
} |
||||||
|
} |
||||||
|
.arrow { |
||||||
|
position: absolute; |
||||||
|
top: 30rpx; |
||||||
|
right: 30rpx; |
||||||
|
} |
||||||
|
.pro-name { |
||||||
|
display: flex; |
||||||
|
justify-content: space-between; |
||||||
|
align-items: center; |
||||||
|
padding: 14rpx 24rpx; |
||||||
|
font-size: 30rpx; |
||||||
|
color: #333; |
||||||
|
background: linear-gradient(90deg, #FFF5E5 0%, #FFFFFF 100%); |
||||||
|
.left { |
||||||
|
display: inline-flex; |
||||||
|
align-items: center; |
||||||
|
} |
||||||
|
.icon { |
||||||
|
width: 60rpx; |
||||||
|
height: 60rpx; |
||||||
|
margin-right: 12rpx; |
||||||
|
border-radius: 10rpx; |
||||||
|
} |
||||||
|
} |
||||||
|
.form-list { |
||||||
|
padding: 0 24rpx; |
||||||
|
border-top: 0; |
||||||
|
.period { |
||||||
|
text-align: center; |
||||||
|
} |
||||||
|
.unit { |
||||||
|
display: inline-flex; |
||||||
|
align-items: center; |
||||||
|
.icon { |
||||||
|
width: 28rpx; |
||||||
|
margin-left: 20rpx; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
</style> |
@ -0,0 +1,644 @@ |
|||||||
|
<template> |
||||||
|
<view :class="['page', { show: isDetail }]"> |
||||||
|
<view class="block"> |
||||||
|
<view class="l-title">基本信息</view> |
||||||
|
<view class="form-list"> |
||||||
|
<view class="line"> |
||||||
|
<view class="name">商务经理</view> |
||||||
|
<view class="val">{{ form.businessManagerName }}</view> |
||||||
|
</view> |
||||||
|
<view :class="['line req', {err: err === 'customerName'}]"> |
||||||
|
<view class="name">客户名称</view> |
||||||
|
<view v-if="isDetail" class="val">{{ form.customerName }}</view> |
||||||
|
<view v-else :class="['ph', {val: form.customerName}]" @click="customerVisible = true">{{ form.customerName || '请选择客户' }}</view> |
||||||
|
</view> |
||||||
|
<view class="line"> |
||||||
|
<view class="name">省份</view> |
||||||
|
<view class="val">{{ form.provinceName }}</view> |
||||||
|
</view> |
||||||
|
<view class="line"> |
||||||
|
<view class="name">城市</view> |
||||||
|
<view class="val">{{ form.cityName }}</view> |
||||||
|
</view> |
||||||
|
<view class="line"> |
||||||
|
<view class="name">联系人</view> |
||||||
|
<view class="val">{{ form.orderContact }}</view> |
||||||
|
</view> |
||||||
|
<view class="line"> |
||||||
|
<view class="name">电话</view> |
||||||
|
<view class="val">{{ form.phone }}</view> |
||||||
|
</view> |
||||||
|
<view class="line"> |
||||||
|
<view class="name">邮箱</view> |
||||||
|
<view class="val">{{ form.email }}</view> |
||||||
|
</view> |
||||||
|
<view :class="['line req', {err: err === 'orderType'}]"> |
||||||
|
<view class="name">订单类型</view> |
||||||
|
<view v-if="isDetail" class="val">{{ orderTypes.find(e => e.value === form.orderType).text }}</view> |
||||||
|
<uni-data-picker v-else class="picker-input" placeholder="请选择订单类型" popup-title="请选择订单类型" preload :clear-icon="false" :localdata="orderTypes" v-model="form.orderType" @change="calcTotal(1)"></uni-data-picker> |
||||||
|
</view> |
||||||
|
<view class="line"> |
||||||
|
<view class="name">订单编号</view> |
||||||
|
<view class="val">{{ form.orderNumber }}</view> |
||||||
|
</view> |
||||||
|
<view class="line"> |
||||||
|
<view class="name">订单时间</view> |
||||||
|
<view class="val">{{ form.createTime }}</view> |
||||||
|
</view> |
||||||
|
<view class="line"> |
||||||
|
<view class="name">订单金额(元)</view> |
||||||
|
<view class="val">{{ form.orderAmount }}</view> |
||||||
|
</view> |
||||||
|
</view> |
||||||
|
</view> |
||||||
|
|
||||||
|
<template v-for="c in courseList"> |
||||||
|
<view v-if="c.list.length" class="block pro-wrap" id="products"> |
||||||
|
<view class="l-title">{{ c.name }}</view> |
||||||
|
<uni-icons class="arrow" type="top" size="20" color="#007EFF" @click="toggle(c)"></uni-icons> |
||||||
|
<ul class="pro-list" v-show="!c.shrink"> |
||||||
|
<li v-for="(item, i) in c.list" @click.stop="editCourse(c, i)"> |
||||||
|
<view class="name"> |
||||||
|
<view class="left"> |
||||||
|
<image class="icon" :src="$util.getIcon(item)" mode="widthFix"></image> |
||||||
|
{{ item.productName }} |
||||||
|
</view> |
||||||
|
<image v-if="!isDetail" class="del" src="@/static/image/trash.png" mode="widthFix" @click.stop="delCourse(c, i)"></image> |
||||||
|
</view> |
||||||
|
<view class="info"> |
||||||
|
<view class="line"> |
||||||
|
<view class="label">使用期限</view> |
||||||
|
<view class="val">{{ item.startTime + ' - ' + item.endTime }}</view> |
||||||
|
</view> |
||||||
|
<view class="line"> |
||||||
|
<view class="label">市场价(元)</view> |
||||||
|
<view class="val">{{ item.marketValue }}元</view> |
||||||
|
</view> |
||||||
|
<view class="line"> |
||||||
|
<view class="label">结算价</view> |
||||||
|
<view class="val">{{ item.settlementPrice }}元</view> |
||||||
|
</view> |
||||||
|
<view class="line"> |
||||||
|
<view class="label">折扣率</view> |
||||||
|
<view class="val">{{ item.discountRate }}</view> |
||||||
|
</view> |
||||||
|
<view class="line"> |
||||||
|
<view class="label">平台服务费</view> |
||||||
|
<view class="val">{{ item.serviceFee }}元</view> |
||||||
|
</view> |
||||||
|
<view class="line done"> |
||||||
|
<view class="val">成交价格</view> |
||||||
|
<view class="price">{{ item.finalPrice }}元</view> |
||||||
|
</view> |
||||||
|
</view> |
||||||
|
</li> |
||||||
|
</ul> |
||||||
|
</view> |
||||||
|
</template> |
||||||
|
|
||||||
|
<view class="bottom"> |
||||||
|
<view v-if="!orderId" class="add-wrap"> |
||||||
|
<view class="add-btn" @click="toAdd"> |
||||||
|
<uni-icons class="icon" type="plus" color="#007FFF"></uni-icons> |
||||||
|
添加产品 |
||||||
|
</view> |
||||||
|
</view> |
||||||
|
|
||||||
|
<view :class="['product', isDetail ? 'show' : 'edit']"> |
||||||
|
<view class="text"> |
||||||
|
<view class="total"> |
||||||
|
<view v-if="isDetail">共选<text class="num">{{ courses.length }}</text>个产品</view> |
||||||
|
<view class="column">总成交价合计<text class="num">{{ form.orderAmount }}</text>元</view> |
||||||
|
</view> |
||||||
|
<view class="info"> |
||||||
|
<view class="line"> |
||||||
|
总采购成本:<text class="num">{{ form.purchaseCost }}</text>元 |
||||||
|
</view> |
||||||
|
<view class="line"> |
||||||
|
总产品利润:<text class="num"> {{ form.profit }}</text> 元 |
||||||
|
</view> |
||||||
|
</view> |
||||||
|
</view> |
||||||
|
<view v-if="!isDetail" class="btn" @click="submit">提交({{ courses.length }})</view> |
||||||
|
</view> |
||||||
|
</view> |
||||||
|
|
||||||
|
<view class="popup-mask" v-show="customerVisible" @click="closeCustomer"></view> |
||||||
|
<view class="popup" v-show="customerVisible"> |
||||||
|
<view class="top">请选择客户</view> |
||||||
|
<uni-icons class="close" type="closeempty" size="20" @click="closeCustomer"></uni-icons> |
||||||
|
<uni-search-bar class="search" radius="5" placeholder="请输入客户名称" v-model="keyword" clearButton="auto" cancelButton="none" /> |
||||||
|
<view class="list"> |
||||||
|
<view class="item" v-for="item in customerList" @click="customerChange(item)">{{ item.customerName }}</view> |
||||||
|
</view> |
||||||
|
</view> |
||||||
|
</view> |
||||||
|
</template> |
||||||
|
|
||||||
|
<script> |
||||||
|
import { queryCustomer, queryCustomerDetails } from '@/apis/modules/client.js' |
||||||
|
import { add, update, getDetail } from '@/apis/modules/order.js' |
||||||
|
export default { |
||||||
|
data() { |
||||||
|
return { |
||||||
|
isDetail: false, |
||||||
|
orderId: '', |
||||||
|
orderTypes: [{ |
||||||
|
text: '正式', |
||||||
|
value: 1 |
||||||
|
}, { |
||||||
|
text: '试用', |
||||||
|
value: 2 |
||||||
|
}], |
||||||
|
form: { |
||||||
|
businessManagerName: uni.getStorageSync('team').userName, |
||||||
|
// orderNumber: '', // 编号 |
||||||
|
provinceId: '', // 省份id |
||||||
|
provinceName: '', |
||||||
|
orderContact: '', // 联系人 |
||||||
|
email: '', |
||||||
|
customerId: '', // 客户id |
||||||
|
customerName: '', |
||||||
|
orderType: '', |
||||||
|
cityId: '', |
||||||
|
cityName: '', |
||||||
|
phone: '', |
||||||
|
orderAmount: 0, |
||||||
|
customerName: '', |
||||||
|
profit: 0, // 利润 |
||||||
|
purchaseCost: 0, // 采购成本 |
||||||
|
teamId: uni.getStorageSync('team').id, |
||||||
|
businessManagerId: this.$util.getBmId() |
||||||
|
}, |
||||||
|
courseList: {}, |
||||||
|
courses: [], // 缓存的产品列表 |
||||||
|
contract: { // 合同信息 |
||||||
|
contractName: '', // 合同名称 |
||||||
|
contractFile: '', // 合同文件 |
||||||
|
contractMoney: '', // 合同金额 |
||||||
|
contractNumber: '',// 合同编号 |
||||||
|
startTime: '', // 期限-头 |
||||||
|
endTime: '' // 期限-尾 |
||||||
|
}, |
||||||
|
|
||||||
|
customerVisible: false, |
||||||
|
keyword: '', |
||||||
|
searchTimer: null, |
||||||
|
customerList: [], |
||||||
|
customerListAll: [], |
||||||
|
err: '' |
||||||
|
} |
||||||
|
}, |
||||||
|
watch: { |
||||||
|
keyword () { |
||||||
|
clearTimeout(this.searchTimer) |
||||||
|
this.searchTimer = setTimeout(() => { |
||||||
|
this.filterCustomer() |
||||||
|
}, 500) |
||||||
|
} |
||||||
|
}, |
||||||
|
onShow() { |
||||||
|
const pages = getCurrentPages() |
||||||
|
const { options } = pages[pages.length - 1] |
||||||
|
this.orderId = options.orderId |
||||||
|
this.isDetail = !!options.show |
||||||
|
const store = uni.getStorageSync('courses') |
||||||
|
if (this.orderId) { |
||||||
|
this.getInfo() |
||||||
|
} else if (store) { |
||||||
|
// 新增取缓存,取了删除 |
||||||
|
const list = [] |
||||||
|
for (const i in store) { |
||||||
|
list.push(...store[i].list) |
||||||
|
} |
||||||
|
this.courseList = store |
||||||
|
this.courses = list |
||||||
|
this.$nextTick(() => { |
||||||
|
uni.pageScrollTo({ |
||||||
|
selector: '#products', |
||||||
|
}) |
||||||
|
}) |
||||||
|
|
||||||
|
try { |
||||||
|
uni.removeStorageSync('courses') |
||||||
|
} catch (e) {} |
||||||
|
this.calcTotal() |
||||||
|
} else { |
||||||
|
// 如果是客户订单记录页面点的新增,会有客户id,要默认选中该客户 |
||||||
|
const { customerId } = options |
||||||
|
customerId && this.customerChange({ |
||||||
|
customerId |
||||||
|
}) |
||||||
|
} |
||||||
|
// 非详情才需要查询客户 |
||||||
|
if (!this.isDetail) { |
||||||
|
this.getCustomer() |
||||||
|
} |
||||||
|
// 设置标题 |
||||||
|
uni.setNavigationBarTitle({ |
||||||
|
title: this.orderId ? |
||||||
|
(this.isDetail ? |
||||||
|
'订单详情' : |
||||||
|
'编辑订单') : |
||||||
|
'新增订单' |
||||||
|
}) |
||||||
|
}, |
||||||
|
methods: { |
||||||
|
// 获取详情 |
||||||
|
getInfo() { |
||||||
|
uni.showLoading({ |
||||||
|
title: '加载中' |
||||||
|
}) |
||||||
|
getDetail({ |
||||||
|
orderId: this.orderId |
||||||
|
}).then(({ orderDetails }) => { |
||||||
|
const order = orderDetails |
||||||
|
this.contract = order.contractInformation |
||||||
|
this.form = order.order |
||||||
|
this.courses = order.orderOther |
||||||
|
this.handleProduct(order.orderOther) |
||||||
|
this.calcTotal() |
||||||
|
uni.hideLoading() |
||||||
|
}).catch(e => { |
||||||
|
uni.hideLoading() |
||||||
|
}) |
||||||
|
}, |
||||||
|
// 转换产品列表 |
||||||
|
handleProduct(list) { |
||||||
|
const courses = { |
||||||
|
practice: { |
||||||
|
shrink: false, |
||||||
|
name: '实训课程产品', |
||||||
|
list: [] |
||||||
|
}, |
||||||
|
theory: { |
||||||
|
shrink: false, |
||||||
|
name: '理论课程产品', |
||||||
|
list: [] |
||||||
|
}, |
||||||
|
data: { |
||||||
|
shrink: false, |
||||||
|
name: '数据产品', |
||||||
|
list: [] |
||||||
|
} |
||||||
|
} |
||||||
|
// 3个分类的课程分别push到不同数组(0->理论 1-实训 2 数据产品) |
||||||
|
list.map(e => { |
||||||
|
e.serviceFee = (e.settlementPrice * 0.1).toFixed(2) |
||||||
|
const type = e.productType |
||||||
|
!type ? |
||||||
|
courses.theory.list.push(e) : |
||||||
|
type === 1 ? |
||||||
|
courses.practice.list.push(e) : |
||||||
|
courses.data.list.push(e) |
||||||
|
}) |
||||||
|
this.courseList = courses |
||||||
|
}, |
||||||
|
// 获取客户列表 |
||||||
|
getCustomer() { |
||||||
|
queryCustomer({ |
||||||
|
countries: '中国', |
||||||
|
provinceId: '', |
||||||
|
cityId: '', |
||||||
|
searchContent: this.keyword, |
||||||
|
page: 1, |
||||||
|
size: 10000 |
||||||
|
}).then(({ message }) => { |
||||||
|
this.customerListAll = message.list |
||||||
|
this.customerList = message.list |
||||||
|
}).catch(res => {}) |
||||||
|
}, |
||||||
|
// 客户模糊匹配 |
||||||
|
filterCustomer() { |
||||||
|
const { keyword } = this |
||||||
|
this.customerList = keyword ? |
||||||
|
this.customerListAll.filter(e => e.customerName.includes(keyword)) : |
||||||
|
this.customerListAll |
||||||
|
}, |
||||||
|
// 关闭客户弹框 |
||||||
|
closeCustomer() { |
||||||
|
this.customerVisible = false |
||||||
|
this.keyword = '' |
||||||
|
}, |
||||||
|
// 客户名称选择回调 |
||||||
|
customerChange(item) { |
||||||
|
const { form } = this |
||||||
|
// 获取客户详情 |
||||||
|
queryCustomerDetails({ |
||||||
|
customerId: item.customerId |
||||||
|
}).then(({ result }) => { |
||||||
|
this.handleErr('customerName') |
||||||
|
const e = result.customer |
||||||
|
form.customerId = e.customerId |
||||||
|
form.customerName = e.customerName |
||||||
|
form.provinceId = e.provinceId |
||||||
|
form.cityId = e.cityId |
||||||
|
form.provinceName = e.provinceName |
||||||
|
form.cityName = e.cityName |
||||||
|
form.phone = e.phone |
||||||
|
form.email = e.email |
||||||
|
form.orderContact = e.name |
||||||
|
}).catch(e => {}) |
||||||
|
this.closeCustomer() |
||||||
|
}, |
||||||
|
// 跳转 |
||||||
|
toAdd() { |
||||||
|
uni.setStorageSync('courses', this.courses) |
||||||
|
const { customerId, orderType } = this.form |
||||||
|
customerId ? |
||||||
|
this.$util.to(`../addCourse/addCourse?orderType=${orderType}&customerId=${customerId}`) : |
||||||
|
this.$util.errMsg('请先选择客户!') |
||||||
|
}, |
||||||
|
// 编辑课程 |
||||||
|
editCourse(c, i) { |
||||||
|
if (this.isDetail) return false |
||||||
|
uni.setStorageSync('courses', this.courses) |
||||||
|
const { customerId, orderType } = this.form |
||||||
|
this.$util.to(`../editCourse/editCourse?orderType=${orderType}&customerId=${customerId}`) |
||||||
|
}, |
||||||
|
// 删除课程 |
||||||
|
delCourse(c, i) { |
||||||
|
const that = this |
||||||
|
uni.showModal({ |
||||||
|
title: '提示', |
||||||
|
content: '确定要删除吗?', |
||||||
|
success(res) { |
||||||
|
if (res.confirm) { |
||||||
|
c.list.splice(i, 1) |
||||||
|
const courses = [] |
||||||
|
const list = that.courseList |
||||||
|
for (const j in list) { |
||||||
|
list[j].list.map(n => { |
||||||
|
courses.push(n) |
||||||
|
}) |
||||||
|
} |
||||||
|
that.courses = courses |
||||||
|
that.calcTotal() |
||||||
|
} |
||||||
|
} |
||||||
|
}) |
||||||
|
}, |
||||||
|
// 收缩产品 |
||||||
|
toggle(c) { |
||||||
|
c.shrink = !c.shrink |
||||||
|
}, |
||||||
|
// 计算订单总额 |
||||||
|
calcTotal(out) { |
||||||
|
this.handleErr('orderType') |
||||||
|
const { form } = this |
||||||
|
const isTrial = form.orderType === 2 // 是否试用 |
||||||
|
let total = 0 |
||||||
|
const list = this.courses |
||||||
|
let purchase = 0 // 总采购成本 |
||||||
|
let profit = 0 // 总利润 |
||||||
|
/** |
||||||
|
* 1)总采购成本+总产品利润=总成交价格 |
||||||
|
|
||||||
|
(2)单个产品采购成本 =结算价+平台服务费 |
||||||
|
|
||||||
|
(3)平台服务费=结算价*10% |
||||||
|
|
||||||
|
(4)单个产品的利润=成交价-采购成本 |
||||||
|
|
||||||
|
总成本和总利润为单个产品的采购成本价和利润的和 |
||||||
|
*/ |
||||||
|
list.map(e => { |
||||||
|
// out=1 && 试用,则把结算价等重置为0 |
||||||
|
if (out && isTrial) { |
||||||
|
e.settlementPrice = 0 |
||||||
|
e.serviceFee = 0 |
||||||
|
e.finalPrice = 0 |
||||||
|
e.finalValue = 0 |
||||||
|
e.discountRate = '0%' |
||||||
|
} else { |
||||||
|
const curPurchase = +e.settlementPrice + +e.serviceFee |
||||||
|
purchase += curPurchase |
||||||
|
profit += +e.finalPrice - curPurchase |
||||||
|
} |
||||||
|
}) |
||||||
|
form.purchaseCost = Math.round(purchase) |
||||||
|
form.profit = Math.round(profit) |
||||||
|
form.orderAmount = +form.purchaseCost + +form.profit |
||||||
|
}, |
||||||
|
// 处理错误提示 |
||||||
|
handleErr(val) { |
||||||
|
if (val === this.err) this.err = '' |
||||||
|
}, |
||||||
|
// 提交 |
||||||
|
submit() { |
||||||
|
const { form, courses } = this |
||||||
|
if (!form.customerId) { |
||||||
|
this.err = 'customerName' |
||||||
|
return this.$util.errMsg('请选择客户!') |
||||||
|
} |
||||||
|
if (!form.orderType) { |
||||||
|
this.err = 'orderType' |
||||||
|
return this.$util.errMsg('请选择订单类型!') |
||||||
|
} |
||||||
|
if (!courses.length) return this.$util.errMsg('请选择课程权限或数据权限后再确认订单!') |
||||||
|
courses.map(e => { |
||||||
|
e.startTime = this.$util.formatDate(new Date(e.startTime), 'yyyy-MM-dd') |
||||||
|
}) |
||||||
|
uni.showLoading({ |
||||||
|
title: '提交中' |
||||||
|
}) |
||||||
|
const data = { |
||||||
|
contractInformation: this.contract, // 合同信息 |
||||||
|
order: form, // 订单基本数据 |
||||||
|
orderOther: courses // 产品列表 |
||||||
|
} |
||||||
|
if (this.orderId) { |
||||||
|
update(data).then(res => { |
||||||
|
uni.hideLoading() |
||||||
|
this.$util.sucMsg('编辑成功') |
||||||
|
setTimeout(() => { |
||||||
|
uni.navigateBack() |
||||||
|
}, 1500) |
||||||
|
}).catch(res => { |
||||||
|
uni.hideLoading() |
||||||
|
}) |
||||||
|
} else { |
||||||
|
add(data).then(res => { |
||||||
|
uni.hideLoading() |
||||||
|
this.$util.sucMsg('添加成功') |
||||||
|
setTimeout(() => { |
||||||
|
uni.navigateBack() |
||||||
|
}, 1500) |
||||||
|
}).catch(res => { |
||||||
|
uni.hideLoading() |
||||||
|
}) |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
</script> |
||||||
|
|
||||||
|
<style scoped lang="scss"> |
||||||
|
.page { |
||||||
|
padding-bottom: 420rpx; |
||||||
|
} |
||||||
|
.show { |
||||||
|
padding-bottom: 280rpx; |
||||||
|
} |
||||||
|
.pro-wrap { |
||||||
|
position: relative; |
||||||
|
padding: 0; |
||||||
|
.l-title { |
||||||
|
margin: 0 24rpx; |
||||||
|
} |
||||||
|
} |
||||||
|
.arrow { |
||||||
|
position: absolute; |
||||||
|
top: 20rpx; |
||||||
|
right: 30rpx; |
||||||
|
} |
||||||
|
.pro-list { |
||||||
|
.name { |
||||||
|
display: flex; |
||||||
|
justify-content: space-between; |
||||||
|
align-items: center; |
||||||
|
padding: 14rpx 24rpx; |
||||||
|
font-size: 30rpx; |
||||||
|
color: #333; |
||||||
|
background: linear-gradient(90deg, #FFF5E5 0%, #FFFFFF 100%); |
||||||
|
} |
||||||
|
.left { |
||||||
|
display: inline-flex; |
||||||
|
align-items: center; |
||||||
|
} |
||||||
|
.del { |
||||||
|
width: 40rpx; |
||||||
|
} |
||||||
|
.icon { |
||||||
|
width: 60rpx; |
||||||
|
height: 60rpx; |
||||||
|
margin-right: 12rpx; |
||||||
|
border-radius: 10rpx; |
||||||
|
} |
||||||
|
.info { |
||||||
|
padding: 12rpx 24rpx; |
||||||
|
} |
||||||
|
.line { |
||||||
|
display: flex; |
||||||
|
justify-content: space-between; |
||||||
|
padding: 12rpx 0; |
||||||
|
margin: 5px 0; |
||||||
|
font-size: 12px; |
||||||
|
} |
||||||
|
.label { |
||||||
|
font-size: 28rpx; |
||||||
|
color: #999; |
||||||
|
} |
||||||
|
.val { |
||||||
|
font-size: 28rpx; |
||||||
|
color: #333; |
||||||
|
} |
||||||
|
.done { |
||||||
|
margin-top: 12rpx; |
||||||
|
padding-top: 24rpx; |
||||||
|
font-size: 13px; |
||||||
|
color: #333; |
||||||
|
border-top: 1px solid #E6E8ED; |
||||||
|
} |
||||||
|
.price { |
||||||
|
font-size: 32rpx; |
||||||
|
color: #007EFF; |
||||||
|
} |
||||||
|
} |
||||||
|
.bottom { |
||||||
|
position: fixed; |
||||||
|
bottom: 0; |
||||||
|
padding-bottom: env(safe-area-inset-bottom); |
||||||
|
width: 100%; |
||||||
|
background-color: #fff; |
||||||
|
box-shadow: 0 -2px 2px #f5f5f5; |
||||||
|
box-sizing: border-box; |
||||||
|
} |
||||||
|
.add-wrap { |
||||||
|
padding: 16rpx 24rpx 40rpx; |
||||||
|
background-color: #f5f5f5; |
||||||
|
} |
||||||
|
/deep/.add-btn { |
||||||
|
display: flex; |
||||||
|
justify-content: center; |
||||||
|
align-items: center; |
||||||
|
font-size: 28rpx; |
||||||
|
line-height: 88rpx; |
||||||
|
color: #007EFF; |
||||||
|
background-color: #fff; |
||||||
|
border: 1px solid #007EFF; |
||||||
|
border-radius: 16rpx; |
||||||
|
.icon { |
||||||
|
margin-right: 10rpx; |
||||||
|
} |
||||||
|
.uni-icons { |
||||||
|
font-size: 38rpx !important; |
||||||
|
} |
||||||
|
} |
||||||
|
.product { |
||||||
|
display: flex; |
||||||
|
justify-content: space-between; |
||||||
|
align-items: center; |
||||||
|
padding: 24rpx; |
||||||
|
background-color: #fff; |
||||||
|
.total { |
||||||
|
white-space: nowrap; |
||||||
|
} |
||||||
|
.line { |
||||||
|
&:first-child { |
||||||
|
margin-bottom: 8px; |
||||||
|
} |
||||||
|
} |
||||||
|
&.show { |
||||||
|
padding: 24rpx 50rpx; |
||||||
|
.total { |
||||||
|
display: flex; |
||||||
|
margin-bottom: 30rpx; |
||||||
|
font-size: 30rpx; |
||||||
|
font-weight: 600; |
||||||
|
color: #333; |
||||||
|
.column { |
||||||
|
margin-left: 10rpx; |
||||||
|
} |
||||||
|
.num { |
||||||
|
margin: 0 5rpx; |
||||||
|
font-size: 34rpx; |
||||||
|
font-weight: 600; |
||||||
|
color: #007EFF; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
&.edit { |
||||||
|
.total { |
||||||
|
margin-bottom: 10rpx; |
||||||
|
text-align: right; |
||||||
|
font-size: 30rpx; |
||||||
|
color: #666; |
||||||
|
.num { |
||||||
|
font-weight: 600; |
||||||
|
font-size: 34rpx; |
||||||
|
} |
||||||
|
} |
||||||
|
.num { |
||||||
|
margin: 0 5rpx; |
||||||
|
font-size: 30rpx; |
||||||
|
color: #007EFF; |
||||||
|
} |
||||||
|
} |
||||||
|
.info { |
||||||
|
font-size: 24rpx; |
||||||
|
color: #333; |
||||||
|
white-space: nowrap; |
||||||
|
} |
||||||
|
.btn { |
||||||
|
width: 180rpx; |
||||||
|
margin-left: 30rpx; |
||||||
|
line-height: 80rpx; |
||||||
|
font-size: 32rpx; |
||||||
|
text-align: center; |
||||||
|
color: #fff; |
||||||
|
border-radius: 10rpx; |
||||||
|
background-color: #007EFF; |
||||||
|
} |
||||||
|
} |
||||||
|
</style> |
@ -0,0 +1,270 @@ |
|||||||
|
<template> |
||||||
|
<view> |
||||||
|
<view class="filter"> |
||||||
|
<uni-search-bar class="search" radius="30" placeholder="请输入产品名称" v-model="keyword" clearButton="auto" cancelButton="none" /> |
||||||
|
<uni-icons class="icon" custom-prefix="iconfont" type="icon-filter" size="22" color="#007eff" @click="popup = true"></uni-icons> |
||||||
|
</view> |
||||||
|
|
||||||
|
<ul class="tab"> |
||||||
|
<li v-for="(tab, i) in tabs" :class="{active: curTab === tab.id}" @click="tabChange(tab)">{{ tab.name }}</li> |
||||||
|
</ul> |
||||||
|
|
||||||
|
<ul v-if="list.length" class="list"> |
||||||
|
<li v-for="item in list"> |
||||||
|
<view class="pro-name"> |
||||||
|
<image class="icon" :src="item.miniProgramPictureAddress ? item.miniProgramPictureAddress : normalIcon" mode="widthFix"></image> |
||||||
|
{{ item.productName }} |
||||||
|
</view> |
||||||
|
<view class="info"> |
||||||
|
<view class="line"> |
||||||
|
<text class="name">起止日期:</text> |
||||||
|
<text class="val">{{ item.startAndEndTime }}</text> |
||||||
|
</view> |
||||||
|
<view class="line"> |
||||||
|
<text class="name">订阅状态:</text> |
||||||
|
<text class="val">{{ item.status }}</text> |
||||||
|
</view> |
||||||
|
<view class="line"> |
||||||
|
<text class="name">产品状态:</text> |
||||||
|
<text class="val">{{ item.isEnable }}</text> |
||||||
|
</view> |
||||||
|
</view> |
||||||
|
</li> |
||||||
|
</ul> |
||||||
|
<empty v-else></empty> |
||||||
|
<filter-popup :data="filterData" :form.sync="filterForm" v-model="popup" title="全部筛选" height="1104rpx" @finsh="subFinsh"></filter-popup> |
||||||
|
</view> |
||||||
|
</template> |
||||||
|
|
||||||
|
<script> |
||||||
|
import { getProductsSubscribedByCustomers } from '@/apis/modules/client.js' |
||||||
|
import product from '@/config/product.js' |
||||||
|
export default { |
||||||
|
data() { |
||||||
|
return { |
||||||
|
normalIcon: product.normalIcon, |
||||||
|
customerId: '', |
||||||
|
popup: false, |
||||||
|
//筛选表单数据 |
||||||
|
filterData: [ |
||||||
|
{ |
||||||
|
children: false,//是否有子项 |
||||||
|
title: "订阅状态", |
||||||
|
key: "orderStatus", //键名 接收对象名字 |
||||||
|
keyValue: "value", //获取的值是哪个 |
||||||
|
isRadio: true, //是否单选 否则多选 |
||||||
|
data: [ |
||||||
|
{ |
||||||
|
title: '生效', |
||||||
|
value: 1 |
||||||
|
}, |
||||||
|
{ |
||||||
|
title: '过期', |
||||||
|
value: 2 |
||||||
|
}, |
||||||
|
], |
||||||
|
}, |
||||||
|
{ |
||||||
|
children: false,//是否有子项 |
||||||
|
title: "产品状态", |
||||||
|
key: "productStatus", //键名 接收对象名字 |
||||||
|
keyValue: "value", //获取的值是哪个 |
||||||
|
isRadio: true, //是否单选 否则多选 |
||||||
|
data: [ |
||||||
|
{ |
||||||
|
title: '启用', |
||||||
|
value: 1 |
||||||
|
}, |
||||||
|
{ |
||||||
|
title: '禁用', |
||||||
|
value: 2 |
||||||
|
}, |
||||||
|
], |
||||||
|
} |
||||||
|
], |
||||||
|
filterForm: {}, |
||||||
|
curTab: '', |
||||||
|
tabs: [ |
||||||
|
{ |
||||||
|
name: '全部', |
||||||
|
id: '' |
||||||
|
}, |
||||||
|
{ |
||||||
|
name: '实训课程', |
||||||
|
id: 1 |
||||||
|
}, |
||||||
|
{ |
||||||
|
name: '理论课程', |
||||||
|
id: 0 |
||||||
|
}, |
||||||
|
{ |
||||||
|
name: '数据产品', |
||||||
|
id: 3 |
||||||
|
} |
||||||
|
], |
||||||
|
searchTimer: null, |
||||||
|
orderStatus: '', |
||||||
|
productStatus: '', |
||||||
|
keyword: '', |
||||||
|
list: [], |
||||||
|
listAll: [], |
||||||
|
page: 1, |
||||||
|
pageSize: 10 |
||||||
|
} |
||||||
|
}, |
||||||
|
watch: { |
||||||
|
keyword () { |
||||||
|
clearTimeout(this.searchTimer) |
||||||
|
this.searchTimer = setTimeout(() => { |
||||||
|
this.filter() |
||||||
|
}, 500) |
||||||
|
} |
||||||
|
}, |
||||||
|
// 下拉刷新 |
||||||
|
onPullDownRefresh() { |
||||||
|
this.getList() |
||||||
|
setTimeout(() => { |
||||||
|
uni.stopPullDownRefresh() |
||||||
|
}, 1500) |
||||||
|
}, |
||||||
|
onShow() { |
||||||
|
const pages = getCurrentPages() |
||||||
|
this.customerId = pages[pages.length - 1].options.customerId |
||||||
|
this.getList() |
||||||
|
}, |
||||||
|
methods: { |
||||||
|
getList() { |
||||||
|
uni.showLoading({ |
||||||
|
title: '加载中' |
||||||
|
}) |
||||||
|
getProductsSubscribedByCustomers({ |
||||||
|
customeId: this.customerId |
||||||
|
}).then(({ data }) => { |
||||||
|
const { tabs } = this |
||||||
|
data.map(e => { |
||||||
|
const list = e.startAndEndTimeList |
||||||
|
let connect = true // 每个订单的开始结束日期是否连续 |
||||||
|
list.map((n, i) => { |
||||||
|
// 第一个不用计算。用当前订单的开始日期跟上一个订单的结束日期做比较,只差一天,就表示是连续订单 |
||||||
|
if (i) { |
||||||
|
if (new Date(n.startTime).getTime() - 86400000 !== new Date(list[i - 1].endTime).getTime()) connect = false |
||||||
|
} |
||||||
|
}) |
||||||
|
// 如果是连续订单,则取第一个订单的开始日期和最后一个订单的结束日期 |
||||||
|
const now = Date.now() |
||||||
|
if (now < list[0].startTime) { |
||||||
|
e.startTime = list[0].startTime |
||||||
|
e.endTime = connect ? list[list.length - 1].endTime : list[0].endTime |
||||||
|
e.status = '未生效' |
||||||
|
} else if (now > list[list.length - 1].endTime) { |
||||||
|
e.status = '已过期' |
||||||
|
} else { |
||||||
|
// 连续订单 |
||||||
|
if (connect) { |
||||||
|
e.startTime = list[0].startTime |
||||||
|
e.endTime = list[list.length - 1].endTime |
||||||
|
e.status = '生效中' |
||||||
|
e.orderEnable = list[0].isEnable |
||||||
|
} else { |
||||||
|
for (const i in list) { |
||||||
|
const n = list[i] |
||||||
|
if (now >= new Date(n.startTime).getTime() && now <= new Date(n.endTime).getTime()) { |
||||||
|
// 生效中的订单,直接取该订单的开始结束日期 |
||||||
|
e.startTime = n.startTime |
||||||
|
e.endTime = n.endTime |
||||||
|
e.status = '生效中' |
||||||
|
e.orderEnable = n.isEnable |
||||||
|
break |
||||||
|
} else if (i && now > new Date(list[i - 1].endTime).getTime() && now < new Date(n.startTime).getTime()) { |
||||||
|
// 当前时间位于两个订单时间之间,则取次订单的开始结束日期,并且为未生效 |
||||||
|
e.startTime = n.startTime |
||||||
|
e.endTime = n.endTime |
||||||
|
e.status = '未生效' |
||||||
|
e.orderEnable = n.isEnable |
||||||
|
break |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
const date = new Date() |
||||||
|
date.setHours(0) |
||||||
|
date.setMinutes(0) |
||||||
|
date.setSeconds(0) |
||||||
|
e.startAndEndTime = e.startTime + ' ~ ' + e.endTime |
||||||
|
// 1开启 0禁用(已过期的订单,或者当前生效的订单为禁用,则显示为禁用,否则是启用) |
||||||
|
e.isEnable = (e.status === '已过期' || !e.orderEnable) ? '禁用' : '启用' |
||||||
|
}) |
||||||
|
this.list = data |
||||||
|
this.listAll = data |
||||||
|
uni.hideLoading() |
||||||
|
}).catch(e => { |
||||||
|
uni.hideLoading() |
||||||
|
}) |
||||||
|
}, |
||||||
|
// 筛选确定回调 |
||||||
|
subFinsh(val) { |
||||||
|
const { orderStatus, productStatus } = val |
||||||
|
this.orderStatus = orderStatus.length ? orderStatus[0] : '' |
||||||
|
this.productStatus = productStatus.length ? productStatus[0] : '' |
||||||
|
this.filter() |
||||||
|
}, |
||||||
|
// 筛选 |
||||||
|
filter() { |
||||||
|
const list = this.listAll |
||||||
|
const { orderStatus, productStatus, keyword, curTab } = this |
||||||
|
this.list = list.filter(e => (orderStatus === '' || ((orderStatus === 2 && e.status === '已过期') || (orderStatus === 1 && e.status === '生效中'))) && (productStatus === '' || ((productStatus === 2 && e.isEnable === '禁用') || (productStatus === 1 && e.isEnable === '启用'))) && e.productName.includes(keyword) && (curTab === '' || (curTab === e.productType))) |
||||||
|
}, |
||||||
|
// tab切换 |
||||||
|
tabChange(tab) { |
||||||
|
this.curTab = tab.id |
||||||
|
this.filter() |
||||||
|
}, |
||||||
|
// 跳转详情 |
||||||
|
toDetail(item) { |
||||||
|
this.$util.to(`../clientDetail/clientDetail?customerId=${item.customerId}&show=1`) |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
</script> |
||||||
|
|
||||||
|
<style scoped lang="scss"> |
||||||
|
.filter { |
||||||
|
margin-bottom: 10px; |
||||||
|
} |
||||||
|
.list { |
||||||
|
li { |
||||||
|
padding: 0 24rpx; |
||||||
|
margin: 16rpx 24rpx; |
||||||
|
background-color: #fff; |
||||||
|
border-radius: 16rpx; |
||||||
|
} |
||||||
|
.pro-name { |
||||||
|
display: flex; |
||||||
|
align-items: center; |
||||||
|
padding: 18rpx 0; |
||||||
|
font-size: 30rpx; |
||||||
|
color: #333; |
||||||
|
border-bottom: 1px solid #E6E8ED; |
||||||
|
.icon { |
||||||
|
width: 52rpx; |
||||||
|
margin-right: 20rpx; |
||||||
|
} |
||||||
|
} |
||||||
|
.info { |
||||||
|
padding: 12rpx 0; |
||||||
|
} |
||||||
|
.line { |
||||||
|
display: flex; |
||||||
|
padding: 12rpx 0; |
||||||
|
} |
||||||
|
.name { |
||||||
|
margin-right: 10rpx; |
||||||
|
font-size: 28rpx; |
||||||
|
color: #999; |
||||||
|
} |
||||||
|
.val { |
||||||
|
font-size: 28rpx; |
||||||
|
color: #333; |
||||||
|
} |
||||||
|
} |
||||||
|
</style> |
@ -0,0 +1,311 @@ |
|||||||
|
<template> |
||||||
|
<view> |
||||||
|
<view class="filter"> |
||||||
|
<uni-search-bar class="search" radius="30" placeholder="请输入学校名称,商务经理,订单号" v-model="keyword" clearButton="auto" cancelButton="none" /> |
||||||
|
<view :class="['sort', sort]" @click="switchSort"></view> |
||||||
|
<uni-icons class="icon" custom-prefix="iconfont" type="icon-filter" size="22" color="#007eff" @click="popup = true"></uni-icons> |
||||||
|
</view> |
||||||
|
<ul class="tab"> |
||||||
|
<li v-for="(tab, i) in tabs" :class="{active: curTab === tab.id}" @click="tabChange(tab)">{{ tab.name }}</li> |
||||||
|
</ul> |
||||||
|
|
||||||
|
<template v-if="list.length"> |
||||||
|
<view class="list"> |
||||||
|
<uni-swipe-action> |
||||||
|
<uni-swipe-action-item |
||||||
|
v-for="item in list" |
||||||
|
:threshold="0" |
||||||
|
:right-options="delOption" |
||||||
|
@click="del(item)" |
||||||
|
> |
||||||
|
<view class="item" @click="toDetail(item)"> |
||||||
|
<view class="c-name">{{ item.orderNumber }}</view> |
||||||
|
<view class="info"> |
||||||
|
<view class="left"> |
||||||
|
<view v-if="curTab" class="line"> |
||||||
|
<text class="name">商务经理:</text> |
||||||
|
<text class="val">{{ item.businessManagerName }}</text> |
||||||
|
</view> |
||||||
|
<view class="line"> |
||||||
|
<text class="name">客户名称:</text> |
||||||
|
<text class="val">{{ item.customerName }}</text> |
||||||
|
</view> |
||||||
|
<view class="line"> |
||||||
|
<text class="name">订单金额:</text> |
||||||
|
<text class="val">{{ item.orderAmount }}元</text> |
||||||
|
</view> |
||||||
|
<view class="line"> |
||||||
|
<text class="name">订单内容:</text> |
||||||
|
<view class="val ell-wrap"> |
||||||
|
<view :class="{ell: !item.toggle}">{{ item.orderContent }}</view> |
||||||
|
<view v-if="item.orderContent.length > 14" class="toggle" @click.stop="toggle(item)">{{ item.toggle ? '收起' : '展开' }}</view> |
||||||
|
</view> |
||||||
|
</view> |
||||||
|
<view class="line"> |
||||||
|
<text class="name">下单日期:</text> |
||||||
|
<text class="val">{{ item.createTime }}</text> |
||||||
|
</view> |
||||||
|
</view> |
||||||
|
<view :class="['type', 'type' + item.orderStatus]"> |
||||||
|
{{ filterData[0].data.find(e => e.value === item.orderStatus).title }} |
||||||
|
</view> |
||||||
|
</view> |
||||||
|
</view> |
||||||
|
</uni-swipe-action-item> |
||||||
|
</uni-swipe-action> |
||||||
|
</view> |
||||||
|
<uni-load-more :status="status" /> |
||||||
|
</template> |
||||||
|
<empty v-else></empty> |
||||||
|
|
||||||
|
<uni-icons class="plus" type="plus-filled" size="60" color="#007eff" @click="$util.to('../orderDetail/orderDetail')"></uni-icons> |
||||||
|
<filter-popup :data="filterData" :form.sync="filterForm" v-model="popup" title="全部筛选" height="1104rpx" @finsh="subFinsh"></filter-popup> |
||||||
|
</view> |
||||||
|
</template> |
||||||
|
|
||||||
|
<script> |
||||||
|
import { queryCustomer } from '@/apis/modules/client.js' |
||||||
|
import { list, del } from '@/apis/modules/order.js' |
||||||
|
export default { |
||||||
|
data() { |
||||||
|
return { |
||||||
|
popup: false, |
||||||
|
//筛选表单数据 |
||||||
|
filterData: [ |
||||||
|
{ |
||||||
|
children: false,//是否有子项 |
||||||
|
title: "订单状态", |
||||||
|
key: "orderStatus", //键名 接收对象名字 |
||||||
|
keyValue: "value", //获取的值是哪个 |
||||||
|
isRadio: true, //是否单选 否则多选 |
||||||
|
data: [ |
||||||
|
{ |
||||||
|
title: "待发货", |
||||||
|
value: 0 |
||||||
|
}, |
||||||
|
{ |
||||||
|
title: "已完成", |
||||||
|
value: 1 |
||||||
|
}, |
||||||
|
], |
||||||
|
} |
||||||
|
], |
||||||
|
filterForm: {}, |
||||||
|
curTab: 0, |
||||||
|
tabs: [ |
||||||
|
{ |
||||||
|
name: '我的订单', |
||||||
|
id: 0 |
||||||
|
}, |
||||||
|
{ |
||||||
|
name: '团队全部订单', |
||||||
|
id: 1 |
||||||
|
} |
||||||
|
], |
||||||
|
reachBottom: 0, // 是否是上拉加载。0->否,1->是,-1->加载完所有数据 |
||||||
|
status: 'more', // 上拉加载状态 more|loading|noMore |
||||||
|
searchTimer: null, |
||||||
|
orderStatus: '', |
||||||
|
sort: 'desc', |
||||||
|
keyword: '', |
||||||
|
list: [], |
||||||
|
page: 1, |
||||||
|
pageSize: 10, |
||||||
|
delOption: [{ |
||||||
|
text: '删除', |
||||||
|
style: { |
||||||
|
backgroundColor: '#F56C6C' |
||||||
|
} |
||||||
|
}], |
||||||
|
} |
||||||
|
}, |
||||||
|
watch: { |
||||||
|
keyword () { |
||||||
|
clearTimeout(this.searchTimer) |
||||||
|
this.searchTimer = setTimeout(() => { |
||||||
|
this.initList() |
||||||
|
}, 500) |
||||||
|
} |
||||||
|
}, |
||||||
|
// 下拉刷新 |
||||||
|
onPullDownRefresh() { |
||||||
|
this.initList() |
||||||
|
setTimeout(() => { |
||||||
|
uni.stopPullDownRefresh() |
||||||
|
}, 1500) |
||||||
|
}, |
||||||
|
// 上拉加载 |
||||||
|
onReachBottom() { |
||||||
|
if (this.reachBottom >= 0) { |
||||||
|
this.reachBottom = 1 |
||||||
|
this.status = 'loading' |
||||||
|
this.getList() |
||||||
|
} |
||||||
|
}, |
||||||
|
onShow() { |
||||||
|
// 清除产品缓存 |
||||||
|
try { |
||||||
|
uni.removeStorageSync('courses') |
||||||
|
} catch (e) {} |
||||||
|
this.initRole() |
||||||
|
}, |
||||||
|
methods: { |
||||||
|
// 初始化权限 |
||||||
|
initRole() { |
||||||
|
this.tabs = [] |
||||||
|
const auth = uni.getStorageSync('auth') |
||||||
|
auth.includes('首页:订单:我的订单') && this.tabs.push({ |
||||||
|
name: '我的订单', |
||||||
|
id: 0 |
||||||
|
}) |
||||||
|
auth.includes('首页:订单:团队全部订单') && this.tabs.push({ |
||||||
|
name: '团队全部订单', |
||||||
|
id: 1 |
||||||
|
}) |
||||||
|
const len = this.tabs.length |
||||||
|
// 只有一个的话,取第一个,而且不用显示tab |
||||||
|
if (len === 1) { |
||||||
|
this.curTab = this.tabs[0].id |
||||||
|
this.tabs = [] |
||||||
|
} |
||||||
|
this.initList() |
||||||
|
}, |
||||||
|
getList() { |
||||||
|
const data = { |
||||||
|
businessManagerId: this.$util.getBmId(), |
||||||
|
teamId: uni.getStorageSync('team').id, |
||||||
|
keywords: this.keyword, |
||||||
|
pageNum: this.page, |
||||||
|
pageSize: this.pageSize, |
||||||
|
sort: this.sort, |
||||||
|
orderStatus: this.orderStatus, |
||||||
|
type: this.curTab |
||||||
|
} |
||||||
|
uni.showLoading({ |
||||||
|
title: '加载中' |
||||||
|
}) |
||||||
|
list(data).then(({ data }) => { |
||||||
|
uni.hideLoading() |
||||||
|
// 未加载完所有数据,并且不是筛选,则拼接list,否则直接赋值 |
||||||
|
const list = data.records |
||||||
|
list.map(e => { |
||||||
|
e.toggle = e.orderContent.length < 14 // 超过了14个字才需要显示展开按钮 |
||||||
|
}) |
||||||
|
this.list = this.reachBottom > 0 ? [...this.list, ...list] : list |
||||||
|
this.page++ // 每次获取了数据后page+1 |
||||||
|
const noMore = this.list.length === data.total // 是否加载完所有数据 |
||||||
|
this.status = noMore ? 'noMore' : 'more' // 加载完了则设置为noMore |
||||||
|
this.reachBottom = noMore ? -1 : 0 // 加载完了则设置为-1 |
||||||
|
}).catch(e => { |
||||||
|
uni.hideLoading() |
||||||
|
}) |
||||||
|
}, |
||||||
|
initList() { |
||||||
|
this.page = 1 |
||||||
|
this.reachBottom = 0 |
||||||
|
this.getList() |
||||||
|
}, |
||||||
|
// 展开 |
||||||
|
toggle(item) { |
||||||
|
item.toggle = !item.toggle |
||||||
|
}, |
||||||
|
// 筛选确定回调 |
||||||
|
subFinsh(val) { |
||||||
|
const { orderStatus } = val |
||||||
|
this.orderStatus = orderStatus.length ? orderStatus[0] : '' |
||||||
|
this.initList() |
||||||
|
}, |
||||||
|
// 排序 |
||||||
|
switchSort() { |
||||||
|
this.sort = this.sort === 'desc' ? 'asc' : 'desc' |
||||||
|
this.initList() |
||||||
|
}, |
||||||
|
// tab切换 |
||||||
|
tabChange(tab) { |
||||||
|
this.curTab = tab.id |
||||||
|
this.initList() |
||||||
|
}, |
||||||
|
// 跳转详情 |
||||||
|
toDetail(item) { |
||||||
|
this.$util.to(`../orderDetail/orderDetail?orderId=${item.orderId}&show=1`) |
||||||
|
}, |
||||||
|
// 删除 |
||||||
|
del(e) { |
||||||
|
const that = this |
||||||
|
uni.showModal({ |
||||||
|
title: '提示', |
||||||
|
content: '确定要删除吗?', |
||||||
|
success(res) { |
||||||
|
if (res.confirm) { |
||||||
|
del({ |
||||||
|
ids: [e.orderId] |
||||||
|
}).then(res => { |
||||||
|
that.$util.sucMsg('删除成功') |
||||||
|
that.initList() |
||||||
|
}).catch(res => {}) |
||||||
|
} |
||||||
|
} |
||||||
|
}) |
||||||
|
}, |
||||||
|
} |
||||||
|
} |
||||||
|
</script> |
||||||
|
|
||||||
|
<style scoped lang="scss"> |
||||||
|
.list { |
||||||
|
margin-top: 20rpx; |
||||||
|
background-color: #fff; |
||||||
|
.item { |
||||||
|
padding: 20rpx 40rpx; |
||||||
|
border-bottom: 1px solid #f1f1f1; |
||||||
|
} |
||||||
|
.c-name { |
||||||
|
font-size: 30rpx; |
||||||
|
color: #333; |
||||||
|
} |
||||||
|
.info { |
||||||
|
display: flex; |
||||||
|
justify-content: space-between; |
||||||
|
align-items: center; |
||||||
|
margin-top: 10rpx; |
||||||
|
} |
||||||
|
.left { |
||||||
|
max-width: 70%; |
||||||
|
} |
||||||
|
.line { |
||||||
|
display: flex; |
||||||
|
padding: 10rpx 0; |
||||||
|
} |
||||||
|
.name { |
||||||
|
margin-right: 10rpx; |
||||||
|
white-space: nowrap; |
||||||
|
font-size: 28rpx; |
||||||
|
color: #999; |
||||||
|
} |
||||||
|
.val { |
||||||
|
max-width: 88%; |
||||||
|
font-size: 28rpx; |
||||||
|
color: #333; |
||||||
|
} |
||||||
|
.ell { |
||||||
|
white-space: nowrap; |
||||||
|
text-overflow: ellipsis; |
||||||
|
overflow: hidden; |
||||||
|
} |
||||||
|
.toggle { |
||||||
|
margin-top: 10rpx; |
||||||
|
white-space: nowrap; |
||||||
|
font-size: 24rpx; |
||||||
|
color: #0e92ef; |
||||||
|
} |
||||||
|
.type { |
||||||
|
margin-left: 20rpx; |
||||||
|
font-size: 28rpx; |
||||||
|
color: #ff7b2d; |
||||||
|
white-space: nowrap; |
||||||
|
} |
||||||
|
.type1 { |
||||||
|
color: #bdbdbd; |
||||||
|
} |
||||||
|
} |
||||||
|
</style> |
@ -0,0 +1,12 @@ |
|||||||
|
{ |
||||||
|
"id": "filter-popup", |
||||||
|
"name": "筛选 菜单 筛选菜单 上拉筛选 ", |
||||||
|
"version": "1.0.4", |
||||||
|
"description": "筛选菜单,支持单选和多选 , 选择后的数据通过.sync双向绑定,全端支持 导入即用", |
||||||
|
"keywords": [ |
||||||
|
"筛选", |
||||||
|
"菜单", |
||||||
|
"筛选菜单", |
||||||
|
"上拉筛选" |
||||||
|
] |
||||||
|
} |
@ -0,0 +1,231 @@ |
|||||||
|
{ |
||||||
|
"pages": [ |
||||||
|
{ |
||||||
|
"path" : "pages/login/login", |
||||||
|
"style" : |
||||||
|
{ |
||||||
|
"navigationBarTitleText": "登录", |
||||||
|
"enablePullDownRefresh": false |
||||||
|
} |
||||||
|
}, |
||||||
|
{ |
||||||
|
"path" : "pages/index/index", |
||||||
|
"style" : |
||||||
|
{ |
||||||
|
"navigationBarTitleText": "", |
||||||
|
"enablePullDownRefresh": false |
||||||
|
} |
||||||
|
}, |
||||||
|
{ |
||||||
|
"path" : "pages/qrcode/qrcode", |
||||||
|
"style" : |
||||||
|
{ |
||||||
|
"navigationBarTitleText": "邀请加入", |
||||||
|
"enablePullDownRefresh": false |
||||||
|
} |
||||||
|
}, |
||||||
|
{ |
||||||
|
"path" : "pages/clients/clients", |
||||||
|
"style" : |
||||||
|
{ |
||||||
|
"navigationBarTitleText": "客户列表", |
||||||
|
"enablePullDownRefresh": true |
||||||
|
} |
||||||
|
}, |
||||||
|
{ |
||||||
|
"path" : "pages/products/products", |
||||||
|
"style" : |
||||||
|
{ |
||||||
|
"navigationBarTitleText": "产品", |
||||||
|
"enablePullDownRefresh": true |
||||||
|
} |
||||||
|
}, |
||||||
|
{ |
||||||
|
"path" : "pages/clientDetail/clientDetail", |
||||||
|
"style" : |
||||||
|
{ |
||||||
|
"navigationBarTitleText": "客户详情", |
||||||
|
"enablePullDownRefresh": false |
||||||
|
} |
||||||
|
}, |
||||||
|
{ |
||||||
|
"path" : "pages/addStaff/addStaff", |
||||||
|
"style" : |
||||||
|
{ |
||||||
|
"navigationBarTitleText": "邀请成员", |
||||||
|
"enablePullDownRefresh": false |
||||||
|
} |
||||||
|
}, |
||||||
|
{ |
||||||
|
"path" : "pages/plans/plans", |
||||||
|
"style" : |
||||||
|
{ |
||||||
|
"navigationBarTitleText": "产品方案", |
||||||
|
"enablePullDownRefresh": false |
||||||
|
} |
||||||
|
}, |
||||||
|
{ |
||||||
|
"path" : "pages/person/person", |
||||||
|
"style" : |
||||||
|
{ |
||||||
|
"navigationBarTitleText": "我的", |
||||||
|
"enablePullDownRefresh": false |
||||||
|
} |
||||||
|
}, |
||||||
|
{ |
||||||
|
"path" : "pages/send/send", |
||||||
|
"style" : |
||||||
|
{ |
||||||
|
"navigationBarTitleText": "下载发送", |
||||||
|
"enablePullDownRefresh": false |
||||||
|
} |
||||||
|
}, |
||||||
|
{ |
||||||
|
"path" : "pages/password/password", |
||||||
|
"style" : |
||||||
|
{ |
||||||
|
"navigationBarTitleText": "修改密码", |
||||||
|
"enablePullDownRefresh": false |
||||||
|
} |
||||||
|
}, |
||||||
|
{ |
||||||
|
"path" : "pages/setting/setting", |
||||||
|
"style" : |
||||||
|
{ |
||||||
|
"navigationBarTitleText": "设置", |
||||||
|
"enablePullDownRefresh": false |
||||||
|
} |
||||||
|
}, |
||||||
|
{ |
||||||
|
"path" : "pages/teams/teams", |
||||||
|
"style" : |
||||||
|
{ |
||||||
|
"navigationBarTitleText": "团队", |
||||||
|
"enablePullDownRefresh": true |
||||||
|
} |
||||||
|
}, |
||||||
|
{ |
||||||
|
"path" : "pages/account/account", |
||||||
|
"style" : |
||||||
|
{ |
||||||
|
"navigationBarTitleText": "修改账号", |
||||||
|
"enablePullDownRefresh": false |
||||||
|
} |
||||||
|
} |
||||||
|
,{ |
||||||
|
"path" : "pages/phone/phone", |
||||||
|
"style" : |
||||||
|
{ |
||||||
|
"navigationBarTitleText": "修改手机号", |
||||||
|
"enablePullDownRefresh": false |
||||||
|
} |
||||||
|
} |
||||||
|
,{ |
||||||
|
"path" : "pages/email/email", |
||||||
|
"style" : |
||||||
|
{ |
||||||
|
"navigationBarTitleText": "修改邮箱", |
||||||
|
"enablePullDownRefresh": false |
||||||
|
} |
||||||
|
} |
||||||
|
], |
||||||
|
"subPackages": [{ |
||||||
|
"root": "order", |
||||||
|
"pages": [ |
||||||
|
{ |
||||||
|
"path": "orders/orders", |
||||||
|
"style" : |
||||||
|
{ |
||||||
|
"navigationBarTitleText": "订单列表", |
||||||
|
"enablePullDownRefresh": true |
||||||
|
} |
||||||
|
}, |
||||||
|
{ |
||||||
|
"path" : "addCourse/addCourse", |
||||||
|
"style" : |
||||||
|
{ |
||||||
|
"navigationBarTitleText": "选择产品", |
||||||
|
"enablePullDownRefresh": true |
||||||
|
} |
||||||
|
}, |
||||||
|
{ |
||||||
|
"path" : "orderDetail/orderDetail", |
||||||
|
"style" : |
||||||
|
{ |
||||||
|
"navigationBarTitleText": "订单详情", |
||||||
|
"enablePullDownRefresh": false |
||||||
|
} |
||||||
|
}, |
||||||
|
{ |
||||||
|
"path" : "ordered/ordered", |
||||||
|
"style" : |
||||||
|
{ |
||||||
|
"navigationBarTitleText": "已订阅产品", |
||||||
|
"enablePullDownRefresh": false |
||||||
|
} |
||||||
|
}, |
||||||
|
{ |
||||||
|
"path" : "editCourse/editCourse", |
||||||
|
"style" : |
||||||
|
{ |
||||||
|
"navigationBarTitleText": "编辑产品", |
||||||
|
"enablePullDownRefresh": false |
||||||
|
} |
||||||
|
}, |
||||||
|
{ |
||||||
|
"path" : "curClient/curClient", |
||||||
|
"style" : |
||||||
|
{ |
||||||
|
"navigationBarTitleText": "订单记录", |
||||||
|
"enablePullDownRefresh": false |
||||||
|
} |
||||||
|
} |
||||||
|
] |
||||||
|
}], |
||||||
|
"preloadRule": { |
||||||
|
"order/orders/orders": { |
||||||
|
"network": "all", |
||||||
|
"packages": ["__APP__"] |
||||||
|
} |
||||||
|
}, |
||||||
|
"condition": { //模式配置,仅开发期间生效 |
||||||
|
"current": 0, //当前激活的模式(list 的索引项) |
||||||
|
"list": [{ |
||||||
|
"name": "test", //模式名称 |
||||||
|
"path": "pages/login/login" //启动页面,必选 |
||||||
|
}] |
||||||
|
}, |
||||||
|
"globalStyle": { |
||||||
|
"navigationBarTextStyle": "white", |
||||||
|
"navigationBarTitleText": "或然中台", |
||||||
|
"navigationBarBackgroundColor": "#007EFF", |
||||||
|
"backgroundColor": "#f5f5f5", |
||||||
|
"app-plus": { |
||||||
|
"background": "#efeff4" |
||||||
|
} |
||||||
|
}, |
||||||
|
"tabBar": { |
||||||
|
"color": "#B8B9B8", |
||||||
|
"selectedColor": "#007FFF", |
||||||
|
"borderStyle": "white", |
||||||
|
"backgroundColor": "#ffffff", |
||||||
|
"fontSize": "16px", |
||||||
|
"iconWidth": "30px", |
||||||
|
"list": [{ |
||||||
|
"pagePath": "pages/index/index", |
||||||
|
"iconPath": "static/image/tab1.png", |
||||||
|
"selectedIconPath": "static/image/tab1-1.png", |
||||||
|
"text": "首页" |
||||||
|
}, { |
||||||
|
"pagePath": "pages/teams/teams", |
||||||
|
"iconPath": "static/image/tab2.png", |
||||||
|
"selectedIconPath": "static/image/tab2-1.png", |
||||||
|
"text": "团队" |
||||||
|
}, { |
||||||
|
"pagePath": "pages/person/person", |
||||||
|
"iconPath": "static/image/tab3.png", |
||||||
|
"selectedIconPath": "static/image/tab3-1.png", |
||||||
|
"text": "我的" |
||||||
|
}] |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,61 @@ |
|||||||
|
<template> |
||||||
|
<view class="page"> |
||||||
|
<view class="input"> |
||||||
|
<uni-easyinput v-model.trim="account" placeholder="请输入账号" @input="accountChange"></uni-easyinput> |
||||||
|
</view> |
||||||
|
<button type="primary" @click="submit">确认</button> |
||||||
|
</view> |
||||||
|
</template> |
||||||
|
|
||||||
|
<script> |
||||||
|
import { checkIfAnAccountExists, changeAccount } from '@/apis/modules/user.js' |
||||||
|
export default { |
||||||
|
data() { |
||||||
|
return { |
||||||
|
timer: null, |
||||||
|
account: '', |
||||||
|
repeat: false |
||||||
|
} |
||||||
|
}, |
||||||
|
onShow() { |
||||||
|
|
||||||
|
}, |
||||||
|
methods: { |
||||||
|
// 账号判重 |
||||||
|
accountChange() { |
||||||
|
clearTimeout(this.timer) |
||||||
|
this.timer = setTimeout(() => { |
||||||
|
checkIfAnAccountExists(this.account).then(() => { |
||||||
|
this.repeat = false |
||||||
|
}).catch(e => { |
||||||
|
this.repeat = true |
||||||
|
}) |
||||||
|
}, 500) |
||||||
|
}, |
||||||
|
submit() { |
||||||
|
const { account } = this |
||||||
|
if(!account) return this.$util.errMsg('请输入账号') |
||||||
|
if (this.repeat) return this.$util.errMsg('账号已存在!') |
||||||
|
changeAccount(account).then(res => { |
||||||
|
this.$util.sucMsg('修改成功!') |
||||||
|
setTimeout(() => { |
||||||
|
uni.navigateBack() |
||||||
|
}, 1000) |
||||||
|
}).catch(e => {}) |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
</script> |
||||||
|
|
||||||
|
<style scoped lang="scss"> |
||||||
|
.page { |
||||||
|
padding: 20px; |
||||||
|
background-color: #fff; |
||||||
|
} |
||||||
|
/deep/.input { |
||||||
|
margin-bottom: 15px; |
||||||
|
.is-input-border { |
||||||
|
border-color: #dedede !important; |
||||||
|
} |
||||||
|
} |
||||||
|
</style> |
@ -0,0 +1,51 @@ |
|||||||
|
<template> |
||||||
|
<view> |
||||||
|
<uni-section title="邀请成员" type="line"> |
||||||
|
<uni-list> |
||||||
|
<uni-list-item thumb-size="sm" showArrow title="二维码邀请" clickable :to="`../qrcode/qrcode`"> |
||||||
|
<template v-slot:header> |
||||||
|
<view class="slot-box"> |
||||||
|
<image class="icon" src="@/static/image/qrcode.png" mode="widthFix"></image> |
||||||
|
</view> |
||||||
|
</template> |
||||||
|
<template v-slot:body> |
||||||
|
<text class="slot-box text">二维码邀请</text> |
||||||
|
</template> |
||||||
|
</uni-list-item> |
||||||
|
</uni-list> |
||||||
|
</uni-section> |
||||||
|
</view> |
||||||
|
</template> |
||||||
|
|
||||||
|
<script> |
||||||
|
export default { |
||||||
|
data() { |
||||||
|
return { |
||||||
|
extraIcon: { |
||||||
|
color: '#007eff', |
||||||
|
size: '22', |
||||||
|
type: 'icon-qrcode' |
||||||
|
} |
||||||
|
} |
||||||
|
}, |
||||||
|
methods: { |
||||||
|
|
||||||
|
} |
||||||
|
} |
||||||
|
</script> |
||||||
|
|
||||||
|
<style scoped lang="scss"> |
||||||
|
.slot-box { |
||||||
|
display: flex; |
||||||
|
flex-direction: row; |
||||||
|
align-items: center; |
||||||
|
} |
||||||
|
.icon { |
||||||
|
width: 25px; |
||||||
|
height: 25px; |
||||||
|
margin-right: 10px; |
||||||
|
} |
||||||
|
.text { |
||||||
|
font-size: 14px; |
||||||
|
} |
||||||
|
</style> |
@ -0,0 +1,372 @@ |
|||||||
|
<template> |
||||||
|
<view class="page"> |
||||||
|
<uni-card v-if="customerId" :is-shadow="false" :border="false" is-full> |
||||||
|
<view class="info"> |
||||||
|
<view class="name"><image class="school" src="@/static/image/school.png" mode="widthFix"></image>{{ form.customerName }}</view> |
||||||
|
<view class="text">客户类型:{{ customerType }}</view> |
||||||
|
<view class="text">产品到期时间:{{ form.expireDate || '' }}</view> |
||||||
|
</view> |
||||||
|
</uni-card> |
||||||
|
|
||||||
|
<view class="block"> |
||||||
|
<view class="l-title">基本信息</view> |
||||||
|
<view class="form-list"> |
||||||
|
<view :class="['line req', {err: err === 'customerName'}]"> |
||||||
|
<view class="name">客户名称</view> |
||||||
|
<view v-if="isDetail" class="val">{{ form.customerName }}</view> |
||||||
|
<view v-else :class="['ph', {val: form.customerName}]" @click="schoolVisible = true">{{ form.customerName || '请选择学校' }}</view> |
||||||
|
</view> |
||||||
|
<view class="line"> |
||||||
|
<view class="name">省份</view> |
||||||
|
<view class="val">{{ form.provinceName }}</view> |
||||||
|
</view> |
||||||
|
<view class="line"> |
||||||
|
<view class="name">城市</view> |
||||||
|
<view class="val">{{ form.cityName }}</view> |
||||||
|
</view> |
||||||
|
<view :class="['line req', {err: err === 'industryClass'}]"> |
||||||
|
<view class="name">行业类型</view> |
||||||
|
<view v-if="isDetail" class="val">{{ form.industryClassName }}</view> |
||||||
|
<uni-data-picker v-else class="picker-input" placeholder="请选择行业类型" popup-title="请选择行业类型" preload :clear-icon="false" :localdata="industryClassList" :map="{text: 'industryClassName', value: 'industryClassId'}" v-model="form.industryClassId" @change="industryClassChange"></uni-data-picker> |
||||||
|
</view> |
||||||
|
<view :class="['line req', {err: err === 'industry'}]"> |
||||||
|
<view class="name">行业</view> |
||||||
|
<view v-if="isDetail" class="val">{{ form.industryName }}</view> |
||||||
|
<uni-data-picker v-else class="picker-input" placeholder="请选择行业" popup-title="请选择行业" preload :clear-icon="false" :localdata="industryList" :map="{text: 'industryName', value: 'industryId'}" v-model="form.industryId" :readonly="form.industryClassId ? false : true" @change="handleErr('industry')"></uni-data-picker> |
||||||
|
</view> |
||||||
|
<view :class="['line req', {err: err === 'name'}]"> |
||||||
|
<view class="name">联系人姓名</view> |
||||||
|
<view v-if="isDetail" class="val">{{ form.name }}</view> |
||||||
|
<input v-else type="text" placeholder="请输入" v-model="form.name" @change="handleErr('name')"> |
||||||
|
</view> |
||||||
|
<view class="line"> |
||||||
|
<view class="name">手机</view> |
||||||
|
<view v-if="isDetail" class="val">{{ form.phone }}</view> |
||||||
|
<input v-else type="number" maxlength="11" placeholder="请输入" v-model="form.phone"> |
||||||
|
</view> |
||||||
|
<view :class="['line req', {err: err === 'account'}]"> |
||||||
|
<view class="name">账号</view> |
||||||
|
<view v-if="isDetail" class="val">{{ form.account }}</view> |
||||||
|
<input v-else type="text" placeholder="请以院校首字母+admin的格式来设置" v-model="form.account" @change="handleErr('account')"> |
||||||
|
</view> |
||||||
|
<view class="line"> |
||||||
|
<view class="name">职务</view> |
||||||
|
<view v-if="isDetail" class="val">{{ form.position }}</view> |
||||||
|
<input v-else type="text" placeholder="请输入" v-model="form.position"> |
||||||
|
</view> |
||||||
|
<view class="line"> |
||||||
|
<view class="name">邮箱</view> |
||||||
|
<view v-if="isDetail" class="val">{{ form.email }}</view> |
||||||
|
<input v-else type="text" placeholder="请输入" v-model="form.email"> |
||||||
|
</view> |
||||||
|
<view v-if="customerId" class="line"> |
||||||
|
<view class="name">产品到期时间</view> |
||||||
|
<view class="val">{{ form.expireDate }}</view> |
||||||
|
</view> |
||||||
|
<view v-if="customerId" class="line"> |
||||||
|
<view class="name">客户类型</view> |
||||||
|
<view class="val">{{ customerType }}</view> |
||||||
|
</view> |
||||||
|
</view> |
||||||
|
</view> |
||||||
|
|
||||||
|
<view v-if="isDetail" class="action"> |
||||||
|
<view class="item" @click="toPage(`../clientDetail/clientDetail?customerId=${customerId}`)"> |
||||||
|
<uni-icons class="icon" custom-prefix="iconfont" type="icon-edit" size="30" color="#959595"></uni-icons> |
||||||
|
<view class="text">编辑</view> |
||||||
|
</view> |
||||||
|
<view class="item" @click="toPage(`/order/ordered/ordered?customerId=${customerId}`)"> |
||||||
|
<uni-icons class="icon" custom-prefix="iconfont" type="icon-product" size="30" color="#959595"></uni-icons> |
||||||
|
<view class="text">已订阅产品</view> |
||||||
|
</view> |
||||||
|
<view class="item" @click="toPage(`/order/curClient/curClient?customerId=${customerId}&name=${form.customerName}`)"> |
||||||
|
<uni-icons class="icon" custom-prefix="iconfont" type="icon-dingdan" size="30" color="#959595"></uni-icons> |
||||||
|
<view class="text">订单</view> |
||||||
|
</view> |
||||||
|
</view> |
||||||
|
<view v-else class="btn-wrap"> |
||||||
|
<view class="btn" @click="submit">确定</view> |
||||||
|
</view> |
||||||
|
|
||||||
|
<view class="popup-mask" v-show="schoolVisible" @click="closeSchool"></view> |
||||||
|
<view class="popup" v-show="schoolVisible"> |
||||||
|
<view class="top">请选择学校</view> |
||||||
|
<uni-icons class="close" type="closeempty" size="20" @click="closeSchool"></uni-icons> |
||||||
|
<uni-search-bar class="search" radius="5" placeholder="请输入学校名称" v-model="keyword" clearButton="auto" cancelButton="none" /> |
||||||
|
<view class="list"> |
||||||
|
<view class="item" v-for="item in schoolList" @click="schoolChange(item)">{{ item.schoolName }}</view> |
||||||
|
</view> |
||||||
|
</view> |
||||||
|
</view> |
||||||
|
</template> |
||||||
|
|
||||||
|
<script> |
||||||
|
import { queryCustomerDetails, querySchool, queryIndustryClass, queryIndustry, queryCustomerIsExists, addCustomer, updateCustomer } from '@/apis/modules/client.js' |
||||||
|
export default { |
||||||
|
data() { |
||||||
|
return { |
||||||
|
isDetail: false, |
||||||
|
customerId: '', |
||||||
|
// 客户类型 |
||||||
|
customerTypeList: [{ |
||||||
|
name: '正式', |
||||||
|
value: 1 |
||||||
|
}, |
||||||
|
{ |
||||||
|
name: '试用', |
||||||
|
value: 2 |
||||||
|
}, |
||||||
|
{ |
||||||
|
name: '到期', |
||||||
|
value: 3 |
||||||
|
}], |
||||||
|
nameRepeat: false, |
||||||
|
schoolVisible: false, |
||||||
|
keyword: '', |
||||||
|
searchTimer: null, |
||||||
|
schoolList: [], |
||||||
|
schoolListAll: [], |
||||||
|
industryClassList: [], |
||||||
|
industryList: [], |
||||||
|
form: { |
||||||
|
countries: '中国', |
||||||
|
customerId: '', |
||||||
|
customerName: '', |
||||||
|
industryClassId: '', |
||||||
|
industryId: '', |
||||||
|
provinceId: '', |
||||||
|
provinceName: '', |
||||||
|
account: '', |
||||||
|
name: '', |
||||||
|
phone: '', |
||||||
|
position: '', |
||||||
|
cityId: '', |
||||||
|
cityName: '', |
||||||
|
customerType: '', |
||||||
|
expireDate: '', |
||||||
|
email: '', |
||||||
|
schoolId: '' |
||||||
|
}, |
||||||
|
customerType: '', |
||||||
|
err: '' |
||||||
|
} |
||||||
|
}, |
||||||
|
watch: { |
||||||
|
keyword () { |
||||||
|
clearTimeout(this.searchTimer) |
||||||
|
this.searchTimer = setTimeout(() => { |
||||||
|
this.filterSchool() |
||||||
|
}, 500) |
||||||
|
} |
||||||
|
}, |
||||||
|
onShow() { |
||||||
|
const pages = getCurrentPages() |
||||||
|
const { options } = pages[pages.length - 1] |
||||||
|
this.customerId = options.customerId |
||||||
|
this.isDetail = !!options.show |
||||||
|
|
||||||
|
options.customerId && this.getInfo() |
||||||
|
// 非详情才需要查询学校和行业 |
||||||
|
if (!this.isDetail) { |
||||||
|
this.getSchool() |
||||||
|
this.getIndustryClass() |
||||||
|
} |
||||||
|
// 设置标题 |
||||||
|
uni.setNavigationBarTitle({ |
||||||
|
title: options.customerId ? |
||||||
|
(options.show ? |
||||||
|
'客户详情' : |
||||||
|
'编辑客户') : |
||||||
|
'新增客户' |
||||||
|
}) |
||||||
|
}, |
||||||
|
methods: { |
||||||
|
// 获取详情 |
||||||
|
getInfo() { |
||||||
|
uni.showLoading({ |
||||||
|
title: '加载中' |
||||||
|
}) |
||||||
|
queryCustomerDetails({ |
||||||
|
customerId: this.customerId |
||||||
|
}).then(({ result }) => { |
||||||
|
const { customer } = result |
||||||
|
this.form = customer |
||||||
|
!this.isDetail && customer.industryClassId && this.getIndustry() |
||||||
|
this.customerType = this.customerTypeList.find(e => e.value === customer.customerType).name |
||||||
|
uni.hideLoading() |
||||||
|
}).catch(e => { |
||||||
|
uni.hideLoading() |
||||||
|
}) |
||||||
|
}, |
||||||
|
// 获取学校列表 |
||||||
|
getSchool() { |
||||||
|
querySchool({ |
||||||
|
schoolName: '', |
||||||
|
provinceId: '', |
||||||
|
cityId: '' |
||||||
|
}).then(({ list }) => { |
||||||
|
this.schoolListAll = list |
||||||
|
this.schoolList = list |
||||||
|
}).catch(res => {}) |
||||||
|
}, |
||||||
|
// 学校模糊匹配 |
||||||
|
filterSchool() { |
||||||
|
const { keyword } = this |
||||||
|
this.schoolList = keyword ? |
||||||
|
this.schoolListAll.filter(e => e.schoolName.includes(keyword)) : |
||||||
|
this.schoolListAll |
||||||
|
}, |
||||||
|
// 关闭学校弹框 |
||||||
|
closeSchool() { |
||||||
|
this.schoolVisible = false |
||||||
|
this.keyword = '' |
||||||
|
}, |
||||||
|
// 客户名称选择回调 |
||||||
|
schoolChange(school) { |
||||||
|
const { form } = this |
||||||
|
const { schoolId } = school |
||||||
|
form.schoolId = schoolId |
||||||
|
form.customerName = school.schoolName |
||||||
|
form.provinceId = school.provinceId |
||||||
|
form.provinceName = school.provinceName |
||||||
|
form.cityId = school.cityId |
||||||
|
form.cityName = school.cityName |
||||||
|
this.closeSchool() |
||||||
|
// 客户名称判重 |
||||||
|
queryCustomerIsExists({ |
||||||
|
schoolId |
||||||
|
}).then(res => { |
||||||
|
this.nameRepeat = false |
||||||
|
this.handleErr('customerName') |
||||||
|
}).catch(res => { |
||||||
|
this.nameRepeat = true |
||||||
|
this.err = 'customerName' |
||||||
|
}) |
||||||
|
}, |
||||||
|
// 处理错误提示 |
||||||
|
handleErr(val) { |
||||||
|
if (val === this.err) this.err = '' |
||||||
|
}, |
||||||
|
// 获取行业类 |
||||||
|
getIndustryClass() { |
||||||
|
queryIndustryClass().then(({ list }) => { |
||||||
|
this.industryClassList = list |
||||||
|
}).catch(res => {}) |
||||||
|
}, |
||||||
|
// 行业分类选择回调 |
||||||
|
industryClassChange() { |
||||||
|
this.handleErr('industryClass') |
||||||
|
this.getIndustry() |
||||||
|
}, |
||||||
|
// 获取行业 |
||||||
|
getIndustry() { |
||||||
|
queryIndustry({ |
||||||
|
industryClassId: this.form.industryClassId |
||||||
|
}).then(({ list }) => { |
||||||
|
this.industryList = list |
||||||
|
}).catch(res => {}) |
||||||
|
}, |
||||||
|
// 跳转 |
||||||
|
toPage(path) { |
||||||
|
this.$util.to(path) |
||||||
|
}, |
||||||
|
// 提交 |
||||||
|
submit() { |
||||||
|
const refs = this.$refs |
||||||
|
const { form } = this |
||||||
|
const { schoolId, industryClassId, industryId, name, account } = form |
||||||
|
if (!schoolId) { |
||||||
|
this.err = 'customerName' |
||||||
|
return this.$util.errMsg('请选择客户!') |
||||||
|
}
if (this.nameRepeat) { |
||||||
|
this.err = 'customerName' |
||||||
|
return this.$util.errMsg('客户已存在!') |
||||||
|
}
if (!industryClassId) { |
||||||
|
this.err = 'industryClass' |
||||||
|
return this.$util.errMsg('请选择行业类型!') |
||||||
|
}
if (!industryId) { |
||||||
|
this.err = 'industry' |
||||||
|
return this.$util.errMsg('请选择行业!') |
||||||
|
}
if (!name) { |
||||||
|
this.err = 'name' |
||||||
|
return this.$util.errMsg('请输入联系人姓名!') |
||||||
|
}
if (!account) { |
||||||
|
this.err = 'account' |
||||||
|
return this.$util.errMsg('请输入账号!') |
||||||
|
} |
||||||
|
uni.showLoading({ |
||||||
|
title: '提交中' |
||||||
|
}) |
||||||
|
if (this.customerId) { |
||||||
|
updateCustomer(form).then(res => { |
||||||
|
uni.hideLoading() |
||||||
|
this.$util.sucMsg('编辑成功') |
||||||
|
setTimeout(() => { |
||||||
|
uni.navigateBack() |
||||||
|
}, 1500) |
||||||
|
}).catch(res => {}) |
||||||
|
} else { |
||||||
|
addCustomer(form).then(({ customerId }) => { |
||||||
|
uni.hideLoading() |
||||||
|
const that = this |
||||||
|
uni.showModal({ |
||||||
|
title: '提示', |
||||||
|
content: '创建客户成功,是否马上为该客户创建订单?', |
||||||
|
success: function (res) { |
||||||
|
if (res.confirm) { |
||||||
|
// 选择是则直接跳转到新建订单页面,并且选中当前新加的客户 |
||||||
|
uni.redirectTo({ |
||||||
|
url: `/order/orderDetail/orderDetail?customerId=${customerId}` |
||||||
|
}) |
||||||
|
} else if (res.cancel) { |
||||||
|
uni.navigateBack() |
||||||
|
} |
||||||
|
} |
||||||
|
}) |
||||||
|
}).catch(res => {}) |
||||||
|
} |
||||||
|
}, |
||||||
|
} |
||||||
|
} |
||||||
|
</script> |
||||||
|
|
||||||
|
<style scoped lang="scss"> |
||||||
|
.page { |
||||||
|
padding-bottom: 170rpx; |
||||||
|
-webkit-overflow-scrolling: touch; |
||||||
|
} |
||||||
|
.info { |
||||||
|
.name { |
||||||
|
display: flex; |
||||||
|
align-items: center; |
||||||
|
margin-bottom: 5px; |
||||||
|
font-size: 16px; |
||||||
|
color: #333; |
||||||
|
} |
||||||
|
.school { |
||||||
|
width: 48rpx; |
||||||
|
margin-right: 10rpx; |
||||||
|
} |
||||||
|
} |
||||||
|
.action { |
||||||
|
z-index: 2; |
||||||
|
position: fixed; |
||||||
|
bottom: 0; |
||||||
|
display: flex; |
||||||
|
justify-content: space-around; |
||||||
|
width: 100%; |
||||||
|
padding: 5px 10px; |
||||||
|
padding-bottom: env(safe-area-inset-bottom); |
||||||
|
background-color: #fff; |
||||||
|
border-top: 1px solid #f3f3f3; |
||||||
|
box-shadow: 0 -2px 2px #f5f5f5; |
||||||
|
box-sizing: border-box; |
||||||
|
.item { |
||||||
|
text-align: center; |
||||||
|
} |
||||||
|
.text { |
||||||
|
font-size: 10px; |
||||||
|
color: #959595; |
||||||
|
} |
||||||
|
} |
||||||
|
</style> |
@ -0,0 +1,244 @@ |
|||||||
|
<template> |
||||||
|
<view class="page"> |
||||||
|
<view class="filter"> |
||||||
|
<uni-search-bar class="search" radius="30" placeholder="请输入客户名称" v-model="keyword" clearButton="auto" cancelButton="none" /> |
||||||
|
<uni-icons class="icon" custom-prefix="iconfont" type="icon-filter" size="22" color="#007eff" @click="popup = true"></uni-icons> |
||||||
|
</view> |
||||||
|
<ul class="tab"> |
||||||
|
<li v-for="(tab, i) in tabs" :class="{active: curTab === tab.id}" @click="tabChange(tab)">{{ tab.name }}</li> |
||||||
|
</ul> |
||||||
|
|
||||||
|
<template v-if="list.length"> |
||||||
|
<ul class="list"> |
||||||
|
<li v-for="item in list" @click="toDetail(item)"> |
||||||
|
<view class="c-name">{{ item.customerName }}</view> |
||||||
|
<view class="info"> |
||||||
|
<view class="left"> |
||||||
|
<view class="line"> |
||||||
|
<text class="name">联系人:</text> |
||||||
|
<text class="val">{{ item.orderContact }}</text> |
||||||
|
</view> |
||||||
|
<view class="line"> |
||||||
|
<text class="name">账号:</text> |
||||||
|
<text class="val">{{ item.account }}</text> |
||||||
|
</view> |
||||||
|
<view class="line"> |
||||||
|
<text class="name">产品到期时间:</text> |
||||||
|
<text class="val">{{ item.expireDate.split(' ')[0] }}</text> |
||||||
|
</view> |
||||||
|
<view class="line"> |
||||||
|
<text class="name">商务经理:</text> |
||||||
|
<text class="val">{{ item.businessManagerName }}</text> |
||||||
|
</view> |
||||||
|
</view> |
||||||
|
<view class="type"> |
||||||
|
{{ filterData[0].data.find(e => e.value === item.customerType).title }}客户 |
||||||
|
</view> |
||||||
|
</view> |
||||||
|
</li> |
||||||
|
</ul> |
||||||
|
<uni-load-more :status="status" /> |
||||||
|
</template> |
||||||
|
<empty v-else text="您当前暂无有下单的客户,请快去给客户下订单吧"></empty> |
||||||
|
|
||||||
|
<uni-icons class="plus" type="plus-filled" size="60" color="#007eff" @click="$util.to('../clientDetail/clientDetail')"></uni-icons> |
||||||
|
<filter-popup :data="filterData" :form.sync="filterForm" v-model="popup" title="全部筛选" height="1104rpx" @finsh="subFinsh"></filter-popup> |
||||||
|
</view> |
||||||
|
</template> |
||||||
|
|
||||||
|
<script> |
||||||
|
import { list, all } from '@/apis/modules/client.js' |
||||||
|
export default { |
||||||
|
data() { |
||||||
|
return { |
||||||
|
popup: false, |
||||||
|
//筛选表单数据 |
||||||
|
filterData: [ |
||||||
|
{ |
||||||
|
children: false,//是否有子项 |
||||||
|
title: "客户类型", |
||||||
|
key: "customerType", //键名 接收对象名字 |
||||||
|
keyValue: "value", //获取的值是哪个 |
||||||
|
isRadio: true, //是否单选 否则多选 |
||||||
|
data: [ |
||||||
|
{ |
||||||
|
title: '正式', |
||||||
|
value: 1 |
||||||
|
}, |
||||||
|
{ |
||||||
|
title: '试用', |
||||||
|
value: 2 |
||||||
|
}, |
||||||
|
{ |
||||||
|
title: '到期', |
||||||
|
value: 3 |
||||||
|
} |
||||||
|
], |
||||||
|
} |
||||||
|
], |
||||||
|
filterForm: { |
||||||
|
customerType: [] |
||||||
|
}, |
||||||
|
curTab: 0, |
||||||
|
tabs: [], |
||||||
|
reachBottom: 0, // 是否是上拉加载。0->否,1->是,-1->加载完所有数据 |
||||||
|
status: 'more', // 上拉加载状态 more|loading|noMore |
||||||
|
searchTimer: null, |
||||||
|
customerType: '', |
||||||
|
keyword: '', |
||||||
|
list: [], |
||||||
|
page: 1, |
||||||
|
pageSize: 10 |
||||||
|
} |
||||||
|
}, |
||||||
|
watch: { |
||||||
|
keyword () { |
||||||
|
clearTimeout(this.searchTimer) |
||||||
|
this.searchTimer = setTimeout(() => { |
||||||
|
this.initList() |
||||||
|
}, 500) |
||||||
|
} |
||||||
|
}, |
||||||
|
// 下拉刷新 |
||||||
|
onPullDownRefresh() { |
||||||
|
this.initList() |
||||||
|
setTimeout(() => { |
||||||
|
uni.stopPullDownRefresh() |
||||||
|
}, 1500) |
||||||
|
}, |
||||||
|
// 上拉加载 |
||||||
|
onReachBottom() { |
||||||
|
if (this.reachBottom >= 0) { |
||||||
|
this.reachBottom = 1 |
||||||
|
this.status = 'loading' |
||||||
|
this.getList() |
||||||
|
} |
||||||
|
}, |
||||||
|
onShow() { |
||||||
|
this.initRole() |
||||||
|
}, |
||||||
|
methods: { |
||||||
|
// 初始化权限 |
||||||
|
initRole() { |
||||||
|
this.tabs = [] |
||||||
|
const auth = uni.getStorageSync('auth') |
||||||
|
auth.includes('首页:客户:我的客户') && this.tabs.push({ |
||||||
|
name: '我的客户', |
||||||
|
id: 0 |
||||||
|
}) |
||||||
|
auth.includes('首页:客户:团队全部客户') && this.tabs.push({ |
||||||
|
name: '团队全部客户', |
||||||
|
id: 1 |
||||||
|
}) |
||||||
|
const len = this.tabs.length |
||||||
|
// 只有一个的话,取第一个,而且不用显示tab |
||||||
|
if (len === 1) { |
||||||
|
this.curTab = this.tabs[0].id |
||||||
|
this.tabs = [] |
||||||
|
} |
||||||
|
this.initList() |
||||||
|
}, |
||||||
|
// 获取列表 |
||||||
|
getList() { |
||||||
|
const data = { |
||||||
|
businessManagerId: this.$util.getBmId(), |
||||||
|
teamId: uni.getStorageSync('team').id, |
||||||
|
customerType: this.customerType, |
||||||
|
keywords: this.keyword, |
||||||
|
pageNum: this.page, |
||||||
|
pageSize: this.pageSize, |
||||||
|
type: this.curTab // 团队:1 / 个人:0 |
||||||
|
} |
||||||
|
uni.showLoading({ |
||||||
|
title: '加载中' |
||||||
|
}) |
||||||
|
all(data).then(({ data }) => { |
||||||
|
uni.hideLoading() |
||||||
|
// 未加载完所有数据,并且不是筛选,则拼接list,否则直接赋值 |
||||||
|
this.list = this.reachBottom > 0 ? [...this.list, ...data.records] : data.records |
||||||
|
this.page++ // 每次获取了数据后page+1 |
||||||
|
const noMore = this.list.length === data.total // 是否加载完所有数据 |
||||||
|
this.status = noMore ? 'noMore' : 'more' // 加载完了则设置为noMore |
||||||
|
this.reachBottom = noMore ? -1 : 0 // 加载完了则设置为-1 |
||||||
|
}).catch(e => { |
||||||
|
uni.hideLoading() |
||||||
|
}) |
||||||
|
}, |
||||||
|
initList() { |
||||||
|
this.page = 1 |
||||||
|
this.reachBottom = 0 |
||||||
|
this.getList() |
||||||
|
}, |
||||||
|
// 筛选确定回调 |
||||||
|
subFinsh(val) { |
||||||
|
const { customerType } = val |
||||||
|
this.customerType = customerType.length ? customerType[0] : '' |
||||||
|
this.initList() |
||||||
|
}, |
||||||
|
// tab切换 |
||||||
|
tabChange(tab) { |
||||||
|
this.curTab = tab.id |
||||||
|
this.initList() |
||||||
|
}, |
||||||
|
// 跳转详情 |
||||||
|
toDetail(item) { |
||||||
|
this.$util.to(`../clientDetail/clientDetail?customerId=${item.customerId}&show=1`) |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
</script> |
||||||
|
|
||||||
|
<style scoped lang="scss"> |
||||||
|
.page { |
||||||
|
padding-bottom: 90px; |
||||||
|
} |
||||||
|
.filter { |
||||||
|
display: flex; |
||||||
|
align-items: center; |
||||||
|
.search { |
||||||
|
flex: 1; |
||||||
|
} |
||||||
|
.sl-filter { |
||||||
|
width: 30%; |
||||||
|
margin-left: 10%; |
||||||
|
} |
||||||
|
} |
||||||
|
.list { |
||||||
|
margin-top: 20rpx; |
||||||
|
background-color: #fff; |
||||||
|
li { |
||||||
|
padding: 20rpx 40rpx; |
||||||
|
border-bottom: 1px solid #f1f1f1; |
||||||
|
} |
||||||
|
.c-name { |
||||||
|
font-size: 30rpx; |
||||||
|
color: #333; |
||||||
|
} |
||||||
|
.info { |
||||||
|
display: flex; |
||||||
|
justify-content: space-between; |
||||||
|
align-items: center; |
||||||
|
margin-top: 10rpx; |
||||||
|
} |
||||||
|
.line { |
||||||
|
display: flex; |
||||||
|
padding: 10rpx 0; |
||||||
|
} |
||||||
|
.name { |
||||||
|
width: 200rpx; |
||||||
|
margin-right: 10rpx; |
||||||
|
font-size: 28rpx; |
||||||
|
color: #999; |
||||||
|
} |
||||||
|
.val { |
||||||
|
max-width: 70%; |
||||||
|
font-size: 28rpx; |
||||||
|
color: #333; |
||||||
|
} |
||||||
|
.type { |
||||||
|
font-size: 28rpx; |
||||||
|
color: #ff7b2d; |
||||||
|
white-space: nowrap; |
||||||
|
} |
||||||
|
} |
||||||
|
</style> |
@ -0,0 +1,113 @@ |
|||||||
|
<template> |
||||||
|
<view class="page"> |
||||||
|
<view class="input"> |
||||||
|
<uni-easyinput v-model="form.email" placeholder="请填写你的邮箱" :clearable="false" /> |
||||||
|
</view> |
||||||
|
<view class="input code-wrap"> |
||||||
|
<uni-easyinput class="code" v-model="form.code" placeholder="验证码" :clearable="false" /> |
||||||
|
<view class="send-code" @click="sendCode" :disabled="codeDisabled">{{ btnText }}</view> |
||||||
|
</view> |
||||||
|
<button type="primary" @click="submit">确认</button> |
||||||
|
</view> |
||||||
|
</template> |
||||||
|
|
||||||
|
<script> |
||||||
|
import { updateMyEmail, mailCodeSend } from '@/apis/modules/user.js' |
||||||
|
export default { |
||||||
|
data() { |
||||||
|
return { |
||||||
|
userId: '', |
||||||
|
form: { |
||||||
|
email: '', |
||||||
|
code: '' |
||||||
|
}, |
||||||
|
codeDisabled: false, |
||||||
|
phoneTimer: null, |
||||||
|
btnText: '发送验证码', |
||||||
|
} |
||||||
|
}, |
||||||
|
onShow() { |
||||||
|
|
||||||
|
}, |
||||||
|
methods: { |
||||||
|
// 发送验证码 |
||||||
|
sendCode() { |
||||||
|
const { email } = this.form |
||||||
|
if (!email) return this.$util.errMsg('请输入邮箱') |
||||||
|
if (!/^([a-zA-Z]|[0-9])(\w|\-)+@[a-zA-Z0-9]+\.([a-zA-Z]{2,4})$/.test(email) && !/^([a-zA-Z]|[0-9])(\w|\-)+@[a-zA-Z0-9]+\.([a-zA-Z]{2,4})$/.test(email)) return this.$util.errMsg('请输入正确的请输入邮箱') |
||||||
|
mailCodeSend({ |
||||||
|
email, |
||||||
|
platformId: 4 |
||||||
|
}).then(res => { |
||||||
|
this.phoneCountdown() |
||||||
|
}).catch(res => {}) |
||||||
|
}, |
||||||
|
// 验证码倒计时 |
||||||
|
phoneCountdown() { |
||||||
|
let count = 60 |
||||||
|
if (!this.phoneTimer) { |
||||||
|
this.codeDisabled = true |
||||||
|
this.phoneTimer = setInterval(() => { |
||||||
|
if (count > 0) { |
||||||
|
count-- |
||||||
|
this.btnText = `${count}秒后重试` |
||||||
|
} else { |
||||||
|
this.codeDisabled = false |
||||||
|
clearInterval(this.phoneTimer) |
||||||
|
this.phoneTimer = null |
||||||
|
this.btnText = `发送验证码` |
||||||
|
} |
||||||
|
}, 1000) |
||||||
|
} |
||||||
|
}, |
||||||
|
// 提交 |
||||||
|
submit() { |
||||||
|
const { email, code } = this.form |
||||||
|
if (!email) return this.$util.errMsg('请输入邮箱') |
||||||
|
if (!code) return this.$util.errMsg('请输入验证码') |
||||||
|
updateMyEmail({ |
||||||
|
email, |
||||||
|
code, |
||||||
|
platformId: 4 |
||||||
|
}).then(res => { |
||||||
|
this.$util.sucMsg('修改成功!') |
||||||
|
setTimeout(() => { |
||||||
|
uni.navigateBack() |
||||||
|
}, 1500) |
||||||
|
}).catch(res => {}) |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
</script> |
||||||
|
|
||||||
|
<style scoped lang="scss"> |
||||||
|
.page { |
||||||
|
padding: 20px; |
||||||
|
background-color: #fff; |
||||||
|
} |
||||||
|
/deep/.input { |
||||||
|
margin-bottom: 15px; |
||||||
|
.is-input-border { |
||||||
|
border-color: #dedede !important; |
||||||
|
} |
||||||
|
} |
||||||
|
.input { |
||||||
|
margin-bottom: 20px; |
||||||
|
} |
||||||
|
.code-wrap { |
||||||
|
display: flex; |
||||||
|
} |
||||||
|
.code { |
||||||
|
flex: 1; |
||||||
|
} |
||||||
|
.send-code { |
||||||
|
width: 100px; |
||||||
|
margin-left: 20px; |
||||||
|
text-align: center; |
||||||
|
color: #4386ff; |
||||||
|
font-size: 12px; |
||||||
|
line-height: 36px; |
||||||
|
border: 1px solid #4386ff; |
||||||
|
border-radius: 5px; |
||||||
|
} |
||||||
|
</style> |
@ -0,0 +1,349 @@ |
|||||||
|
<template> |
||||||
|
<view :class="['page', {oh: !per}]"> |
||||||
|
<image class="bg" src="@/static/image/index/index2.png" mode="widthFix"></image> |
||||||
|
<view class="team"> |
||||||
|
<uni-data-picker class="picker-input" placeholder="切换团队" popup-title="切换团队" preload :clear-icon="false" :localdata="list" :map="{text: 'partnerClassificationName', value: 'teamId'}" v-model="teamId" @change="teamChange"></uni-data-picker> |
||||||
|
</view> |
||||||
|
|
||||||
|
<view class="banner"> |
||||||
|
<image class="img" src="@/static/image/index/index1.png" mode="widthFix"></image> |
||||||
|
<view class="info"> |
||||||
|
<view class="title">城市合伙人招募中</view> |
||||||
|
<view class="text">携手共创教育信息化新未来,合伙共享产业互联领域新红利</view> |
||||||
|
</view> |
||||||
|
</view> |
||||||
|
|
||||||
|
<ul class="entry"> |
||||||
|
<li v-if="auth('首页:客户')" @click="$util.to('../clients/clients')"> |
||||||
|
<image class="icon" src="@/static/image/index/index3.png" mode="widthFix"></image> |
||||||
|
<view class="text">客户</view> |
||||||
|
</li> |
||||||
|
<li @click="$util.to('../plans/plans')"> |
||||||
|
<image class="icon" src="@/static/image/index/index4.png" mode="widthFix"></image> |
||||||
|
<view class="text">方案</view> |
||||||
|
</li> |
||||||
|
<li v-if="auth('首页:订单')" @click="$util.to('/order/orders/orders')"> |
||||||
|
<image class="icon" src="@/static/image/index/index5.png" mode="widthFix"></image> |
||||||
|
<view class="text">订单</view> |
||||||
|
</li> |
||||||
|
<li @click="$util.to('../products/products')"> |
||||||
|
<image class="icon" src="@/static/image/index/index6.png" mode="widthFix"></image> |
||||||
|
<view class="text">产品</view> |
||||||
|
</li> |
||||||
|
</ul> |
||||||
|
|
||||||
|
<view class="panel"> |
||||||
|
<view class="title" @click="toPanel(1)"> |
||||||
|
<view class="left"> |
||||||
|
<image class="icon" src="@/static/image/index/index8.png" mode="widthFix"></image> |
||||||
|
销售进展 |
||||||
|
</view> |
||||||
|
<view class="right"> |
||||||
|
<image class="date" src="@/static/image/index/index7.png" mode="widthFix"></image> |
||||||
|
<text>本月</text> |
||||||
|
<image class="arrow" src="@/static/image/index/index10.png" mode="widthFix"></image> |
||||||
|
</view> |
||||||
|
</view> |
||||||
|
<view class="data first"> |
||||||
|
<view class="line"> |
||||||
|
<view class="item"> |
||||||
|
<view class="name">本月新增客户</view> |
||||||
|
<view class="val">0</view> |
||||||
|
</view> |
||||||
|
<view class="item"> |
||||||
|
<view class="name">我的客户</view> |
||||||
|
<view class="val">0</view> |
||||||
|
</view> |
||||||
|
</view> |
||||||
|
<view class="line"> |
||||||
|
<view class="item"> |
||||||
|
<view class="name">本月新增产品试用</view> |
||||||
|
<view class="val">0</view> |
||||||
|
</view> |
||||||
|
<view class="item"> |
||||||
|
<view class="name">试用客户</view> |
||||||
|
<view class="val">0</view> |
||||||
|
</view> |
||||||
|
</view> |
||||||
|
</view> |
||||||
|
</view> |
||||||
|
|
||||||
|
|
||||||
|
<view class="panel"> |
||||||
|
<view class="title y-title" @click="toPanel(1)"> |
||||||
|
<view class="left"> |
||||||
|
<image class="icon" src="@/static/image/index/index9.png" mode="widthFix"></image> |
||||||
|
年度业绩看板 |
||||||
|
</view> |
||||||
|
<image class="arrow" src="@/static/image/index/index10.png" mode="widthFix"></image> |
||||||
|
</view> |
||||||
|
<view class="data second"> |
||||||
|
<view class="line"> |
||||||
|
<view class="item"> |
||||||
|
<view class="val">0</view> |
||||||
|
<view class="name">成交总额</view> |
||||||
|
</view> |
||||||
|
<view class="item"> |
||||||
|
<view class="val">0</view> |
||||||
|
<view class="name">收益金额</view> |
||||||
|
</view> |
||||||
|
<view class="item"> |
||||||
|
<view class="val">0</view> |
||||||
|
<view class="name">已到账</view> |
||||||
|
</view> |
||||||
|
<view class="item"> |
||||||
|
<view class="val">0</view> |
||||||
|
<view class="name">未到账</view> |
||||||
|
</view> |
||||||
|
</view> |
||||||
|
</view> |
||||||
|
</view> |
||||||
|
<view v-if="!per" class="per-mask">功能升级中,敬请期待...</view> |
||||||
|
</view> |
||||||
|
</template> |
||||||
|
|
||||||
|
<script> |
||||||
|
import { getUserRolesPermissionMenu } from '@/apis/modules/user.js' |
||||||
|
import { getTeamsByAccountId, getTheBusinessManagerIdsUnderTheTeam } from '@/apis/modules/client.js' |
||||||
|
import { treeList } from '@/apis/modules/parner.js' |
||||||
|
export default { |
||||||
|
data() { |
||||||
|
return { |
||||||
|
per: true, // 是否有权限 |
||||||
|
// teamId: uni.getStorageSync('team').teamId || '', |
||||||
|
teamId: '', |
||||||
|
list: [], |
||||||
|
id: '', |
||||||
|
teamList: [] |
||||||
|
} |
||||||
|
}, |
||||||
|
onShow() { |
||||||
|
this.per = true |
||||||
|
this.getInfo() |
||||||
|
}, |
||||||
|
methods: { |
||||||
|
// 初始化权限 |
||||||
|
initRole() { |
||||||
|
if (!uni.getStorageSync('auth').includes('首页')) { |
||||||
|
this.per = false |
||||||
|
} |
||||||
|
}, |
||||||
|
// 查询当前角色权限 |
||||||
|
getAuth() { |
||||||
|
uni.getStorageSync('token') && getUserRolesPermissionMenu({ |
||||||
|
teamId: this.list.find(e => e.teamId === this.teamId).partnerClassificationId, |
||||||
|
platformId: 4 |
||||||
|
}).then(({ permissionMenu }) => { |
||||||
|
uni.hideLoading() |
||||||
|
const auth = [] |
||||||
|
// 生成权限数组 |
||||||
|
const generateAuth = (list, parent) => { |
||||||
|
list.map(e => { |
||||||
|
const name = `${parent ? parent + ':' : ''}${e.name}` |
||||||
|
auth.push(name) |
||||||
|
generateAuth(e.children, name) |
||||||
|
}) |
||||||
|
} |
||||||
|
generateAuth(permissionMenu[0].children, '') |
||||||
|
uni.setStorageSync('auth', auth) |
||||||
|
this.$forceUpdate() |
||||||
|
this.initRole() |
||||||
|
}).catch(e => { |
||||||
|
uni.hideLoading() |
||||||
|
uni.setStorageSync('auth', []) |
||||||
|
this.initRole() |
||||||
|
}) |
||||||
|
}, |
||||||
|
// 获取团队 |
||||||
|
getInfo() { |
||||||
|
uni.showLoading({ |
||||||
|
title: '加载中' |
||||||
|
}) |
||||||
|
getTeamsByAccountId().then(({ data }) => { |
||||||
|
data.map(e => { |
||||||
|
const n = e.partnerClassificationList |
||||||
|
e.id = n.id |
||||||
|
e.teamId = e.isTeam == 1 ? e.partnerClassificationId : n.id |
||||||
|
e.partnerClassificationName = n.partnerClassificationName |
||||||
|
delete e.partnerClassificationList |
||||||
|
}) |
||||||
|
if (data.length) { |
||||||
|
/** |
||||||
|
* @description 如果是第一次进,则默认选中第一个团队,并把该团队的信息存入缓存 |
||||||
|
* 或者团队列表里没有该id,则说明超管已经被转让,也需要重新选中团队 |
||||||
|
*/ |
||||||
|
if (!this.teamId || !data.find(e => e.teamId == this.teamId)) { |
||||||
|
this.teamId = data[0].teamId |
||||||
|
uni.setStorageSync('team', data[0]) |
||||||
|
} |
||||||
|
} else { |
||||||
|
// 如果没有团队,则退出登录 |
||||||
|
uni.hideLoading() |
||||||
|
uni.clearStorageSync() |
||||||
|
uni.navigateTo({ |
||||||
|
url: '../login/login' |
||||||
|
}) |
||||||
|
} |
||||||
|
|
||||||
|
this.list = data |
||||||
|
this.getAuth() |
||||||
|
}).catch(e => { |
||||||
|
uni.hideLoading() |
||||||
|
}) |
||||||
|
}, |
||||||
|
// 团队选择回调 |
||||||
|
teamChange() { |
||||||
|
const { teamId } = this |
||||||
|
const e = this.list.find(e => e.teamId == teamId) |
||||||
|
uni.setStorageSync('team', e) |
||||||
|
this.getAuth() |
||||||
|
}, |
||||||
|
// 提示暂未开放 |
||||||
|
toPanel(i) { |
||||||
|
this.$util.errMsg('功能暂未开放!') |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
</script> |
||||||
|
|
||||||
|
<style scoped lang="scss"> |
||||||
|
.page { |
||||||
|
position: relative; |
||||||
|
min-height: 100%; |
||||||
|
padding: 30rpx 22rpx; |
||||||
|
box-sizing: border-box; |
||||||
|
} |
||||||
|
.bg { |
||||||
|
z-index: -1; |
||||||
|
position: absolute; |
||||||
|
top: 0; |
||||||
|
left: 0; |
||||||
|
width: 100%; |
||||||
|
height: 100%; |
||||||
|
} |
||||||
|
.team { |
||||||
|
width: 300rpx; |
||||||
|
margin-bottom: 30rpx; |
||||||
|
} |
||||||
|
.banner { |
||||||
|
position: relative; |
||||||
|
.img { |
||||||
|
width: 100%; |
||||||
|
} |
||||||
|
.info { |
||||||
|
position: absolute; |
||||||
|
top: 80rpx; |
||||||
|
left: 46rpx; |
||||||
|
} |
||||||
|
.title { |
||||||
|
margin-bottom: 15rpx; |
||||||
|
font-size: 36rpx; |
||||||
|
font-weight: 600; |
||||||
|
color: #001D67; |
||||||
|
} |
||||||
|
.text { |
||||||
|
font-size: 20rpx; |
||||||
|
font-family: PingFangSC-Regular, PingFang SC; |
||||||
|
color: #001D67; |
||||||
|
} |
||||||
|
} |
||||||
|
.entry { |
||||||
|
display: flex; |
||||||
|
justify-content: space-around; |
||||||
|
align-items: center; |
||||||
|
margin: 10rpx 0 30rpx; |
||||||
|
text-align: center; |
||||||
|
.icon { |
||||||
|
width: 78rpx; |
||||||
|
} |
||||||
|
.text { |
||||||
|
font-size: 28rpx; |
||||||
|
color: #333; |
||||||
|
} |
||||||
|
} |
||||||
|
.panel { |
||||||
|
margin: 20rpx 10rpx; |
||||||
|
background-color: #fff; |
||||||
|
border-radius: 20rpx; |
||||||
|
overflow: hidden; |
||||||
|
.title { |
||||||
|
display: flex; |
||||||
|
justify-content: space-between; |
||||||
|
align-items: center; |
||||||
|
padding: 17rpx 20rpx; |
||||||
|
background: linear-gradient(90deg, #E5EFFF 0%, #FFFFFF 100%); |
||||||
|
} |
||||||
|
.y-title { |
||||||
|
background: linear-gradient(90deg, #FFF5E5 0%, #FFFFFF 100%); |
||||||
|
} |
||||||
|
.left { |
||||||
|
display: flex; |
||||||
|
align-items: center; |
||||||
|
font-size: 30rpx; |
||||||
|
color: #333; |
||||||
|
} |
||||||
|
.right { |
||||||
|
display: flex; |
||||||
|
align-items: center; |
||||||
|
font-size: 28rpx; |
||||||
|
color: #333; |
||||||
|
text { |
||||||
|
margin: 0 15rpx 0 8rpx; |
||||||
|
} |
||||||
|
} |
||||||
|
.icon { |
||||||
|
width: 36rpx; |
||||||
|
margin-right: 10rpx; |
||||||
|
} |
||||||
|
.date { |
||||||
|
width: 26rpx; |
||||||
|
} |
||||||
|
.arrow { |
||||||
|
width: 16rpx; |
||||||
|
} |
||||||
|
.data { |
||||||
|
padding: 33rpx 36rpx; |
||||||
|
} |
||||||
|
.line { |
||||||
|
display: flex; |
||||||
|
} |
||||||
|
.first { |
||||||
|
.item:first-child { |
||||||
|
width: 65%; |
||||||
|
} |
||||||
|
.name { |
||||||
|
margin-bottom: 14rpx; |
||||||
|
font-size: 24rpx; |
||||||
|
color: #999; |
||||||
|
} |
||||||
|
.val { |
||||||
|
font-size: 30rpx; |
||||||
|
color: #333; |
||||||
|
} |
||||||
|
.line:first-child { |
||||||
|
margin-bottom: 32rpx; |
||||||
|
} |
||||||
|
} |
||||||
|
.second { |
||||||
|
padding: 38rpx 36rpx; |
||||||
|
.line { |
||||||
|
justify-content: space-between; |
||||||
|
} |
||||||
|
.item { |
||||||
|
text-align: center; |
||||||
|
} |
||||||
|
.val { |
||||||
|
margin-bottom: 10rpx; |
||||||
|
font-size: 30rpx; |
||||||
|
color: #333; |
||||||
|
} |
||||||
|
.name { |
||||||
|
font-size: 24rpx; |
||||||
|
color: #999; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
.oh { |
||||||
|
overflow: hidden; |
||||||
|
} |
||||||
|
</style> |
@ -0,0 +1,236 @@ |
|||||||
|
<template> |
||||||
|
<view class="page"> |
||||||
|
<view class="wrap"> |
||||||
|
<image class="logo" src="@/static/image/logo.png" mode=""></image> |
||||||
|
<view class="hello">Hi,城市合伙人请登录</view> |
||||||
|
<button v-if="isLogin && !getPhone" class="btn phone" open-type="getPhoneNumber" @getphonenumber="onGetPhoneNumber"> |
||||||
|
<image src="@/static/image/phone.png" mode="widthFix"></image> |
||||||
|
绑定手机 |
||||||
|
</button> |
||||||
|
<template v-else> |
||||||
|
<view class="btn wechat" @click="login"> |
||||||
|
<image src="@/static/image/wechat.png" mode="widthFix"></image> |
||||||
|
微信授权登录 |
||||||
|
</view> |
||||||
|
<view class="btn phone"> |
||||||
|
<image src="@/static/image/phone.png" mode="widthFix"></image> |
||||||
|
手机账号登录 |
||||||
|
</view> |
||||||
|
</template> |
||||||
|
|
||||||
|
<view class="agree"> |
||||||
|
<uni-data-checkbox class="check" multiple v-model="agree" :localdata="agreeData"></uni-data-checkbox> |
||||||
|
<text @click="toAgreement(0)">《用户服务协议》</text> |
||||||
|
<text @click="toAgreement(1)">《用户隐私协议》</text> |
||||||
|
</view> |
||||||
|
</view> |
||||||
|
</view> |
||||||
|
</template> |
||||||
|
|
||||||
|
<script> |
||||||
|
import { login, userBinding } from '@/apis/modules/user.js' |
||||||
|
import WXBizDataCrypt from '@/libs/WXBizDataCrypt' |
||||||
|
export default { |
||||||
|
data() { |
||||||
|
return { |
||||||
|
agree: [], |
||||||
|
agreeData: [{ |
||||||
|
text: '同意', |
||||||
|
value: 1 |
||||||
|
}], |
||||||
|
isLogin: false, // 是否已登录 |
||||||
|
getPhone: false ,// 是否已授权手机号 |
||||||
|
sessionKey: '', |
||||||
|
openId: '', |
||||||
|
unionid: '', |
||||||
|
submiting: false |
||||||
|
} |
||||||
|
}, |
||||||
|
onShow() { |
||||||
|
// 先授权用户信息,再授权手机号 |
||||||
|
this.checkLogin() |
||||||
|
}, |
||||||
|
methods: { |
||||||
|
// 检查登录状态 |
||||||
|
checkLogin() { |
||||||
|
if (uni.getStorageSync('token')) { |
||||||
|
this.toIndex() |
||||||
|
} else { |
||||||
|
uni.clearStorageSync() |
||||||
|
this.isLogin = false |
||||||
|
this.getPhone = false |
||||||
|
} |
||||||
|
}, |
||||||
|
// 授权用户信息 |
||||||
|
login() { |
||||||
|
if (this.agree.length) { |
||||||
|
if (this.submiting) return false |
||||||
|
const that = this |
||||||
|
uni.getUserProfile({ |
||||||
|
lang: 'zh_CN', |
||||||
|
desc: '登录', |
||||||
|
success: ({ userInfo }) => { |
||||||
|
console.log(22, userInfo) |
||||||
|
uni.setStorageSync('userName', userInfo.nickName) |
||||||
|
uni.setStorageSync('avatar', userInfo.avatarUrl) |
||||||
|
uni.login({ |
||||||
|
success: ({ code }) => { |
||||||
|
if (code) { |
||||||
|
this.submiting = true |
||||||
|
login({ |
||||||
|
code, |
||||||
|
avatarUrl: userInfo.avatarUrl |
||||||
|
}).then(({ data }) => { |
||||||
|
const e = data.sessionKey |
||||||
|
this.sessionKey = e.session_key |
||||||
|
this.openId = e.openid |
||||||
|
this.unionid = e.unionid |
||||||
|
uni.setStorageSync('sessionKey', e.session_key) |
||||||
|
this.submiting = false |
||||||
|
// 如果没有绑定手机号,则显示绑定按钮,引导用户绑定,否则,直接跳到首页 |
||||||
|
if (data.state === 'login') { |
||||||
|
this.toIndex() |
||||||
|
uni.setStorageSync('token', data.token) |
||||||
|
} else { |
||||||
|
this.isLogin = true |
||||||
|
} |
||||||
|
}).catch(e => { |
||||||
|
this.submiting = false |
||||||
|
}) |
||||||
|
} else { |
||||||
|
this.submiting = false |
||||||
|
that.$util.errMsg('登录失败!') |
||||||
|
} |
||||||
|
} |
||||||
|
}) |
||||||
|
}, |
||||||
|
fail(res) { |
||||||
|
that.$util.errMsg('登录授权失败!') |
||||||
|
} |
||||||
|
}) |
||||||
|
} else { |
||||||
|
this.$util.errMsg('请先阅读勾选协议!') |
||||||
|
} |
||||||
|
}, |
||||||
|
// 绑定手机号 |
||||||
|
onGetPhoneNumber(e){ |
||||||
|
if (this.submiting) return false |
||||||
|
const { encryptedData, iv } = e.detail |
||||||
|
// 获取手机号有两种方法,1.前端使用js完成;2.使用接口完成 |
||||||
|
// const WXBizDataCrypt = require('@/libs/WXBizDataCrypt') |
||||||
|
const accountInfo = uni.getAccountInfoSync() // 获取小程序appid |
||||||
|
const pc = new WXBizDataCrypt(accountInfo.miniProgram.appId , this.sessionKey) |
||||||
|
const data = pc.decryptData(encryptedData , iv) |
||||||
|
this.submiting = true |
||||||
|
// 绑定手机号 |
||||||
|
userBinding({ |
||||||
|
openId: this.openId, |
||||||
|
phone: data.phoneNumber, |
||||||
|
unionid: this.unionid |
||||||
|
}).then(({ token }) => { |
||||||
|
this.submiting = false |
||||||
|
uni.setStorageSync('token', token) |
||||||
|
this.toIndex() |
||||||
|
}).catch(e => { |
||||||
|
this.submiting = false |
||||||
|
uni.showToast({ |
||||||
|
title: e.message, |
||||||
|
icon: 'none' |
||||||
|
}) |
||||||
|
}) |
||||||
|
}, |
||||||
|
toAgreement(id) { |
||||||
|
this.$util.openFile(id) |
||||||
|
}, |
||||||
|
// 跳转到首页 |
||||||
|
toIndex() { |
||||||
|
uni.reLaunch({ |
||||||
|
url: '../index/index' |
||||||
|
}) |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
</script> |
||||||
|
|
||||||
|
<style scoped lang="scss"> |
||||||
|
.page { |
||||||
|
min-height: calc(100vh - 170rpx); |
||||||
|
padding-top: 170rpx; |
||||||
|
background: url(@/static/image/login1.png) 0 0/175rpx auto no-repeat, |
||||||
|
url(@/static/image/login2.png) bottom right/123rpx auto no-repeat; |
||||||
|
overflow: hidden; |
||||||
|
} |
||||||
|
.wrap { |
||||||
|
position: relative; |
||||||
|
height: 60vh; |
||||||
|
padding: 214rpx 74rpx 28rpx; |
||||||
|
margin: 0 61rpx; |
||||||
|
text-align: center; |
||||||
|
background-color: #fff; |
||||||
|
border-radius: 20rpx; |
||||||
|
.logo { |
||||||
|
width: 393rpx; |
||||||
|
height: 93rpx; |
||||||
|
} |
||||||
|
.hello { |
||||||
|
margin: 36rpx 0; |
||||||
|
font-size: 28rpx; |
||||||
|
color: #333; |
||||||
|
} |
||||||
|
.btn { |
||||||
|
display: flex; |
||||||
|
justify-content: center; |
||||||
|
align-items: center; |
||||||
|
width: 100%; |
||||||
|
height: 88rpx; |
||||||
|
font-size: 32rpx; |
||||||
|
border-radius: 10rpx; |
||||||
|
image { |
||||||
|
width: 50rpx; |
||||||
|
margin-right: 15rpx; |
||||||
|
} |
||||||
|
} |
||||||
|
.wechat { |
||||||
|
margin-bottom: 38rpx; |
||||||
|
color: #fff; |
||||||
|
background-color: #007EFF; |
||||||
|
} |
||||||
|
.phone { |
||||||
|
color: #007EFF; |
||||||
|
border: 1px solid #007EFF; |
||||||
|
background-color: #fff; |
||||||
|
image { |
||||||
|
width: 40rpx; |
||||||
|
} |
||||||
|
} |
||||||
|
.agree { |
||||||
|
position: absolute; |
||||||
|
bottom: 28rpx; |
||||||
|
left: 0%; |
||||||
|
display: flex; |
||||||
|
justify-content: center; |
||||||
|
align-items: center; |
||||||
|
width: 100%; |
||||||
|
text-align: center; |
||||||
|
font-size: 24rpx; |
||||||
|
color: #ccc; |
||||||
|
text { |
||||||
|
color: #007EFF; |
||||||
|
} |
||||||
|
} |
||||||
|
/deep/.check { |
||||||
|
.checklist-box { |
||||||
|
margin: 0; |
||||||
|
} |
||||||
|
.checkbox__inner { |
||||||
|
width: 40rpx !important; |
||||||
|
height: 40rpx !important; |
||||||
|
border-radius: 50% !important; |
||||||
|
} |
||||||
|
.checkbox__inner-icon { |
||||||
|
top: 8rpx !important; |
||||||
|
left: 14rpx !important; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
</style> |
@ -0,0 +1,62 @@ |
|||||||
|
<template> |
||||||
|
<view class="page"> |
||||||
|
<view class="input"> |
||||||
|
<uni-easyinput type="password" v-model.trim="form.password" placeholder="请输入旧密码"></uni-easyinput> |
||||||
|
</view> |
||||||
|
<view class="input"> |
||||||
|
<uni-easyinput type="password" v-model.trim="form.newPassword" placeholder="请输入新密码"></uni-easyinput> |
||||||
|
</view> |
||||||
|
<view class="input"> |
||||||
|
<uni-easyinput type="password" v-model.trim="form.reNewPassword" placeholder="请再次输入新密码"></uni-easyinput> |
||||||
|
</view> |
||||||
|
<button type="primary" @click="submit">确认</button> |
||||||
|
</view> |
||||||
|
</template> |
||||||
|
|
||||||
|
<script> |
||||||
|
import { examinePassword } from '@/apis/modules/user.js' |
||||||
|
export default { |
||||||
|
data() { |
||||||
|
return { |
||||||
|
form: { |
||||||
|
password: '', |
||||||
|
newPassword: '', |
||||||
|
reNewPassword: '' |
||||||
|
}, |
||||||
|
} |
||||||
|
}, |
||||||
|
methods: { |
||||||
|
submit() { |
||||||
|
const { form } = this |
||||||
|
const { password, newPassword, reNewPassword } = form |
||||||
|
if(!password) return this.$util.errMsg('请输入旧密码') |
||||||
|
if(!newPassword) return this.$util.errMsg('请输入新密码') |
||||||
|
if(!reNewPassword) return this.$util.errMsg('请确认新密码') |
||||||
|
if(newPassword.length < 6 || reNewPassword.length < 6) return this.$util.errMsg('请输入6位数以上的密码') |
||||||
|
if(newPassword !== reNewPassword) return this.$util.errMsg('输入的新密码不一致,请重新确认') |
||||||
|
if(password === newPassword) return this.$util.errMsg('旧密码跟新密码不能一致') |
||||||
|
|
||||||
|
form.accountId = uni.getStorageSync('team').accountId |
||||||
|
examinePassword(form).then(res => { |
||||||
|
this.$util.sucMsg('修改成功!') |
||||||
|
setTimeout(() => { |
||||||
|
uni.navigateBack() |
||||||
|
}, 1000) |
||||||
|
}).catch(e => {}) |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
</script> |
||||||
|
|
||||||
|
<style scoped lang="scss"> |
||||||
|
.page { |
||||||
|
padding: 20px; |
||||||
|
background-color: #fff; |
||||||
|
} |
||||||
|
/deep/.input { |
||||||
|
margin-bottom: 15px; |
||||||
|
.is-input-border { |
||||||
|
border-color: #dedede !important; |
||||||
|
} |
||||||
|
} |
||||||
|
</style> |
@ -0,0 +1,140 @@ |
|||||||
|
<template> |
||||||
|
<view class="page"> |
||||||
|
<image class="bg" src="@/static/image/person-bg.png"></image> |
||||||
|
<view class="wrap"> |
||||||
|
<view class="info"> |
||||||
|
<image class="avatar" :src="avatar" mode=""></image> |
||||||
|
<view class="text"> |
||||||
|
<view class="name">{{ my.info.userName }}</view> |
||||||
|
<view class="phone">{{ my.info.phone }}</view> |
||||||
|
</view> |
||||||
|
</view> |
||||||
|
<view class="list"> |
||||||
|
<view v-if="auth('我的:我的收益')" class="item"> |
||||||
|
<view class="left"> |
||||||
|
<image class="icon" src="@/static/image/person1.png" mode=""></image> |
||||||
|
<text class="name">我的项目收益</text> |
||||||
|
</view> |
||||||
|
<text class="val">{{ my.myIncome}}元</text> |
||||||
|
</view> |
||||||
|
<view v-if="auth('我的:团队收益')" class="item"> |
||||||
|
<view class="left"> |
||||||
|
<image class="icon" src="@/static/image/person2.png" mode=""></image> |
||||||
|
<text class="name">团队收益</text> |
||||||
|
</view> |
||||||
|
<text class="val">{{ my.teamIncome}}元</text> |
||||||
|
</view> |
||||||
|
<view v-if="auth('我的:设置')" class="item" @click="$util.to('../setting/setting')"> |
||||||
|
<view class="left"> |
||||||
|
<image class="icon" src="@/static/image/person3.png" mode=""></image> |
||||||
|
<text class="name">设置</text> |
||||||
|
</view> |
||||||
|
</view> |
||||||
|
</view> |
||||||
|
</view> |
||||||
|
<view v-if="!per" class="per-mask">功能升级中,敬请期待...</view> |
||||||
|
</view> |
||||||
|
</template> |
||||||
|
|
||||||
|
<script> |
||||||
|
import { my } from '@/apis/modules/parner.js' |
||||||
|
export default { |
||||||
|
data() { |
||||||
|
return { |
||||||
|
per: true, // 是否有权限 |
||||||
|
my: { |
||||||
|
info: { |
||||||
|
phone: '' |
||||||
|
}, |
||||||
|
myIncome: 0, |
||||||
|
teamIncome: 0 |
||||||
|
}, |
||||||
|
avatar: uni.getStorageSync('avatar') || '@/static/image/avatar.png', |
||||||
|
userName: uni.getStorageSync('userName') |
||||||
|
} |
||||||
|
}, |
||||||
|
onShow() { |
||||||
|
this.per = true |
||||||
|
this.initRole() |
||||||
|
}, |
||||||
|
methods: { |
||||||
|
// 初始化权限 |
||||||
|
initRole() { |
||||||
|
if (!uni.getStorageSync('auth').includes('我的')) { |
||||||
|
this.per = false |
||||||
|
} else { |
||||||
|
this.getInfo() |
||||||
|
} |
||||||
|
}, |
||||||
|
// 获取个人信息 |
||||||
|
getInfo() { |
||||||
|
const team = uni.getStorageSync('team') |
||||||
|
my({ |
||||||
|
partnerId: team.partnerId, |
||||||
|
teamId: team.teamId |
||||||
|
}).then(({ my }) => { |
||||||
|
this.my = my |
||||||
|
}).catch(e => {}) |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
</script> |
||||||
|
|
||||||
|
<style scoped lang="scss"> |
||||||
|
.bg { |
||||||
|
width: 100%; |
||||||
|
height: 300rpx; |
||||||
|
} |
||||||
|
.wrap { |
||||||
|
position: relative; |
||||||
|
padding: 0 24rpx; |
||||||
|
margin-top: -150rpx; |
||||||
|
} |
||||||
|
.info { |
||||||
|
display: flex; |
||||||
|
align-items: center; |
||||||
|
padding: 26rpx 34rpx; |
||||||
|
background-color: #fff; |
||||||
|
border-radius: 16rpx; |
||||||
|
.avatar { |
||||||
|
width: 120rpx; |
||||||
|
height: 120rpx; |
||||||
|
margin-right: 28rpx; |
||||||
|
border-radius: 50%; |
||||||
|
} |
||||||
|
.name { |
||||||
|
margin-bottom: 10rpx; |
||||||
|
font-size: 40rpx; |
||||||
|
color: #333; |
||||||
|
} |
||||||
|
.phone { |
||||||
|
font-size: 28rpx; |
||||||
|
color: #333; |
||||||
|
} |
||||||
|
} |
||||||
|
.list { |
||||||
|
margin-top: 16rpx; |
||||||
|
.item { |
||||||
|
display: flex; |
||||||
|
justify-content: space-between; |
||||||
|
align-items: center; |
||||||
|
padding: 26rpx 28rpx; |
||||||
|
margin-bottom: 16rpx; |
||||||
|
background-color: #fff; |
||||||
|
border-radius: 16rpx; |
||||||
|
} |
||||||
|
.left { |
||||||
|
display: inline-flex; |
||||||
|
align-items: center; |
||||||
|
} |
||||||
|
.icon { |
||||||
|
width: 48rpx; |
||||||
|
height: 48rpx; |
||||||
|
margin-right: 16rpx; |
||||||
|
} |
||||||
|
text { |
||||||
|
font-size: 28rpx; |
||||||
|
color: #333; |
||||||
|
} |
||||||
|
} |
||||||
|
</style> |
@ -0,0 +1,119 @@ |
|||||||
|
<template> |
||||||
|
<view class="page"> |
||||||
|
<view class="input"> |
||||||
|
<uni-easyinput type="number" v-model="form.phone" placeholder="请填写你的手机号" maxlength="11" :clearable="false" /> |
||||||
|
</view> |
||||||
|
<view class="input code-wrap"> |
||||||
|
<uni-easyinput class="code" type="number" v-model="form.code" placeholder="验证码" maxlength="6" :clearable="false" /> |
||||||
|
<view class="send-code" @click="sendCode" :disabled="codeDisabled">{{ btnText }}</view> |
||||||
|
</view> |
||||||
|
<button type="primary" @click="submit">确认</button> |
||||||
|
</view> |
||||||
|
</template> |
||||||
|
|
||||||
|
<script> |
||||||
|
import { sendPhoneOrEmailCode, changePhoneNumber, checkIfThePhoneNumberExists } from '@/apis/modules/user.js' |
||||||
|
export default { |
||||||
|
data() { |
||||||
|
return { |
||||||
|
userId: '', |
||||||
|
form: { |
||||||
|
phone: '', |
||||||
|
code: '' |
||||||
|
}, |
||||||
|
codeDisabled: false, |
||||||
|
phoneTimer: null, |
||||||
|
phoneOpener: '', |
||||||
|
btnText: '发送验证码', |
||||||
|
} |
||||||
|
}, |
||||||
|
onShow() { |
||||||
|
|
||||||
|
}, |
||||||
|
methods: { |
||||||
|
// 发送验证码 |
||||||
|
sendCode() { |
||||||
|
const { phone } = this.form |
||||||
|
if (!phone) return this.$util.errMsg('请输入手机号') |
||||||
|
if (!/^1[3456789]\d{9}$/.test(phone) && !/^([a-zA-Z]|[0-9])(\w|\-)+@[a-zA-Z0-9]+\.([a-zA-Z]{2,4})$/.test(phone)) return this.$util.errMsg('请输入正确的手机号') |
||||||
|
// 手机号判重 |
||||||
|
checkIfThePhoneNumberExists(phone).then(() => { |
||||||
|
sendPhoneOrEmailCode({ |
||||||
|
userId: this.userId, |
||||||
|
phone, |
||||||
|
types: 2 |
||||||
|
}).then(({ message }) => { |
||||||
|
if (message.opener) { |
||||||
|
this.phoneCountdown() |
||||||
|
this.phoneOpener = message.opener |
||||||
|
} else { |
||||||
|
this.$util.errMsg(message) |
||||||
|
} |
||||||
|
}).catch(res => {}) |
||||||
|
}).catch(res => {}) |
||||||
|
}, |
||||||
|
// 验证码倒计时 |
||||||
|
phoneCountdown() { |
||||||
|
let count = 60 |
||||||
|
if (!this.phoneTimer) { |
||||||
|
this.codeDisabled = true |
||||||
|
this.phoneTimer = setInterval(() => { |
||||||
|
if (count > 0) { |
||||||
|
count-- |
||||||
|
this.btnText = `${count}秒后重试` |
||||||
|
} else { |
||||||
|
this.codeDisabled = false |
||||||
|
clearInterval(this.phoneTimer) |
||||||
|
this.phoneTimer = null |
||||||
|
this.btnText = `发送验证码` |
||||||
|
} |
||||||
|
}, 1000) |
||||||
|
} |
||||||
|
}, |
||||||
|
// 提交 |
||||||
|
submit() { |
||||||
|
const { phone, code } = this.form |
||||||
|
if (!phone) return this.$util.errMsg('请输入手机号') |
||||||
|
if (!code) return this.$util.errMsg('请输入验证码') |
||||||
|
changePhoneNumber(phone, code).then(res => { |
||||||
|
this.$util.sucMsg('修改成功!') |
||||||
|
setTimeout(() => { |
||||||
|
uni.navigateBack() |
||||||
|
}, 1500) |
||||||
|
}).catch(res => {}) |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
</script> |
||||||
|
|
||||||
|
<style scoped lang="scss"> |
||||||
|
.page { |
||||||
|
padding: 20px; |
||||||
|
background-color: #fff; |
||||||
|
} |
||||||
|
/deep/.input { |
||||||
|
margin-bottom: 15px; |
||||||
|
.is-input-border { |
||||||
|
border-color: #dedede !important; |
||||||
|
} |
||||||
|
} |
||||||
|
.input { |
||||||
|
margin-bottom: 20px; |
||||||
|
} |
||||||
|
.code-wrap { |
||||||
|
display: flex; |
||||||
|
} |
||||||
|
.code { |
||||||
|
flex: 1; |
||||||
|
} |
||||||
|
.send-code { |
||||||
|
width: 100px; |
||||||
|
margin-left: 20px; |
||||||
|
text-align: center; |
||||||
|
color: #4386ff; |
||||||
|
font-size: 12px; |
||||||
|
line-height: 36px; |
||||||
|
border: 1px solid #4386ff; |
||||||
|
border-radius: 5px; |
||||||
|
} |
||||||
|
</style> |
@ -0,0 +1,199 @@ |
|||||||
|
<template> |
||||||
|
<view> |
||||||
|
<view class="filter"> |
||||||
|
<uni-search-bar class="search" radius="30" placeholder="请输入方案名称" clearButton="auto" cancelButton="none" @confirm="search" /> |
||||||
|
</view> |
||||||
|
|
||||||
|
<ul class="tab"> |
||||||
|
<li v-for="(tab, i) in tabs" :class="{active: curTab === tab.id}" @click="tabChange(tab)">{{ tab.name }}</li> |
||||||
|
</ul> |
||||||
|
|
||||||
|
<view v-if="list.length" class="list"> |
||||||
|
<view v-for="(item, i) in list" class="item" @click="toDetail(i + 2)"> |
||||||
|
<view class="c-name">{{ item.name }}</view> |
||||||
|
<view class="content"> |
||||||
|
<view class="info"> |
||||||
|
<view class="line"> |
||||||
|
<view class="name">产品:</view> |
||||||
|
<view class="val ell-wrap"> |
||||||
|
<view :class="{ell: !item.toggle}" v-html="item.product"></view> |
||||||
|
<view v-if="item.product.length > 14" class="toggle" @click.stop="toggle(item)">{{ item.toggle ? '收起' : '展开' }}</view> |
||||||
|
</view> |
||||||
|
</view> |
||||||
|
<view class="line"> |
||||||
|
<view class="name">更新日期:</view> |
||||||
|
<view class="val">{{ item.date }}</view> |
||||||
|
</view> |
||||||
|
<view class="line"> |
||||||
|
<view class="name">适用专业:</view> |
||||||
|
<view class="val">{{ item.major }}</view> |
||||||
|
</view> |
||||||
|
</view> |
||||||
|
<view class="detail" @click.stop="toEmail(i)">下载</view> |
||||||
|
</view> |
||||||
|
</view> |
||||||
|
</view> |
||||||
|
<empty v-else></empty> |
||||||
|
</view> |
||||||
|
</template> |
||||||
|
|
||||||
|
<script> |
||||||
|
export default { |
||||||
|
data() { |
||||||
|
return { |
||||||
|
curTab: '', |
||||||
|
tabs: [ |
||||||
|
{ |
||||||
|
name: '不限', |
||||||
|
id: '' |
||||||
|
}, |
||||||
|
{ |
||||||
|
name: '标准方案', |
||||||
|
id: 1 |
||||||
|
}, |
||||||
|
{ |
||||||
|
name: '智信云方案', |
||||||
|
id: 2 |
||||||
|
} |
||||||
|
], |
||||||
|
list: [], |
||||||
|
all: [ |
||||||
|
{ |
||||||
|
type: 1, |
||||||
|
toggle: false, |
||||||
|
name: '人工智能实验室建设方案-2020.1', |
||||||
|
product: `python程序设计实验教学系统<br> |
||||||
|
Docker技术实验教学系统<br> |
||||||
|
JAVA语言程序设计实验教学系统<br> |
||||||
|
大数据开发实验教学系统<br> |
||||||
|
Openstack云计算实验教学系统`, |
||||||
|
date: '2022-06-02', |
||||||
|
major: '人工智能方向' |
||||||
|
}, |
||||||
|
{ |
||||||
|
type: 1, |
||||||
|
toggle: false, |
||||||
|
name: '大数据管理与应用专业建设方案', |
||||||
|
product: `python程序设计实验教学系统<br> |
||||||
|
量化投资实验教学系统<br> |
||||||
|
区块链数字货币交易实验系统<br> |
||||||
|
大数分析实验教学系统<br> |
||||||
|
数据可视化实验教学系统<br> |
||||||
|
大数据实证科研平台<br> |
||||||
|
全球宏观经济<br> |
||||||
|
数据库,全球金融交易数据库 `, |
||||||
|
date: '2022-06-02', |
||||||
|
major: '大数据方向' |
||||||
|
}, |
||||||
|
{ |
||||||
|
type: 1, |
||||||
|
toggle: false, |
||||||
|
name: '金融科技实验室建设方案V2.0', |
||||||
|
product: `python程序设计实验教学系统<br> |
||||||
|
量化投资实验教学系统<br> |
||||||
|
区块链数字货币交易实验教学系统<br> |
||||||
|
大数据采集实验教学系统<br> |
||||||
|
大数据分析实验教学系统<br> |
||||||
|
金融建模实验教学系统<br> |
||||||
|
互联网小贷实验教学系统<br> |
||||||
|
互联网支付实验教学系统<br> |
||||||
|
R语言实验教学系统<br> |
||||||
|
供应链金融实验教学系统<br> |
||||||
|
Python数据清洗实验教学系统<br> |
||||||
|
数据可视化实验教学系统<br> |
||||||
|
金融随机过程实验教学系统<br> |
||||||
|
银行综合系统<br> |
||||||
|
大数据实证科研平台<br> |
||||||
|
财经数据库`, |
||||||
|
date: '2022-06-02', |
||||||
|
major: '金融科技,大数据方向' |
||||||
|
} |
||||||
|
] |
||||||
|
} |
||||||
|
}, |
||||||
|
onShow() { |
||||||
|
this.list = JSON.parse(JSON.stringify(this.all)) |
||||||
|
}, |
||||||
|
methods: { |
||||||
|
search(res) { |
||||||
|
uni.showToast({ |
||||||
|
title: '搜索:' + res.value, |
||||||
|
icon: 'none' |
||||||
|
}) |
||||||
|
}, |
||||||
|
// tab切换 |
||||||
|
tabChange(tab) { |
||||||
|
const { id } = tab |
||||||
|
const { all } = this |
||||||
|
this.curTab = id |
||||||
|
this.list = id ? all.filter(e => e.type === id) : all |
||||||
|
}, |
||||||
|
// 跳转详情 |
||||||
|
toDetail(id) { |
||||||
|
this.$util.openFile(id) |
||||||
|
}, |
||||||
|
// 发送邮箱 |
||||||
|
toEmail(id) { |
||||||
|
this.$util.to(`../send/send?id=${id}`) |
||||||
|
}, |
||||||
|
// 展开 |
||||||
|
toggle(item) { |
||||||
|
item.toggle = !item.toggle |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
</script> |
||||||
|
|
||||||
|
<style scoped lang="scss"> |
||||||
|
.list { |
||||||
|
background-color: #fff; |
||||||
|
.item { |
||||||
|
padding: 20rpx 40rpx; |
||||||
|
border-bottom: 1px solid #f1f1f1; |
||||||
|
} |
||||||
|
.c-name { |
||||||
|
font-size: 30rpx; |
||||||
|
color: #333; |
||||||
|
} |
||||||
|
.line { |
||||||
|
display: flex; |
||||||
|
padding: 10rpx 0; |
||||||
|
} |
||||||
|
.content { |
||||||
|
display: flex; |
||||||
|
justify-content: space-between; |
||||||
|
align-items: center; |
||||||
|
margin-top: 20rpx; |
||||||
|
} |
||||||
|
.name { |
||||||
|
width: 140rpx; |
||||||
|
margin-right: 10rpx; |
||||||
|
white-space: nowrap; |
||||||
|
font-size: 28rpx; |
||||||
|
color: #999; |
||||||
|
} |
||||||
|
.val { |
||||||
|
max-width: 88%; |
||||||
|
font-size: 28rpx; |
||||||
|
color: #333; |
||||||
|
} |
||||||
|
.ell { |
||||||
|
height: 38rpx; |
||||||
|
white-space: nowrap; |
||||||
|
text-overflow: ellipsis; |
||||||
|
overflow: hidden; |
||||||
|
} |
||||||
|
.toggle { |
||||||
|
margin-top: 10rpx; |
||||||
|
white-space: nowrap; |
||||||
|
font-size: 24rpx; |
||||||
|
color: #0e92ef; |
||||||
|
} |
||||||
|
.detail { |
||||||
|
margin-left: 20rpx; |
||||||
|
font-size: 26rpx; |
||||||
|
color: #1f83ff; |
||||||
|
white-space: nowrap; |
||||||
|
} |
||||||
|
} |
||||||
|
</style> |
@ -0,0 +1,217 @@ |
|||||||
|
<template> |
||||||
|
<view> |
||||||
|
<view class="filter"> |
||||||
|
<uni-search-bar class="search" radius="30" placeholder="请输入产品名称" v-model="keyword" clearButton="auto" cancelButton="none" /> |
||||||
|
<view :class="['sort', sort]" @click="switchSort"></view> |
||||||
|
</view> |
||||||
|
|
||||||
|
<ul class="tab"> |
||||||
|
<li v-for="(tab, i) in tabs" :class="{active: curTab === tab.id}" @click="tabChange(tab)">{{ tab.name }}</li> |
||||||
|
</ul> |
||||||
|
|
||||||
|
<ul class="list"> |
||||||
|
<li v-for="item in list"> |
||||||
|
<view class="pro-name"> |
||||||
|
<image class="icon" :src="$util.getIcon(item)" mode="widthFix"></image> |
||||||
|
{{ item.productName }} |
||||||
|
</view> |
||||||
|
<view class="info"> |
||||||
|
<view class="line"> |
||||||
|
<text class="name">产品简介:</text> |
||||||
|
<view class="val ell-wrap"> |
||||||
|
<view :class="{ell: !item.toggle}">{{ item.briefIntroduction }}</view> |
||||||
|
<view class="toggle" @click="toggle(item)">{{ item.toggle ? '收起' : '展开' }}</view> |
||||||
|
</view> |
||||||
|
</view> |
||||||
|
<view class="line"> |
||||||
|
<text class="name">产品类型:</text> |
||||||
|
<text class="val">{{ tabs.find(e => e.id === item.productType).name }}</text> |
||||||
|
</view> |
||||||
|
<view class="line"> |
||||||
|
<text class="name">市场单价:</text> |
||||||
|
<text class="val">{{ item.marketPrice }}元/年</text> |
||||||
|
</view> |
||||||
|
<view class="line"> |
||||||
|
<text class="name">结算方式:</text> |
||||||
|
<text class="val">{{ item.settlementMethod ? '比例分成' : '结算单价' }}</text> |
||||||
|
</view> |
||||||
|
<view class="line"> |
||||||
|
<text class="name">供应厂商:</text> |
||||||
|
<text class="val">{{ item.supplier }}</text> |
||||||
|
</view> |
||||||
|
</view> |
||||||
|
</li> |
||||||
|
</ul> |
||||||
|
<uni-load-more :status="status" /> |
||||||
|
</view> |
||||||
|
</template> |
||||||
|
|
||||||
|
<script> |
||||||
|
import { AppletsDataProductList } from '@/apis/modules/product.js' |
||||||
|
export default { |
||||||
|
data() { |
||||||
|
return { |
||||||
|
curTab: '', |
||||||
|
tabs: [ |
||||||
|
{ |
||||||
|
name: '全部', |
||||||
|
id: '' |
||||||
|
}, |
||||||
|
{ |
||||||
|
name: '实训课程', |
||||||
|
id: 1 |
||||||
|
}, |
||||||
|
{ |
||||||
|
name: '理论课程', |
||||||
|
id: 0 |
||||||
|
}, |
||||||
|
{ |
||||||
|
name: '数据产品', |
||||||
|
id: 2 |
||||||
|
} |
||||||
|
], |
||||||
|
reachBottom: 0, // 是否是上拉加载。0->否,1->是,-1->加载完所有数据 |
||||||
|
status: 'more', // 上拉加载状态 more|loading|noMore |
||||||
|
searchTimer: null, |
||||||
|
sort: 'desc', |
||||||
|
keyword: '', |
||||||
|
list: [], |
||||||
|
page: 1, |
||||||
|
pageSize: 10 |
||||||
|
} |
||||||
|
}, |
||||||
|
watch: { |
||||||
|
keyword () { |
||||||
|
clearTimeout(this.searchTimer) |
||||||
|
this.searchTimer = setTimeout(() => { |
||||||
|
this.initList() |
||||||
|
}, 500) |
||||||
|
} |
||||||
|
}, |
||||||
|
// 下拉刷新 |
||||||
|
onPullDownRefresh() { |
||||||
|
this.initList() |
||||||
|
setTimeout(() => { |
||||||
|
uni.stopPullDownRefresh() |
||||||
|
}, 1500) |
||||||
|
}, |
||||||
|
// 上拉加载 |
||||||
|
onReachBottom() { |
||||||
|
if (this.reachBottom >= 0) { |
||||||
|
this.reachBottom = 1 |
||||||
|
this.status = 'loading' |
||||||
|
this.getList() |
||||||
|
} |
||||||
|
}, |
||||||
|
onShow() { |
||||||
|
this.initList() |
||||||
|
}, |
||||||
|
methods: { |
||||||
|
getList() { |
||||||
|
AppletsDataProductList({ |
||||||
|
sort: this.sort, |
||||||
|
keywords: this.keyword, |
||||||
|
productType: this.curTab, |
||||||
|
pageNum: this.page, |
||||||
|
pageSize: this.pageSize |
||||||
|
}).then(({ data }) => { |
||||||
|
// 未加载完所有数据,并且不是筛选,则拼接list,否则直接赋值 |
||||||
|
const list = data.records |
||||||
|
list.map(e => { |
||||||
|
e.toggle = e.briefIntroduction.length < 14 // 超过了14个字才需要显示展开按钮 |
||||||
|
}) |
||||||
|
this.list = this.reachBottom > 0 ? [...this.list, ...list] : list |
||||||
|
this.page++ // 每次获取了数据后page+1 |
||||||
|
const noMore = this.list.length === data.total // 是否加载完所有数据 |
||||||
|
this.status = noMore ? 'noMore' : 'more' // 加载完了则设置为noMore |
||||||
|
this.reachBottom = noMore ? -1 : 0 // 加载完了则设置为-1 |
||||||
|
}).catch(e => {}) |
||||||
|
}, |
||||||
|
initList() { |
||||||
|
this.page = 1 |
||||||
|
this.reachBottom = 0 |
||||||
|
this.getList() |
||||||
|
}, |
||||||
|
// 展开 |
||||||
|
toggle(item) { |
||||||
|
item.toggle = !item.toggle |
||||||
|
}, |
||||||
|
// 排序 |
||||||
|
switchSort() { |
||||||
|
this.sort = this.sort === 'desc' ? 'asc' : 'desc' |
||||||
|
this.initList() |
||||||
|
}, |
||||||
|
// tab切换 |
||||||
|
tabChange(tab) { |
||||||
|
this.curTab = tab.id |
||||||
|
this.initList() |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
</script> |
||||||
|
|
||||||
|
<style scoped lang="scss"> |
||||||
|
.filter { |
||||||
|
display: flex; |
||||||
|
align-items: center; |
||||||
|
.search { |
||||||
|
flex: 1; |
||||||
|
} |
||||||
|
.sl-filter { |
||||||
|
width: 30%; |
||||||
|
margin-left: 10%; |
||||||
|
} |
||||||
|
} |
||||||
|
.list { |
||||||
|
li { |
||||||
|
padding: 0 24rpx; |
||||||
|
margin: 16rpx 24rpx; |
||||||
|
background-color: #fff; |
||||||
|
border-radius: 16rpx; |
||||||
|
} |
||||||
|
.pro-name { |
||||||
|
display: flex; |
||||||
|
align-items: center; |
||||||
|
padding: 18rpx 0; |
||||||
|
font-size: 30rpx; |
||||||
|
color: #333; |
||||||
|
border-bottom: 1px solid #E6E8ED; |
||||||
|
.icon { |
||||||
|
width: 52rpx; |
||||||
|
margin-right: 20rpx; |
||||||
|
} |
||||||
|
} |
||||||
|
.info { |
||||||
|
padding: 12rpx 0; |
||||||
|
} |
||||||
|
.line { |
||||||
|
display: flex; |
||||||
|
padding: 12rpx 0; |
||||||
|
} |
||||||
|
.name { |
||||||
|
margin-right: 10rpx; |
||||||
|
font-size: 28rpx; |
||||||
|
color: #999; |
||||||
|
} |
||||||
|
.val { |
||||||
|
max-width: 70%; |
||||||
|
font-size: 28rpx; |
||||||
|
color: #333; |
||||||
|
} |
||||||
|
.ell-wrap { |
||||||
|
display: inline-flex; |
||||||
|
align-items: center; |
||||||
|
} |
||||||
|
.ell { |
||||||
|
white-space: nowrap; |
||||||
|
text-overflow: ellipsis; |
||||||
|
overflow: hidden; |
||||||
|
} |
||||||
|
.toggle { |
||||||
|
margin-left: 10rpx; |
||||||
|
white-space: nowrap; |
||||||
|
font-size: 24rpx; |
||||||
|
color: #0e92ef; |
||||||
|
} |
||||||
|
} |
||||||
|
</style> |
@ -0,0 +1,108 @@ |
|||||||
|
<template> |
||||||
|
<view class="page"> |
||||||
|
<view class="wrap"> |
||||||
|
<view class="inner"> |
||||||
|
<view class="info"> |
||||||
|
<image class="avatar" :src="avatar" mode=""></image> |
||||||
|
<view class="text"> |
||||||
|
<view class="invite"> |
||||||
|
<text class="name">{{ userName }}</text> 邀请你加入城市合伙人计划 |
||||||
|
</view> |
||||||
|
</view> |
||||||
|
</view> |
||||||
|
<view class="com">{{ team.partnerClassificationName }}</view> |
||||||
|
<u-qrcode ref="qrcode" canvas-id="qrcode" :size="size" :value="link"></u-qrcode> |
||||||
|
<view class="tips">扫一扫,加入我们吧</view> |
||||||
|
</view> |
||||||
|
<view class="warn">邀请二维码失效日期:{{ expireTime }}</view> |
||||||
|
</view> |
||||||
|
</view> |
||||||
|
</template> |
||||||
|
|
||||||
|
<script> |
||||||
|
import { generateInvitationCode } from '@/apis/modules/parner.js' |
||||||
|
export default { |
||||||
|
data() { |
||||||
|
return { |
||||||
|
avatar: uni.getStorageSync('avatar') || '@/static/image/avatar.png', |
||||||
|
userName: uni.getStorageSync('userName'), |
||||||
|
expireTime: '', |
||||||
|
qrcode: '', |
||||||
|
link: '', |
||||||
|
size: uni.upx2px(420), |
||||||
|
team: uni.getStorageSync('team') |
||||||
|
} |
||||||
|
}, |
||||||
|
onShow() { |
||||||
|
this.getQrcode() |
||||||
|
}, |
||||||
|
methods: { |
||||||
|
// 生成二维码 |
||||||
|
getQrcode() { |
||||||
|
const { team } = this |
||||||
|
// 生成邀请码 |
||||||
|
generateInvitationCode(uni.getStorageSync('team').accountId).then(({ expireTime }) => { |
||||||
|
const date = new Date(Date.now() + expireTime * 1000) // 返回的秒,要*1000 |
||||||
|
this.expireTime = `${date.getFullYear()}-${this.$util.preZero(date.getMonth() + 1)}-${this.$util.preZero(date.getDate())} ${this.$util.preZero(date.getHours())}:${this.$util.preZero(date.getMinutes())}:${this.$util.preZero(date.getMinutes())}` |
||||||
|
const team = this.team |
||||||
|
this.link = `https://huorantech.cn/#/join?accountId=${team.accountId}&id=${team.teamId}&isTeam=0` |
||||||
|
// this.link = `http://192.168.31.125:8086/#/join?accountId=${team.accountId}&id=${team.teamId}&isTeam=0` |
||||||
|
}).catch(e => {}) |
||||||
|
}, |
||||||
|
} |
||||||
|
} |
||||||
|
</script> |
||||||
|
|
||||||
|
<style scoped lang="scss"> |
||||||
|
.page { |
||||||
|
display: flex; |
||||||
|
justify-content: center; |
||||||
|
align-items: center; |
||||||
|
height: 100%; |
||||||
|
overflow: hidden; |
||||||
|
} |
||||||
|
.wrap { |
||||||
|
padding-bottom: 40rpx; |
||||||
|
text-align: center; |
||||||
|
background-color: #fff; |
||||||
|
.inner { |
||||||
|
display: flex; |
||||||
|
flex-direction: column; |
||||||
|
justify-content: center; |
||||||
|
align-items: center; |
||||||
|
padding: 40rpx 80rpx 0; |
||||||
|
} |
||||||
|
.info { |
||||||
|
display: flex; |
||||||
|
align-items: center; |
||||||
|
text-align: left; |
||||||
|
} |
||||||
|
.avatar { |
||||||
|
width: 80rpx; |
||||||
|
height: 80rpx; |
||||||
|
margin-right: 20rpx; |
||||||
|
border-radius: 50%; |
||||||
|
} |
||||||
|
.invite { |
||||||
|
font-size: 26rpx; |
||||||
|
} |
||||||
|
.name { |
||||||
|
margin-right: 5rpx; |
||||||
|
font-size: 30rpx; |
||||||
|
color: $uni-primary; |
||||||
|
} |
||||||
|
.com { |
||||||
|
margin: 20rpx 0; |
||||||
|
font-size: 30rpx; |
||||||
|
} |
||||||
|
.tips { |
||||||
|
margin: 30rpx 0 20rpx; |
||||||
|
font-size: 24rpx; |
||||||
|
color: #333; |
||||||
|
} |
||||||
|
.warn { |
||||||
|
font-size: 24rpx; |
||||||
|
color: #f00; |
||||||
|
} |
||||||
|
} |
||||||
|
</style> |
@ -0,0 +1,105 @@ |
|||||||
|
<template> |
||||||
|
<view class="container"> |
||||||
|
<uni-card :is-shadow="false" :border="false" padding="0" is-full> |
||||||
|
<view class="form"> |
||||||
|
<view class="line"> |
||||||
|
<uni-data-checkbox v-model="myVal" :localdata="checkList" @change="myChange"></uni-data-checkbox> |
||||||
|
<text>我的邮箱</text> |
||||||
|
<uni-easyinput v-model="email" disabled /> |
||||||
|
<view class="bind" @click="$util.to('../email/email')">绑定</view> |
||||||
|
</view> |
||||||
|
<view class="line"> |
||||||
|
<uni-data-checkbox v-model="otherVal" :localdata="checkList" @change="otherChange"></uni-data-checkbox> |
||||||
|
<text>其他邮箱</text> |
||||||
|
<uni-easyinput v-model="otherEmail" placeholder="请输入其他邮箱" /> |
||||||
|
</view> |
||||||
|
<button type="primary" @click="submit">确认</button> |
||||||
|
</view> |
||||||
|
</uni-card> |
||||||
|
</view> |
||||||
|
</template> |
||||||
|
|
||||||
|
<script> |
||||||
|
import { mailFileSend } from '@/apis/modules/parner.js' |
||||||
|
import { my } from '@/apis/modules/parner.js' |
||||||
|
export default { |
||||||
|
data() { |
||||||
|
return { |
||||||
|
id: '', |
||||||
|
email: '', |
||||||
|
otherEmail: '', |
||||||
|
myVal: 1, |
||||||
|
otherVal: '', |
||||||
|
checkList: [{ |
||||||
|
text: '', |
||||||
|
value: 1 |
||||||
|
}], |
||||||
|
files: [ |
||||||
|
'人工智能实验室建设方案-2020.1.docx', |
||||||
|
'大数据管理与应用专业建设方案.docx', |
||||||
|
'金融科技实验室建设方案V2.0.docx' |
||||||
|
] |
||||||
|
} |
||||||
|
}, |
||||||
|
onShow() { |
||||||
|
const pages = getCurrentPages() |
||||||
|
const { options } = pages[pages.length - 1] |
||||||
|
this.id = options.id |
||||||
|
this.getInfo() |
||||||
|
}, |
||||||
|
methods: { |
||||||
|
// 获取个人信息 |
||||||
|
getInfo() { |
||||||
|
const team = uni.getStorageSync('team') |
||||||
|
my({ |
||||||
|
partnerId: team.partnerId, |
||||||
|
teamId: team.teamId |
||||||
|
}).then(({ my }) => { |
||||||
|
this.email = my.info.email |
||||||
|
}).catch(e => {}) |
||||||
|
}, |
||||||
|
myChange(e) { |
||||||
|
this.otherVal = '' |
||||||
|
}, |
||||||
|
otherChange(e) { |
||||||
|
this.myVal = '' |
||||||
|
}, |
||||||
|
// 提交 |
||||||
|
submit() { |
||||||
|
const { otherEmail } = this |
||||||
|
if (this.myVal && !this.email) return this.$util.errMsg('请选择其他邮箱!') |
||||||
|
if (this.otherVal && !otherEmail) return this.$util.errMsg('请输入邮箱!') |
||||||
|
mailFileSend({ |
||||||
|
copyWriting: this.files[this.id], |
||||||
|
mail: this.myVal ? this.email : otherEmail |
||||||
|
}).then(res => { |
||||||
|
this.$util.sucMsg('发送成功!') |
||||||
|
setTimeout(() => { |
||||||
|
uni.navigateBack() |
||||||
|
}, 1000) |
||||||
|
}).catch(e => {}) |
||||||
|
}, |
||||||
|
} |
||||||
|
} |
||||||
|
</script> |
||||||
|
|
||||||
|
<style scoped lang="scss"> |
||||||
|
.form { |
||||||
|
padding: 15px; |
||||||
|
background-color: #fff; |
||||||
|
} |
||||||
|
.line { |
||||||
|
display: flex; |
||||||
|
align-items: center; |
||||||
|
margin-bottom: 15px; |
||||||
|
text { |
||||||
|
margin: 0 10px 0 -20px; |
||||||
|
} |
||||||
|
} |
||||||
|
.bind { |
||||||
|
margin-left: 20rpx; |
||||||
|
font-size: 26rpx; |
||||||
|
color: #1f83ff; |
||||||
|
white-space: nowrap; |
||||||
|
} |
||||||
|
</style> |
@ -0,0 +1,90 @@ |
|||||||
|
<template> |
||||||
|
<view> |
||||||
|
<uni-list> |
||||||
|
<uni-list-item :show-extra-icon="true" showArrow :extra-icon="phoneIcon" title="手机号" :rightText="info.phone" clickable @click="toPage('../phone/phone')" /> |
||||||
|
<uni-list-item :show-extra-icon="true" showArrow :extra-icon="mailIcon" title="邮箱" :rightText="info.email" clickable @click="toPage('../email/email')" /> |
||||||
|
<uni-list-item :show-extra-icon="true" showArrow :extra-icon="accountIcon" title="账号" :rightText="info.account" clickable @click="toPage('../account/account')" /> |
||||||
|
<uni-list-item :show-extra-icon="true" showArrow :extra-icon="pwdIcon" title="密码" rightText="******" clickable @click="toPage('../password/password')" /> |
||||||
|
</uni-list> |
||||||
|
|
||||||
|
<view v-if="auth('我的:退出账号')" class="logout" @click="logout">退出登录</view> |
||||||
|
</view> |
||||||
|
</template> |
||||||
|
|
||||||
|
<script> |
||||||
|
import { my } from '@/apis/modules/parner.js' |
||||||
|
export default { |
||||||
|
data() { |
||||||
|
return { |
||||||
|
phoneIcon: { |
||||||
|
color: '#007eff', |
||||||
|
size: '22', |
||||||
|
type: 'phone' |
||||||
|
}, |
||||||
|
mailIcon: { |
||||||
|
color: '#007eff', |
||||||
|
size: '22', |
||||||
|
type: 'email' |
||||||
|
}, |
||||||
|
accountIcon: { |
||||||
|
color: '#007eff', |
||||||
|
size: '22', |
||||||
|
type: 'person' |
||||||
|
}, |
||||||
|
pwdIcon: { |
||||||
|
color: '#007eff', |
||||||
|
size: '22', |
||||||
|
type: 'locked' |
||||||
|
}, |
||||||
|
info: { |
||||||
|
account: '', |
||||||
|
phone: '', |
||||||
|
email: '' |
||||||
|
} |
||||||
|
} |
||||||
|
}, |
||||||
|
onShow() { |
||||||
|
this.getInfo() |
||||||
|
}, |
||||||
|
methods: { |
||||||
|
// 获取个人信息 |
||||||
|
getInfo() { |
||||||
|
const team = uni.getStorageSync('team') |
||||||
|
my({ |
||||||
|
partnerId: team.partnerId, |
||||||
|
teamId: team.teamId |
||||||
|
}).then(({ my }) => { |
||||||
|
this.info = my.info |
||||||
|
}).catch(e => {}) |
||||||
|
}, |
||||||
|
toPage(path) { |
||||||
|
this.$util.to(path) |
||||||
|
}, |
||||||
|
// 退出登录 |
||||||
|
logout() { |
||||||
|
const that = this |
||||||
|
uni.showModal({ |
||||||
|
title: '提示', |
||||||
|
content: '确定要退出账号吗?', |
||||||
|
success(res) { |
||||||
|
if (res.confirm) { |
||||||
|
uni.clearStorageSync() |
||||||
|
that.$util.to('../login/login') |
||||||
|
} |
||||||
|
} |
||||||
|
}) |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
</script> |
||||||
|
|
||||||
|
<style scoped lang="scss"> |
||||||
|
.logout { |
||||||
|
padding: 30rpx 0; |
||||||
|
margin-top: 30rpx; |
||||||
|
font-size: 28rpx; |
||||||
|
color: #333; |
||||||
|
text-align: center; |
||||||
|
background-color: #fff; |
||||||
|
} |
||||||
|
</style> |
@ -0,0 +1,162 @@ |
|||||||
|
<template> |
||||||
|
<view> |
||||||
|
<uni-card :is-shadow="false" :border="false" is-full spacing="0" margin="20"> |
||||||
|
<uni-search-bar class="search" radius="30" placeholder="请输入成员名称" clearButton="auto" cancelButton="none" v-model="keyword" /> |
||||||
|
</uni-card> |
||||||
|
|
||||||
|
<template v-if="list.length"> |
||||||
|
<ul class="list"> |
||||||
|
<li v-for="item in list"> |
||||||
|
<image class="avatar" :src="item.userAvatars || require('@/static/image/avatar.png')" mode=""></image> |
||||||
|
<view class="info"> |
||||||
|
<view class="c-name">{{ item.userName }}</view> |
||||||
|
<view class="line"> |
||||||
|
<text class="name">手机号码:</text> |
||||||
|
<text class="val">{{ item.phone }}</text> |
||||||
|
</view> |
||||||
|
<view class="line"> |
||||||
|
<text class="name">加入时间:</text> |
||||||
|
<text class="val">{{ item.lastLoginTime.split(' ')[0] }}</text> |
||||||
|
</view> |
||||||
|
</view> |
||||||
|
</li> |
||||||
|
</ul> |
||||||
|
<uni-load-more :status="status" /> |
||||||
|
</template> |
||||||
|
<empty v-else></empty> |
||||||
|
|
||||||
|
<uni-icons v-if="auth('团队:邀请成员')" class="plus" type="plus-filled" size="60" color="#007eff" @click="$util.to('../addStaff/addStaff')"></uni-icons> |
||||||
|
<view v-if="!per" class="per-mask">功能升级中,敬请期待...</view> |
||||||
|
</view> |
||||||
|
</template> |
||||||
|
|
||||||
|
<script> |
||||||
|
import { teamList } from '@/apis/modules/parner.js' |
||||||
|
export default { |
||||||
|
data() { |
||||||
|
return { |
||||||
|
per: true, // 是否有权限 |
||||||
|
reachBottom: 0, // 是否是上拉加载。0->否,1->是,-1->加载完所有数据 |
||||||
|
status: 'more', // 上拉加载状态 more|loading|noMore |
||||||
|
searchTimer: null, |
||||||
|
keyword: '', |
||||||
|
list: [], |
||||||
|
page: 1, |
||||||
|
pageSize: 10 |
||||||
|
} |
||||||
|
}, |
||||||
|
watch: { |
||||||
|
keyword () { |
||||||
|
clearTimeout(this.searchTimer) |
||||||
|
this.searchTimer = setTimeout(() => { |
||||||
|
this.initList() |
||||||
|
}, 500) |
||||||
|
} |
||||||
|
}, |
||||||
|
// 下拉刷新 |
||||||
|
onPullDownRefresh() { |
||||||
|
this.initList() |
||||||
|
setTimeout(() => { |
||||||
|
uni.stopPullDownRefresh() |
||||||
|
}, 1500) |
||||||
|
}, |
||||||
|
// 上拉加载 |
||||||
|
onReachBottom() { |
||||||
|
if (this.reachBottom >= 0) { |
||||||
|
this.reachBottom = 1 |
||||||
|
this.status = 'loading' |
||||||
|
this.getList() |
||||||
|
} |
||||||
|
}, |
||||||
|
onShow() { |
||||||
|
this.per = true |
||||||
|
this.initRole() |
||||||
|
}, |
||||||
|
methods: { |
||||||
|
// 初始化权限 |
||||||
|
initRole() { |
||||||
|
const auth = uni.getStorageSync('auth') |
||||||
|
if (!auth.includes('团队')) { |
||||||
|
this.per = false |
||||||
|
} else if (auth.includes('团队:团队列表')) { |
||||||
|
this.initList() |
||||||
|
} |
||||||
|
}, |
||||||
|
// 获取列表 |
||||||
|
getList() { |
||||||
|
uni.showLoading({ |
||||||
|
title: '加载中' |
||||||
|
}) |
||||||
|
teamList({ |
||||||
|
type: 1, |
||||||
|
pageNum: this.page, |
||||||
|
pageSize: this.pageSize, |
||||||
|
keyWord: this.keyword, |
||||||
|
partnerClassificationId: uni.getStorageSync('team').teamId |
||||||
|
}).then(({ pageList }) => { |
||||||
|
uni.hideLoading() |
||||||
|
const { records } = pageList |
||||||
|
// 未加载完所有数据,并且不是筛选,则拼接list,否则直接赋值 |
||||||
|
this.list = this.reachBottom > 0 ? [...this.list, ...records] : records |
||||||
|
this.page++ // 每次获取了数据后page+1 |
||||||
|
const noMore = this.list.length === pageList.total // 是否加载完所有数据 |
||||||
|
this.status = noMore ? 'noMore' : 'more' // 加载完了则设置为noMore |
||||||
|
this.reachBottom = noMore ? -1 : 0 // 加载完了则设置为-1 |
||||||
|
}).catch(e => { |
||||||
|
uni.hideLoading() |
||||||
|
}) |
||||||
|
}, |
||||||
|
initList() { |
||||||
|
this.page = 1 |
||||||
|
this.reachBottom = 0 |
||||||
|
this.getList() |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
</script> |
||||||
|
|
||||||
|
<style scoped lang="scss"> |
||||||
|
.list { |
||||||
|
margin-top: 20rpx; |
||||||
|
background-color: #fff; |
||||||
|
li { |
||||||
|
display: flex; |
||||||
|
align-items: center; |
||||||
|
padding: 20rpx 40rpx; |
||||||
|
border-bottom: 1px solid #f7f7f7; |
||||||
|
&:last-child { |
||||||
|
border-bottom: 0; |
||||||
|
} |
||||||
|
} |
||||||
|
.avatar { |
||||||
|
width: 100rpx; |
||||||
|
height: 100rpx; |
||||||
|
margin-right: 30rpx; |
||||||
|
border-radius: 50%; |
||||||
|
} |
||||||
|
.c-name { |
||||||
|
margin-bottom: 6rpx; |
||||||
|
font-size: 30rpx; |
||||||
|
color: #333; |
||||||
|
} |
||||||
|
.line { |
||||||
|
display: flex; |
||||||
|
padding: 2rpx 0; |
||||||
|
} |
||||||
|
.name { |
||||||
|
margin-right: 10rpx; |
||||||
|
white-space: nowrap; |
||||||
|
font-size: 28rpx; |
||||||
|
color: #999; |
||||||
|
} |
||||||
|
.val { |
||||||
|
font-size: 28rpx; |
||||||
|
color: #333; |
||||||
|
} |
||||||
|
} |
||||||
|
.plus { |
||||||
|
position: fixed; |
||||||
|
bottom: 40rpx; |
||||||
|
right: 40rpx; |
||||||
|
} |
||||||
|
</style> |
@ -0,0 +1,32 @@ |
|||||||
|
@font-face { |
||||||
|
font-family: "iconfont";
src: url('/static/iconfont/iconfont.ttf') format('truetype'); |
||||||
|
} |
||||||
|
|
||||||
|
.iconfont { |
||||||
|
font-family: "iconfont" !important; |
||||||
|
font-size: 16px; |
||||||
|
font-style: normal; |
||||||
|
-webkit-font-smoothing: antialiased; |
||||||
|
-moz-osx-font-smoothing: grayscale; |
||||||
|
} |
||||||
|
|
||||||
|
.icon-qrcode:before { |
||||||
|
content: "\e7dd"; |
||||||
|
} |
||||||
|
|
||||||
|
.icon-dingdan:before { |
||||||
|
content: "\e601"; |
||||||
|
} |
||||||
|
|
||||||
|
.icon-product:before { |
||||||
|
content: "\e788"; |
||||||
|
} |
||||||
|
|
||||||
|
.icon-edit:before { |
||||||
|
content: "\e621"; |
||||||
|
} |
||||||
|
|
||||||
|
.icon-filter:before { |
||||||
|
content: "\e6b9"; |
||||||
|
} |
||||||
|
|
After Width: | Height: | Size: 257 B |
After Width: | Height: | Size: 1.4 KiB |
After Width: | Height: | Size: 38 KiB |
After Width: | Height: | Size: 230 B |
After Width: | Height: | Size: 72 KiB |
After Width: | Height: | Size: 1.0 KiB |
After Width: | Height: | Size: 840 B |
After Width: | Height: | Size: 319 B |
After Width: | Height: | Size: 727 B |
After Width: | Height: | Size: 295 B |
After Width: | Height: | Size: 844 B |
After Width: | Height: | Size: 672 B |
After Width: | Height: | Size: 11 KiB |
After Width: | Height: | Size: 5.0 KiB |
After Width: | Height: | Size: 4.7 KiB |
After Width: | Height: | Size: 7.7 KiB |
After Width: | Height: | Size: 30 KiB |
After Width: | Height: | Size: 572 B |
After Width: | Height: | Size: 654 B |
After Width: | Height: | Size: 557 B |
After Width: | Height: | Size: 1.4 KiB |
After Width: | Height: | Size: 313 B |
After Width: | Height: | Size: 325 B |
After Width: | Height: | Size: 296 B |
After Width: | Height: | Size: 604 B |
After Width: | Height: | Size: 645 B |
After Width: | Height: | Size: 859 B |
After Width: | Height: | Size: 784 B |
After Width: | Height: | Size: 680 B |
After Width: | Height: | Size: 627 B |
After Width: | Height: | Size: 416 B |
After Width: | Height: | Size: 552 B |
@ -0,0 +1,221 @@ |
|||||||
|
button[type=primary] { |
||||||
|
background-color: #007eff; |
||||||
|
} |
||||||
|
page { |
||||||
|
height: 100%; |
||||||
|
background-color: #f5f5f5; |
||||||
|
} |
||||||
|
ul { |
||||||
|
padding-left: 0; |
||||||
|
li { |
||||||
|
list-style: none; |
||||||
|
} |
||||||
|
} |
||||||
|
.block { |
||||||
|
padding: 0 24rpx; |
||||||
|
margin: 20rpx 24rpx; |
||||||
|
border-radius: 16rpx; |
||||||
|
background-color: #fff; |
||||||
|
} |
||||||
|
.l-title { |
||||||
|
display: flex; |
||||||
|
align-items: center; |
||||||
|
padding: 28rpx 0; |
||||||
|
font-size: 28rpx; |
||||||
|
color: #333; |
||||||
|
&:before { |
||||||
|
content: ''; |
||||||
|
width: 6rpx; |
||||||
|
height: 28rpx; |
||||||
|
margin-right: 12rpx; |
||||||
|
vertical-align: middle; |
||||||
|
background-color: #4876F9; |
||||||
|
} |
||||||
|
} |
||||||
|
.filter { |
||||||
|
display: flex; |
||||||
|
align-items: center; |
||||||
|
padding: 10rpx 30rpx 10rpx 10rpx; |
||||||
|
background-color: #fff; |
||||||
|
.search { |
||||||
|
flex: 1; |
||||||
|
} |
||||||
|
.uni-searchbar__box { |
||||||
|
height: 70rpx; |
||||||
|
} |
||||||
|
.sort { |
||||||
|
margin: 0 20rpx 0 10rpx; |
||||||
|
&:before { |
||||||
|
content: ''; |
||||||
|
display: block; |
||||||
|
margin-bottom: 5rpx; |
||||||
|
border: 15rpx solid transparent; |
||||||
|
border-bottom-color: #B9B9B9; |
||||||
|
} |
||||||
|
&:after { |
||||||
|
content: ''; |
||||||
|
display: block; |
||||||
|
border: 15rpx solid transparent; |
||||||
|
border-top-color: #B9B9B9; |
||||||
|
} |
||||||
|
&.desc:before { |
||||||
|
border-bottom-color: #007EFF; |
||||||
|
} |
||||||
|
&.asc:after { |
||||||
|
border-top-color: #007EFF; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
.form-list { |
||||||
|
border-top: 1px solid #E6E8ED; |
||||||
|
.line { |
||||||
|
display: flex; |
||||||
|
justify-content: space-between; |
||||||
|
align-items: center; |
||||||
|
padding: 28rpx 0; |
||||||
|
border-bottom: 1px solid #E6E8ED; |
||||||
|
&:last-child { |
||||||
|
border-bottom: 0; |
||||||
|
} |
||||||
|
} |
||||||
|
.ph { |
||||||
|
font-size: 28rpx; |
||||||
|
color: #999; |
||||||
|
} |
||||||
|
.name, .val, input { |
||||||
|
font-size: 28rpx; |
||||||
|
color: #333; |
||||||
|
} |
||||||
|
input { |
||||||
|
flex: 1; |
||||||
|
margin-left: 20rpx; |
||||||
|
text-align: right; |
||||||
|
} |
||||||
|
.req { |
||||||
|
.name:after { |
||||||
|
content: '*'; |
||||||
|
margin-left: 6rpx; |
||||||
|
color: #F53232; |
||||||
|
vertical-align: middle; |
||||||
|
} |
||||||
|
} |
||||||
|
.err { |
||||||
|
.name { |
||||||
|
color: #f00; |
||||||
|
} |
||||||
|
} |
||||||
|
.inline { |
||||||
|
display: inline-flex; |
||||||
|
align-items: center; |
||||||
|
@extend input; |
||||||
|
input { |
||||||
|
margin-right: 10rpx; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
.picker-input .input-value-border { |
||||||
|
line-height: 1; |
||||||
|
border: 0; |
||||||
|
} |
||||||
|
.tab { |
||||||
|
display: flex; |
||||||
|
justify-content: space-around; |
||||||
|
margin-bottom: 20rpx; |
||||||
|
background-color: #fff; |
||||||
|
li { |
||||||
|
padding: 0 20rpx; |
||||||
|
font-size: 28rpx; |
||||||
|
line-height: 100rpx; |
||||||
|
border-bottom: 3px solid transparent; |
||||||
|
} |
||||||
|
.active { |
||||||
|
color: $uni-primary; |
||||||
|
border-bottom-color: $uni-primary; |
||||||
|
} |
||||||
|
} |
||||||
|
.plus { |
||||||
|
position: fixed; |
||||||
|
bottom: 40rpx; |
||||||
|
right: 40rpx; |
||||||
|
} |
||||||
|
|
||||||
|
.popup-mask { |
||||||
|
z-index: 9; |
||||||
|
position: fixed; |
||||||
|
top: 0; |
||||||
|
left: 0; |
||||||
|
bottom: 0; |
||||||
|
right: 0; |
||||||
|
background-color: rgba(0, 0, 0, .5); |
||||||
|
} |
||||||
|
.popup { |
||||||
|
z-index: 10; |
||||||
|
position: fixed; |
||||||
|
bottom: 0%; |
||||||
|
width: 100%; |
||||||
|
height: 90vh; |
||||||
|
background-color: #fff; |
||||||
|
border-top-left-radius: 8px; |
||||||
|
border-top-right-radius: 8px; |
||||||
|
.top { |
||||||
|
text-align: center; |
||||||
|
line-height: 100rpx; |
||||||
|
font-size: 28rpx; |
||||||
|
color: #333; |
||||||
|
border-bottom: 1px solid #f1f1f1; |
||||||
|
} |
||||||
|
.close { |
||||||
|
position: absolute; |
||||||
|
top: 30rpx; |
||||||
|
right: 30rpx; |
||||||
|
} |
||||||
|
.list { |
||||||
|
max-height: calc(90vh - 206rpx); |
||||||
|
padding: 0 30rpx; |
||||||
|
overflow: auto; |
||||||
|
.item { |
||||||
|
line-height: 80rpx; |
||||||
|
font-size: 24rpx; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
.btn-wrap { |
||||||
|
z-index: 10; |
||||||
|
position: fixed; |
||||||
|
bottom: env(safe-area-inset-bottom); |
||||||
|
bottom: 0; |
||||||
|
display: flex; |
||||||
|
justify-content: flex-end; |
||||||
|
align-items: center; |
||||||
|
width: 100%; |
||||||
|
padding: 20rpx 24rpx 20rpx 40rpx; |
||||||
|
background-color: #fff; |
||||||
|
box-shadow: 0px 0px 7rpx 0px rgba(203, 203, 203, 0.55); |
||||||
|
box-sizing: border-box; |
||||||
|
.btn { |
||||||
|
width: 100%; |
||||||
|
line-height: 80rpx; |
||||||
|
font-size: 30rpx; |
||||||
|
text-align: center; |
||||||
|
color: #fff; |
||||||
|
border-radius: 10rpx; |
||||||
|
background-color: #007EFF; |
||||||
|
} |
||||||
|
} |
||||||
|
.per-mask { |
||||||
|
z-index: 3; |
||||||
|
position: fixed; |
||||||
|
top: 0; |
||||||
|
left: 0; |
||||||
|
display: flex; |
||||||
|
justify-content: center; |
||||||
|
align-items: center; |
||||||
|
width: 100%; |
||||||
|
height: 100%; |
||||||
|
font-size: 28rpx; |
||||||
|
color: #333; |
||||||
|
background-color: rgba(255, 255, 255, 0.95); |
||||||
|
-webkit-user-drag: none; |
||||||
|
-webkit-user-select: none; |
||||||
|
user-select: none; |
||||||
|
} |
@ -0,0 +1,3 @@ |
|||||||
|
@import '@/uni_modules/uni-scss/variables.scss'; |
||||||
|
@import '@/styles/common.scss'; |
||||||
|
@import '@/static/iconfont/iconfont.css'; |
@ -0,0 +1,44 @@ |
|||||||
|
## 3.2.2(2022-05-12) |
||||||
|
3.2.2 |
||||||
|
|
||||||
|
修复vue3引入js报错问题; |
||||||
|
增加draw可选项,可在每一阶段绘制前后扩展自定义方法,详见文档draw(options); |
||||||
|
其他优化。 |
||||||
|
## 3.2.1(2022-05-09) |
||||||
|
3.2.1 |
||||||
|
|
||||||
|
已实现导入临时文件方法`toTempFilePath`; |
||||||
|
已实现保存二维码到本地或相册方法`save`; |
||||||
|
已实现生成完成回调事件`complete`; |
||||||
|
文档补充。 |
||||||
|
## 3.2.0(2022-05-07) |
||||||
|
3.2.0 |
||||||
|
|
||||||
|
适用所有支持canvas的前端应用和Node.js服务端; |
||||||
|
微信小程序端切换为canvas2d; |
||||||
|
支持绘制背景图片和前景图片,也就是说可以绘制背景和logo了; |
||||||
|
支持对定位角进行样式设置; |
||||||
|
支持对分割图案进行样式设置; |
||||||
|
支持对对齐图案进行样式设置; |
||||||
|
支持对时序图案进行样式设置; |
||||||
|
支持对暗块进行样式设置; |
||||||
|
支持对版本信息进行样式设置; |
||||||
|
解决小块之间出现白线问题。 |
||||||
|
## 3.0.1(2022-01-05) |
||||||
|
3.0.1 gcanvas引用目录调整。 |
||||||
|
## 3.0.0(2022-01-04) |
||||||
|
3.0.0 uQRCode 3.0 全新版本来袭。 |
||||||
|
## 2.0.4(2021-11-19) |
||||||
|
2.0.4 新增绘制模式;新增绘制延时、canvas导入文件延时属性。 |
||||||
|
## 2.0.3(2021-10-18) |
||||||
|
2.0.3 修复在部分安卓设备生成异常;移除延迟绘制;新增批量生成示例。 |
||||||
|
## 2.0.23(2021-08-09) |
||||||
|
|
||||||
|
## 2.0.22(2021-08-09) |
||||||
|
|
||||||
|
## 2.0.21(2021-07-28) |
||||||
|
|
||||||
|
## 2.0.2(2021-07-28) |
||||||
|
2.0.2 新增延迟绘制。 |
||||||
|
## 2.0.1(2021-07-26) |
||||||
|
2.0.1 调整为uni_modules目录规范。 |
@ -0,0 +1,241 @@ |
|||||||
|
const isWeex = typeof WXEnvironment !== 'undefined'; |
||||||
|
const isWeexIOS = isWeex && /ios/i.test(WXEnvironment.platform); |
||||||
|
const isWeexAndroid = isWeex && !isWeexIOS; |
||||||
|
|
||||||
|
import GLmethod from '../context-webgl/GLmethod'; |
||||||
|
|
||||||
|
const GCanvasModule = |
||||||
|
(typeof weex !== 'undefined' && weex.requireModule) ? (weex.requireModule('gcanvas')) : |
||||||
|
(typeof __weex_require__ !== 'undefined') ? (__weex_require__('@weex-module/gcanvas')) : {}; |
||||||
|
|
||||||
|
let isDebugging = false; |
||||||
|
|
||||||
|
let isComboDisabled = false; |
||||||
|
|
||||||
|
const logCommand = (function () { |
||||||
|
const methodQuery = []; |
||||||
|
Object.keys(GLmethod).forEach(key => { |
||||||
|
methodQuery[GLmethod[key]] = key; |
||||||
|
}) |
||||||
|
const queryMethod = (id) => { |
||||||
|
return methodQuery[parseInt(id)] || 'NotFoundMethod'; |
||||||
|
} |
||||||
|
const logCommand = (id, cmds) => { |
||||||
|
const mId = cmds.split(',')[0]; |
||||||
|
const mName = queryMethod(mId); |
||||||
|
console.log(`=== callNative - componentId:${id}; method: ${mName}; cmds: ${cmds}`); |
||||||
|
} |
||||||
|
return logCommand; |
||||||
|
})(); |
||||||
|
|
||||||
|
function joinArray(arr, sep) { |
||||||
|
let res = ''; |
||||||
|
for (let i = 0; i < arr.length; i++) { |
||||||
|
if (i !== 0) { |
||||||
|
res += sep; |
||||||
|
} |
||||||
|
res += arr[i]; |
||||||
|
} |
||||||
|
return res; |
||||||
|
} |
||||||
|
|
||||||
|
const commandsCache = {} |
||||||
|
|
||||||
|
const GBridge = { |
||||||
|
|
||||||
|
callEnable: (ref, configArray) => { |
||||||
|
|
||||||
|
commandsCache[ref] = []; |
||||||
|
|
||||||
|
return GCanvasModule.enable({ |
||||||
|
componentId: ref, |
||||||
|
config: configArray |
||||||
|
}); |
||||||
|
}, |
||||||
|
|
||||||
|
callEnableDebug: () => { |
||||||
|
isDebugging = true; |
||||||
|
}, |
||||||
|
|
||||||
|
callEnableDisableCombo: () => { |
||||||
|
isComboDisabled = true; |
||||||
|
}, |
||||||
|
|
||||||
|
callSetContextType: function (componentId, context_type) { |
||||||
|
GCanvasModule.setContextType(context_type, componentId); |
||||||
|
}, |
||||||
|
|
||||||
|
callReset: function(id){ |
||||||
|
GCanvasModule.resetComponent && canvasModule.resetComponent(componentId); |
||||||
|
}, |
||||||
|
|
||||||
|
render: isWeexIOS ? function (componentId) { |
||||||
|
return GCanvasModule.extendCallNative({ |
||||||
|
contextId: componentId, |
||||||
|
type: 0x60000001 |
||||||
|
}); |
||||||
|
} : function (componentId) { |
||||||
|
return callGCanvasLinkNative(componentId, 0x60000001, 'render'); |
||||||
|
}, |
||||||
|
|
||||||
|
render2d: isWeexIOS ? function (componentId, commands, callback) { |
||||||
|
|
||||||
|
if (isDebugging) { |
||||||
|
console.log('>>> >>> render2d ==='); |
||||||
|
console.log('>>> commands: ' + commands); |
||||||
|
} |
||||||
|
|
||||||
|
GCanvasModule.render([commands, callback?true:false], componentId, callback); |
||||||
|
|
||||||
|
} : function (componentId, commands,callback) { |
||||||
|
|
||||||
|
if (isDebugging) { |
||||||
|
console.log('>>> >>> render2d ==='); |
||||||
|
console.log('>>> commands: ' + commands); |
||||||
|
} |
||||||
|
|
||||||
|
callGCanvasLinkNative(componentId, 0x20000001, commands); |
||||||
|
if(callback){ |
||||||
|
callback(); |
||||||
|
} |
||||||
|
}, |
||||||
|
|
||||||
|
callExtendCallNative: isWeexIOS ? function (componentId, cmdArgs) { |
||||||
|
|
||||||
|
throw 'should not be here anymore ' + cmdArgs; |
||||||
|
|
||||||
|
} : function (componentId, cmdArgs) { |
||||||
|
|
||||||
|
throw 'should not be here anymore ' + cmdArgs; |
||||||
|
|
||||||
|
}, |
||||||
|
|
||||||
|
|
||||||
|
flushNative: isWeexIOS ? function (componentId) { |
||||||
|
|
||||||
|
const cmdArgs = joinArray(commandsCache[componentId], ';'); |
||||||
|
commandsCache[componentId] = []; |
||||||
|
|
||||||
|
if (isDebugging) { |
||||||
|
console.log('>>> >>> flush native ==='); |
||||||
|
console.log('>>> commands: ' + cmdArgs); |
||||||
|
} |
||||||
|
|
||||||
|
const result = GCanvasModule.extendCallNative({ |
||||||
|
"contextId": componentId, |
||||||
|
"type": 0x60000000, |
||||||
|
"args": cmdArgs |
||||||
|
}); |
||||||
|
|
||||||
|
const res = result && result.result; |
||||||
|
|
||||||
|
if (isDebugging) { |
||||||
|
console.log('>>> result: ' + res); |
||||||
|
} |
||||||
|
|
||||||
|
return res; |
||||||
|
|
||||||
|
} : function (componentId) { |
||||||
|
|
||||||
|
const cmdArgs = joinArray(commandsCache[componentId], ';'); |
||||||
|
commandsCache[componentId] = []; |
||||||
|
|
||||||
|
if (isDebugging) { |
||||||
|
console.log('>>> >>> flush native ==='); |
||||||
|
console.log('>>> commands: ' + cmdArgs); |
||||||
|
} |
||||||
|
|
||||||
|
const result = callGCanvasLinkNative(componentId, 0x60000000, cmdArgs); |
||||||
|
|
||||||
|
if (isDebugging) { |
||||||
|
console.log('>>> result: ' + result); |
||||||
|
} |
||||||
|
|
||||||
|
return result; |
||||||
|
}, |
||||||
|
|
||||||
|
callNative: function (componentId, cmdArgs, cache) { |
||||||
|
|
||||||
|
if (isDebugging) { |
||||||
|
logCommand(componentId, cmdArgs); |
||||||
|
} |
||||||
|
|
||||||
|
commandsCache[componentId].push(cmdArgs); |
||||||
|
|
||||||
|
if (!cache || isComboDisabled) { |
||||||
|
return GBridge.flushNative(componentId); |
||||||
|
} else { |
||||||
|
return undefined; |
||||||
|
} |
||||||
|
}, |
||||||
|
|
||||||
|
texImage2D(componentId, ...args) { |
||||||
|
if (isWeexIOS) { |
||||||
|
if (args.length === 6) { |
||||||
|
const [target, level, internalformat, format, type, image] = args; |
||||||
|
GBridge.callNative( |
||||||
|
componentId, |
||||||
|
GLmethod.texImage2D + ',' + 6 + ',' + target + ',' + level + ',' + internalformat + ',' + format + ',' + type + ',' + image.src |
||||||
|
) |
||||||
|
} else if (args.length === 9) { |
||||||
|
const [target, level, internalformat, width, height, border, format, type, image] = args; |
||||||
|
GBridge.callNative( |
||||||
|
componentId, |
||||||
|
GLmethod.texImage2D + ',' + 9 + ',' + target + ',' + level + ',' + internalformat + ',' + width + ',' + height + ',' + border + ',' + |
||||||
|
+ format + ',' + type + ',' + (image ? image.src : 0) |
||||||
|
) |
||||||
|
} |
||||||
|
} else if (isWeexAndroid) { |
||||||
|
if (args.length === 6) { |
||||||
|
const [target, level, internalformat, format, type, image] = args; |
||||||
|
GCanvasModule.texImage2D(componentId, target, level, internalformat, format, type, image.src); |
||||||
|
} else if (args.length === 9) { |
||||||
|
const [target, level, internalformat, width, height, border, format, type, image] = args; |
||||||
|
GCanvasModule.texImage2D(componentId, target, level, internalformat, width, height, border, format, type, (image ? image.src : 0)); |
||||||
|
} |
||||||
|
} |
||||||
|
}, |
||||||
|
|
||||||
|
texSubImage2D(componentId, target, level, xoffset, yoffset, format, type, image) { |
||||||
|
if (isWeexIOS) { |
||||||
|
if (arguments.length === 8) { |
||||||
|
GBridge.callNative( |
||||||
|
componentId, |
||||||
|
GLmethod.texSubImage2D + ',' + 6 + ',' + target + ',' + level + ',' + xoffset + ',' + yoffset, + ',' + format + ',' + type + ',' + image.src |
||||||
|
) |
||||||
|
} |
||||||
|
} else if (isWeexAndroid) { |
||||||
|
GCanvasModule.texSubImage2D(componentId, target, level, xoffset, yoffset, format, type, image.src); |
||||||
|
} |
||||||
|
}, |
||||||
|
|
||||||
|
bindImageTexture(componentId, src, imageId) { |
||||||
|
GCanvasModule.bindImageTexture([src, imageId], componentId); |
||||||
|
}, |
||||||
|
|
||||||
|
perloadImage([url, id], callback) { |
||||||
|
GCanvasModule.preLoadImage([url, id], function (image) { |
||||||
|
image.url = url; |
||||||
|
image.id = id; |
||||||
|
callback(image); |
||||||
|
}); |
||||||
|
}, |
||||||
|
|
||||||
|
measureText(text, fontStyle, componentId) { |
||||||
|
return GCanvasModule.measureText([text, fontStyle], componentId); |
||||||
|
}, |
||||||
|
|
||||||
|
getImageData (componentId, x, y, w, h, callback) { |
||||||
|
GCanvasModule.getImageData([x, y,w,h],componentId,callback); |
||||||
|
}, |
||||||
|
|
||||||
|
putImageData (componentId, data, x, y, w, h, callback) { |
||||||
|
GCanvasModule.putImageData([x, y,w,h,data],componentId,callback); |
||||||
|
}, |
||||||
|
|
||||||
|
toTempFilePath(componentId, x, y, width, height, destWidth, destHeight, fileType, quality, callback){
|
||||||
|
GCanvasModule.toTempFilePath([x, y, width,height, destWidth, destHeight, fileType, quality], componentId, callback); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
export default GBridge; |
@ -0,0 +1,18 @@ |
|||||||
|
class FillStyleLinearGradient { |
||||||
|
|
||||||
|
constructor(x0, y0, x1, y1) { |
||||||
|
this._start_pos = { _x: x0, _y: y0 }; |
||||||
|
this._end_pos = { _x: x1, _y: y1 }; |
||||||
|
this._stop_count = 0; |
||||||
|
this._stops = [0, 0, 0, 0, 0]; |
||||||
|
} |
||||||
|
|
||||||
|
addColorStop = function (pos, color) { |
||||||
|
if (this._stop_count < 5 && 0.0 <= pos && pos <= 1.0) { |
||||||
|
this._stops[this._stop_count] = { _pos: pos, _color: color }; |
||||||
|
this._stop_count++; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
export default FillStyleLinearGradient; |
@ -0,0 +1,8 @@ |
|||||||
|
class FillStylePattern { |
||||||
|
constructor(img, pattern) { |
||||||
|
this._style = pattern; |
||||||
|
this._img = img; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
export default FillStylePattern; |
@ -0,0 +1,17 @@ |
|||||||
|
class FillStyleRadialGradient { |
||||||
|
constructor(x0, y0, r0, x1, y1, r1) { |
||||||
|
this._start_pos = { _x: x0, _y: y0, _r: r0 }; |
||||||
|
this._end_pos = { _x: x1, _y: y1, _r: r1 }; |
||||||
|
this._stop_count = 0; |
||||||
|
this._stops = [0, 0, 0, 0, 0]; |
||||||
|
} |
||||||
|
|
||||||
|
addColorStop(pos, color) { |
||||||
|
if (this._stop_count < 5 && 0.0 <= pos && pos <= 1.0) { |
||||||
|
this._stops[this._stop_count] = { _pos: pos, _color: color }; |
||||||
|
this._stop_count++; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
export default FillStyleRadialGradient; |
@ -0,0 +1,666 @@ |
|||||||
|
import FillStylePattern from './FillStylePattern'; |
||||||
|
import FillStyleLinearGradient from './FillStyleLinearGradient'; |
||||||
|
import FillStyleRadialGradient from './FillStyleRadialGradient'; |
||||||
|
import GImage from '../env/image.js'; |
||||||
|
import { |
||||||
|
ArrayBufferToBase64, |
||||||
|
Base64ToUint8ClampedArray |
||||||
|
} from '../env/tool.js'; |
||||||
|
|
||||||
|
export default class CanvasRenderingContext2D { |
||||||
|
|
||||||
|
_drawCommands = ''; |
||||||
|
|
||||||
|
_globalAlpha = 1.0; |
||||||
|
|
||||||
|
_fillStyle = 'rgb(0,0,0)'; |
||||||
|
_strokeStyle = 'rgb(0,0,0)'; |
||||||
|
|
||||||
|
_lineWidth = 1; |
||||||
|
_lineCap = 'butt'; |
||||||
|
_lineJoin = 'miter'; |
||||||
|
|
||||||
|
_miterLimit = 10; |
||||||
|
|
||||||
|
_globalCompositeOperation = 'source-over'; |
||||||
|
|
||||||
|
_textAlign = 'start'; |
||||||
|
_textBaseline = 'alphabetic'; |
||||||
|
|
||||||
|
_font = '10px sans-serif'; |
||||||
|
|
||||||
|
_savedGlobalAlpha = []; |
||||||
|
|
||||||
|
timer = null; |
||||||
|
componentId = null; |
||||||
|
|
||||||
|
_notCommitDrawImageCache = []; |
||||||
|
_needRedrawImageCache = []; |
||||||
|
_redrawCommands = ''; |
||||||
|
_autoSaveContext = true; |
||||||
|
// _imageMap = new GHashMap();
|
||||||
|
// _textureMap = new GHashMap();
|
||||||
|
|
||||||
|
constructor() { |
||||||
|
this.className = 'CanvasRenderingContext2D'; |
||||||
|
//this.save()
|
||||||
|
} |
||||||
|
|
||||||
|
setFillStyle(value) { |
||||||
|
this.fillStyle = value; |
||||||
|
} |
||||||
|
|
||||||
|
set fillStyle(value) { |
||||||
|
this._fillStyle = value; |
||||||
|
|
||||||
|
if (typeof(value) == 'string') { |
||||||
|
this._drawCommands = this._drawCommands.concat("F" + value + ";"); |
||||||
|
} else if (value instanceof FillStylePattern) { |
||||||
|
const image = value._img; |
||||||
|
if (!image.complete) { |
||||||
|
image.onload = () => { |
||||||
|
var index = this._needRedrawImageCache.indexOf(image); |
||||||
|
if (index > -1) { |
||||||
|
this._needRedrawImageCache.splice(index, 1); |
||||||
|
CanvasRenderingContext2D.GBridge.bindImageTexture(this.componentId, image.src, image._id); |
||||||
|
this._redrawflush(true); |
||||||
|
} |
||||||
|
} |
||||||
|
this._notCommitDrawImageCache.push(image); |
||||||
|
} else { |
||||||
|
CanvasRenderingContext2D.GBridge.bindImageTexture(this.componentId, image.src, image._id); |
||||||
|
} |
||||||
|
|
||||||
|
//CanvasRenderingContext2D.GBridge.bindImageTexture(this.componentId, image.src, image._id);
|
||||||
|
this._drawCommands = this._drawCommands.concat("G" + image._id + "," + value._style + ";"); |
||||||
|
} else if (value instanceof FillStyleLinearGradient) { |
||||||
|
var command = "D" + value._start_pos._x.toFixed(2) + "," + value._start_pos._y.toFixed(2) + "," + |
||||||
|
value._end_pos._x.toFixed(2) + "," + value._end_pos._y.toFixed(2) + "," + |
||||||
|
value._stop_count; |
||||||
|
for (var i = 0; i < value._stop_count; ++i) { |
||||||
|
command += ("," + value._stops[i]._pos + "," + value._stops[i]._color); |
||||||
|
} |
||||||
|
this._drawCommands = this._drawCommands.concat(command + ";"); |
||||||
|
} else if (value instanceof FillStyleRadialGradient) { |
||||||
|
var command = "H" + value._start_pos._x.toFixed(2) + "," + value._start_pos._y.toFixed(2) + "," + value._start_pos._r |
||||||
|
.toFixed(2) + "," + |
||||||
|
value._end_pos._x.toFixed(2) + "," + value._end_pos._y.toFixed(2) + "," + value._end_pos._r.toFixed(2) + "," + |
||||||
|
value._stop_count; |
||||||
|
for (var i = 0; i < value._stop_count; ++i) { |
||||||
|
command += ("," + value._stops[i]._pos + "," + value._stops[i]._color); |
||||||
|
} |
||||||
|
this._drawCommands = this._drawCommands.concat(command + ";"); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
get fillStyle() { |
||||||
|
return this._fillStyle; |
||||||
|
} |
||||||
|
|
||||||
|
get globalAlpha() { |
||||||
|
return this._globalAlpha; |
||||||
|
} |
||||||
|
|
||||||
|
setGlobalAlpha(value) { |
||||||
|
this.globalAlpha = value; |
||||||
|
} |
||||||
|
|
||||||
|
set globalAlpha(value) { |
||||||
|
this._globalAlpha = value; |
||||||
|
this._drawCommands = this._drawCommands.concat("a" + value.toFixed(2) + ";"); |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
get strokeStyle() { |
||||||
|
return this._strokeStyle; |
||||||
|
} |
||||||
|
|
||||||
|
setStrokeStyle(value) { |
||||||
|
this.strokeStyle = value; |
||||||
|
} |
||||||
|
|
||||||
|
set strokeStyle(value) { |
||||||
|
|
||||||
|
this._strokeStyle = value; |
||||||
|
|
||||||
|
if (typeof(value) == 'string') { |
||||||
|
this._drawCommands = this._drawCommands.concat("S" + value + ";"); |
||||||
|
} else if (value instanceof FillStylePattern) { |
||||||
|
CanvasRenderingContext2D.GBridge.bindImageTexture(this.componentId, image.src, image._id); |
||||||
|
this._drawCommands = this._drawCommands.concat("G" + image._id + "," + value._style + ";"); |
||||||
|
} else if (value instanceof FillStyleLinearGradient) { |
||||||
|
var command = "D" + value._start_pos._x.toFixed(2) + "," + value._start_pos._y.toFixed(2) + "," + |
||||||
|
value._end_pos._x.toFixed(2) + "," + value._end_pos._y.toFixed(2) + "," + |
||||||
|
value._stop_count; |
||||||
|
|
||||||
|
for (var i = 0; i < value._stop_count; ++i) { |
||||||
|
command += ("," + value._stops[i]._pos + "," + value._stops[i]._color); |
||||||
|
} |
||||||
|
this._drawCommands = this._drawCommands.concat(command + ";"); |
||||||
|
} else if (value instanceof FillStyleRadialGradient) { |
||||||
|
var command = "H" + value._start_pos._x.toFixed(2) + "," + value._start_pos._y.toFixed(2) + "," + value._start_pos._r |
||||||
|
.toFixed(2) + "," + |
||||||
|
value._end_pos._x.toFixed(2) + "," + value._end_pos._y + ",".toFixed(2) + value._end_pos._r.toFixed(2) + "," + |
||||||
|
value._stop_count; |
||||||
|
|
||||||
|
for (var i = 0; i < value._stop_count; ++i) { |
||||||
|
command += ("," + value._stops[i]._pos + "," + value._stops[i]._color); |
||||||
|
} |
||||||
|
this._drawCommands = this._drawCommands.concat(command + ";"); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
get lineWidth() { |
||||||
|
return this._lineWidth; |
||||||
|
} |
||||||
|
|
||||||
|
setLineWidth(value) { |
||||||
|
this.lineWidth = value; |
||||||
|
} |
||||||
|
|
||||||
|
set lineWidth(value) { |
||||||
|
this._lineWidth = value; |
||||||
|
this._drawCommands = this._drawCommands.concat("W" + value + ";"); |
||||||
|
} |
||||||
|
|
||||||
|
get lineCap() { |
||||||
|
return this._lineCap; |
||||||
|
} |
||||||
|
|
||||||
|
setLineCap(value) { |
||||||
|
this.lineCap = value; |
||||||
|
} |
||||||
|
|
||||||
|
set lineCap(value) { |
||||||
|
this._lineCap = value; |
||||||
|
this._drawCommands = this._drawCommands.concat("C" + value + ";"); |
||||||
|
} |
||||||
|
|
||||||
|
get lineJoin() { |
||||||
|
return this._lineJoin; |
||||||
|
} |
||||||
|
|
||||||
|
setLineJoin(value) { |
||||||
|
this.lineJoin = value |
||||||
|
} |
||||||
|
|
||||||
|
set lineJoin(value) { |
||||||
|
this._lineJoin = value; |
||||||
|
this._drawCommands = this._drawCommands.concat("J" + value + ";"); |
||||||
|
} |
||||||
|
|
||||||
|
get miterLimit() { |
||||||
|
return this._miterLimit; |
||||||
|
} |
||||||
|
|
||||||
|
setMiterLimit(value) { |
||||||
|
this.miterLimit = value |
||||||
|
} |
||||||
|
|
||||||
|
set miterLimit(value) { |
||||||
|
this._miterLimit = value; |
||||||
|
this._drawCommands = this._drawCommands.concat("M" + value + ";"); |
||||||
|
} |
||||||
|
|
||||||
|
get globalCompositeOperation() { |
||||||
|
return this._globalCompositeOperation; |
||||||
|
} |
||||||
|
|
||||||
|
set globalCompositeOperation(value) { |
||||||
|
|
||||||
|
this._globalCompositeOperation = value; |
||||||
|
let mode = 0; |
||||||
|
switch (value) { |
||||||
|
case "source-over": |
||||||
|
mode = 0; |
||||||
|
break; |
||||||
|
case "source-atop": |
||||||
|
mode = 5; |
||||||
|
break; |
||||||
|
case "source-in": |
||||||
|
mode = 0; |
||||||
|
break; |
||||||
|
case "source-out": |
||||||
|
mode = 2; |
||||||
|
break; |
||||||
|
case "destination-over": |
||||||
|
mode = 4; |
||||||
|
break; |
||||||
|
case "destination-atop": |
||||||
|
mode = 4; |
||||||
|
break; |
||||||
|
case "destination-in": |
||||||
|
mode = 4; |
||||||
|
break; |
||||||
|
case "destination-out": |
||||||
|
mode = 3; |
||||||
|
break; |
||||||
|
case "lighter": |
||||||
|
mode = 1; |
||||||
|
break; |
||||||
|
case "copy": |
||||||
|
mode = 2; |
||||||
|
break; |
||||||
|
case "xor": |
||||||
|
mode = 6; |
||||||
|
break; |
||||||
|
default: |
||||||
|
mode = 0; |
||||||
|
} |
||||||
|
|
||||||
|
this._drawCommands = this._drawCommands.concat("B" + mode + ";"); |
||||||
|
} |
||||||
|
|
||||||
|
get textAlign() { |
||||||
|
return this._textAlign; |
||||||
|
} |
||||||
|
|
||||||
|
setTextAlign(value) { |
||||||
|
this.textAlign = value |
||||||
|
} |
||||||
|
|
||||||
|
set textAlign(value) { |
||||||
|
|
||||||
|
this._textAlign = value; |
||||||
|
let Align = 0; |
||||||
|
switch (value) { |
||||||
|
case "start": |
||||||
|
Align = 0; |
||||||
|
break; |
||||||
|
case "end": |
||||||
|
Align = 1; |
||||||
|
break; |
||||||
|
case "left": |
||||||
|
Align = 2; |
||||||
|
break; |
||||||
|
case "center": |
||||||
|
Align = 3; |
||||||
|
break; |
||||||
|
case "right": |
||||||
|
Align = 4; |
||||||
|
break; |
||||||
|
default: |
||||||
|
Align = 0; |
||||||
|
} |
||||||
|
|
||||||
|
this._drawCommands = this._drawCommands.concat("A" + Align + ";"); |
||||||
|
} |
||||||
|
|
||||||
|
get textBaseline() { |
||||||
|
return this._textBaseline; |
||||||
|
} |
||||||
|
|
||||||
|
setTextBaseline(value) { |
||||||
|
this.textBaseline = value |
||||||
|
} |
||||||
|
|
||||||
|
set textBaseline(value) { |
||||||
|
this._textBaseline = value; |
||||||
|
let baseline = 0; |
||||||
|
switch (value) { |
||||||
|
case "alphabetic": |
||||||
|
baseline = 0; |
||||||
|
break; |
||||||
|
case "middle": |
||||||
|
baseline = 1; |
||||||
|
break; |
||||||
|
case "top": |
||||||
|
baseline = 2; |
||||||
|
break; |
||||||
|
case "hanging": |
||||||
|
baseline = 3; |
||||||
|
break; |
||||||
|
case "bottom": |
||||||
|
baseline = 4; |
||||||
|
break; |
||||||
|
case "ideographic": |
||||||
|
baseline = 5; |
||||||
|
break; |
||||||
|
default: |
||||||
|
baseline = 0; |
||||||
|
break; |
||||||
|
} |
||||||
|
|
||||||
|
this._drawCommands = this._drawCommands.concat("E" + baseline + ";"); |
||||||
|
} |
||||||
|
|
||||||
|
get font() { |
||||||
|
return this._font; |
||||||
|
} |
||||||
|
|
||||||
|
setFontSize(size) { |
||||||
|
var str = this._font; |
||||||
|
var strs = str.trim().split(/\s+/); |
||||||
|
for (var i = 0; i < strs.length; i++) { |
||||||
|
var values = ["normal", "italic", "oblique", "normal", "small-caps", "normal", "bold", |
||||||
|
"bolder", "lighter", "100", "200", "300", "400", "500", "600", "700", "800", "900", |
||||||
|
"normal", "ultra-condensed", "extra-condensed", "condensed", "semi-condensed", |
||||||
|
"semi-expanded", "expanded", "extra-expanded", "ultra-expanded" |
||||||
|
]; |
||||||
|
|
||||||
|
if (-1 == values.indexOf(strs[i].trim())) { |
||||||
|
if (typeof size === 'string') { |
||||||
|
strs[i] = size; |
||||||
|
} else if (typeof size === 'number') { |
||||||
|
strs[i] = String(size) + 'px'; |
||||||
|
} |
||||||
|
break; |
||||||
|
} |
||||||
|
} |
||||||
|
this.font = strs.join(" "); |
||||||
|
} |
||||||
|
|
||||||
|
set font(value) { |
||||||
|
this._font = value; |
||||||
|
this._drawCommands = this._drawCommands.concat("j" + value + ";"); |
||||||
|
} |
||||||
|
|
||||||
|
setTransform(a, b, c, d, tx, ty) { |
||||||
|
this._drawCommands = this._drawCommands.concat("t" + |
||||||
|
(a === 1 ? "1" : a.toFixed(2)) + "," + |
||||||
|
(b === 0 ? "0" : b.toFixed(2)) + "," + |
||||||
|
(c === 0 ? "0" : c.toFixed(2)) + "," + |
||||||
|
(d === 1 ? "1" : d.toFixed(2)) + "," + tx.toFixed(2) + "," + ty.toFixed(2) + ";"); |
||||||
|
} |
||||||
|
|
||||||
|
transform(a, b, c, d, tx, ty) { |
||||||
|
this._drawCommands = this._drawCommands.concat("f" + |
||||||
|
(a === 1 ? "1" : a.toFixed(2)) + "," + |
||||||
|
(b === 0 ? "0" : b.toFixed(2)) + "," + |
||||||
|
(c === 0 ? "0" : c.toFixed(2)) + "," + |
||||||
|
(d === 1 ? "1" : d.toFixed(2)) + "," + tx + "," + ty + ";"); |
||||||
|
} |
||||||
|
|
||||||
|
resetTransform() { |
||||||
|
this._drawCommands = this._drawCommands.concat("m;"); |
||||||
|
} |
||||||
|
|
||||||
|
scale(a, d) { |
||||||
|
this._drawCommands = this._drawCommands.concat("k" + a.toFixed(2) + "," + |
||||||
|
d.toFixed(2) + ";"); |
||||||
|
} |
||||||
|
|
||||||
|
rotate(angle) { |
||||||
|
this._drawCommands = this._drawCommands |
||||||
|
.concat("r" + angle.toFixed(6) + ";"); |
||||||
|
} |
||||||
|
|
||||||
|
translate(tx, ty) { |
||||||
|
this._drawCommands = this._drawCommands.concat("l" + tx.toFixed(2) + "," + ty.toFixed(2) + ";"); |
||||||
|
} |
||||||
|
|
||||||
|
save() { |
||||||
|
this._savedGlobalAlpha.push(this._globalAlpha); |
||||||
|
this._drawCommands = this._drawCommands.concat("v;"); |
||||||
|
} |
||||||
|
|
||||||
|
restore() { |
||||||
|
this._drawCommands = this._drawCommands.concat("e;"); |
||||||
|
this._globalAlpha = this._savedGlobalAlpha.pop(); |
||||||
|
} |
||||||
|
|
||||||
|
createPattern(img, pattern) { |
||||||
|
if (typeof img === 'string') { |
||||||
|
var imgObj = new GImage(); |
||||||
|
imgObj.src = img; |
||||||
|
img = imgObj; |
||||||
|
} |
||||||
|
return new FillStylePattern(img, pattern); |
||||||
|
} |
||||||
|
|
||||||
|
createLinearGradient(x0, y0, x1, y1) { |
||||||
|
return new FillStyleLinearGradient(x0, y0, x1, y1); |
||||||
|
} |
||||||
|
|
||||||
|
createRadialGradient = function(x0, y0, r0, x1, y1, r1) { |
||||||
|
return new FillStyleRadialGradient(x0, y0, r0, x1, y1, r1); |
||||||
|
}; |
||||||
|
|
||||||
|
createCircularGradient = function(x0, y0, r0) { |
||||||
|
return new FillStyleRadialGradient(x0, y0, 0, x0, y0, r0); |
||||||
|
}; |
||||||
|
|
||||||
|
strokeRect(x, y, w, h) { |
||||||
|
this._drawCommands = this._drawCommands.concat("s" + x + "," + y + "," + w + "," + h + ";"); |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
clearRect(x, y, w, h) { |
||||||
|
this._drawCommands = this._drawCommands.concat("c" + x + "," + y + "," + w + |
||||||
|
"," + h + ";"); |
||||||
|
} |
||||||
|
|
||||||
|
clip() { |
||||||
|
this._drawCommands = this._drawCommands.concat("p;"); |
||||||
|
} |
||||||
|
|
||||||
|
resetClip() { |
||||||
|
this._drawCommands = this._drawCommands.concat("q;"); |
||||||
|
} |
||||||
|
|
||||||
|
closePath() { |
||||||
|
this._drawCommands = this._drawCommands.concat("o;"); |
||||||
|
} |
||||||
|
|
||||||
|
moveTo(x, y) { |
||||||
|
this._drawCommands = this._drawCommands.concat("g" + x.toFixed(2) + "," + y.toFixed(2) + ";"); |
||||||
|
} |
||||||
|
|
||||||
|
lineTo(x, y) { |
||||||
|
this._drawCommands = this._drawCommands.concat("i" + x.toFixed(2) + "," + y.toFixed(2) + ";"); |
||||||
|
} |
||||||
|
|
||||||
|
quadraticCurveTo = function(cpx, cpy, x, y) { |
||||||
|
this._drawCommands = this._drawCommands.concat("u" + cpx + "," + cpy + "," + x + "," + y + ";"); |
||||||
|
} |
||||||
|
|
||||||
|
bezierCurveTo(cp1x, cp1y, cp2x, cp2y, x, y, ) { |
||||||
|
this._drawCommands = this._drawCommands.concat( |
||||||
|
"z" + cp1x.toFixed(2) + "," + cp1y.toFixed(2) + "," + cp2x.toFixed(2) + "," + cp2y.toFixed(2) + "," + |
||||||
|
x.toFixed(2) + "," + y.toFixed(2) + ";"); |
||||||
|
} |
||||||
|
|
||||||
|
arcTo(x1, y1, x2, y2, radius) { |
||||||
|
this._drawCommands = this._drawCommands.concat("h" + x1 + "," + y1 + "," + x2 + "," + y2 + "," + radius + ";"); |
||||||
|
} |
||||||
|
|
||||||
|
beginPath() { |
||||||
|
this._drawCommands = this._drawCommands.concat("b;"); |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
fillRect(x, y, w, h) { |
||||||
|
this._drawCommands = this._drawCommands.concat("n" + x + "," + y + "," + w + |
||||||
|
"," + h + ";"); |
||||||
|
} |
||||||
|
|
||||||
|
rect(x, y, w, h) { |
||||||
|
this._drawCommands = this._drawCommands.concat("w" + x + "," + y + "," + w + "," + h + ";"); |
||||||
|
} |
||||||
|
|
||||||
|
fill() { |
||||||
|
this._drawCommands = this._drawCommands.concat("L;"); |
||||||
|
} |
||||||
|
|
||||||
|
stroke(path) { |
||||||
|
this._drawCommands = this._drawCommands.concat("x;"); |
||||||
|
} |
||||||
|
|
||||||
|
arc(x, y, radius, startAngle, endAngle, anticlockwise) { |
||||||
|
|
||||||
|
let ianticlockwise = 0; |
||||||
|
if (anticlockwise) { |
||||||
|
ianticlockwise = 1; |
||||||
|
} |
||||||
|
|
||||||
|
this._drawCommands = this._drawCommands.concat( |
||||||
|
"y" + x.toFixed(2) + "," + y.toFixed(2) + "," + |
||||||
|
radius.toFixed(2) + "," + startAngle + "," + endAngle + "," + ianticlockwise + |
||||||
|
";" |
||||||
|
); |
||||||
|
} |
||||||
|
|
||||||
|
fillText(text, x, y) { |
||||||
|
let tmptext = text.replace(/!/g, "!!"); |
||||||
|
tmptext = tmptext.replace(/,/g, "!,"); |
||||||
|
tmptext = tmptext.replace(/;/g, "!;"); |
||||||
|
this._drawCommands = this._drawCommands.concat("T" + tmptext + "," + x + "," + y + ",0.0;"); |
||||||
|
} |
||||||
|
|
||||||
|
strokeText = function(text, x, y) { |
||||||
|
let tmptext = text.replace(/!/g, "!!"); |
||||||
|
tmptext = tmptext.replace(/,/g, "!,"); |
||||||
|
tmptext = tmptext.replace(/;/g, "!;"); |
||||||
|
this._drawCommands = this._drawCommands.concat("U" + tmptext + "," + x + "," + y + ",0.0;"); |
||||||
|
} |
||||||
|
|
||||||
|
measureText(text) { |
||||||
|
return CanvasRenderingContext2D.GBridge.measureText(text, this.font, this.componentId); |
||||||
|
} |
||||||
|
|
||||||
|
isPointInPath = function(x, y) { |
||||||
|
throw new Error('GCanvas not supported yet'); |
||||||
|
} |
||||||
|
|
||||||
|
drawImage(image, sx, sy, sw, sh, dx, dy, dw, dh) { |
||||||
|
if (typeof image === 'string') { |
||||||
|
var imgObj = new GImage(); |
||||||
|
imgObj.src = image; |
||||||
|
image = imgObj; |
||||||
|
} |
||||||
|
if (image instanceof GImage) { |
||||||
|
if (!image.complete) { |
||||||
|
imgObj.onload = () => { |
||||||
|
var index = this._needRedrawImageCache.indexOf(image); |
||||||
|
if (index > -1) { |
||||||
|
this._needRedrawImageCache.splice(index, 1); |
||||||
|
CanvasRenderingContext2D.GBridge.bindImageTexture(this.componentId, image.src, image._id); |
||||||
|
this._redrawflush(true); |
||||||
|
} |
||||||
|
} |
||||||
|
this._notCommitDrawImageCache.push(image); |
||||||
|
} else { |
||||||
|
CanvasRenderingContext2D.GBridge.bindImageTexture(this.componentId, image.src, image._id); |
||||||
|
} |
||||||
|
var srcArgs = [image, sx, sy, sw, sh, dx, dy, dw, dh]; |
||||||
|
var args = []; |
||||||
|
for (var arg in srcArgs) { |
||||||
|
if (typeof(srcArgs[arg]) != 'undefined') { |
||||||
|
args.push(srcArgs[arg]); |
||||||
|
} |
||||||
|
} |
||||||
|
this.__drawImage.apply(this, args); |
||||||
|
//this.__drawImage(image,sx, sy, sw, sh, dx, dy, dw, dh);
|
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
__drawImage(image, sx, sy, sw, sh, dx, dy, dw, dh) { |
||||||
|
const numArgs = arguments.length; |
||||||
|
|
||||||
|
function drawImageCommands() { |
||||||
|
|
||||||
|
if (numArgs === 3) { |
||||||
|
const x = parseFloat(sx) || 0.0; |
||||||
|
const y = parseFloat(sy) || 0.0; |
||||||
|
|
||||||
|
return ("d" + image._id + ",0,0," + |
||||||
|
image.width + "," + image.height + "," + |
||||||
|
x + "," + y + "," + image.width + "," + image.height + ";"); |
||||||
|
} else if (numArgs === 5) { |
||||||
|
const x = parseFloat(sx) || 0.0; |
||||||
|
const y = parseFloat(sy) || 0.0; |
||||||
|
const width = parseInt(sw) || image.width; |
||||||
|
const height = parseInt(sh) || image.height; |
||||||
|
|
||||||
|
return ("d" + image._id + ",0,0," + |
||||||
|
image.width + "," + image.height + "," + |
||||||
|
x + "," + y + "," + width + "," + height + ";"); |
||||||
|
} else if (numArgs === 9) { |
||||||
|
sx = parseFloat(sx) || 0.0; |
||||||
|
sy = parseFloat(sy) || 0.0; |
||||||
|
sw = parseInt(sw) || image.width; |
||||||
|
sh = parseInt(sh) || image.height; |
||||||
|
dx = parseFloat(dx) || 0.0; |
||||||
|
dy = parseFloat(dy) || 0.0; |
||||||
|
dw = parseInt(dw) || image.width; |
||||||
|
dh = parseInt(dh) || image.height; |
||||||
|
|
||||||
|
return ("d" + image._id + "," + |
||||||
|
sx + "," + sy + "," + sw + "," + sh + "," + |
||||||
|
dx + "," + dy + "," + dw + "," + dh + ";"); |
||||||
|
} |
||||||
|
} |
||||||
|
this._drawCommands += drawImageCommands(); |
||||||
|
} |
||||||
|
|
||||||
|
_flush(reserve, callback) { |
||||||
|
const commands = this._drawCommands; |
||||||
|
this._drawCommands = ''; |
||||||
|
CanvasRenderingContext2D.GBridge.render2d(this.componentId, commands, callback); |
||||||
|
this._needRender = false; |
||||||
|
} |
||||||
|
|
||||||
|
_redrawflush(reserve, callback) { |
||||||
|
const commands = this._redrawCommands; |
||||||
|
CanvasRenderingContext2D.GBridge.render2d(this.componentId, commands, callback); |
||||||
|
if (this._needRedrawImageCache.length == 0) { |
||||||
|
this._redrawCommands = ''; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
draw(reserve, callback) { |
||||||
|
if (!reserve) { |
||||||
|
this._globalAlpha = this._savedGlobalAlpha.pop(); |
||||||
|
this._savedGlobalAlpha.push(this._globalAlpha); |
||||||
|
this._redrawCommands = this._drawCommands; |
||||||
|
this._needRedrawImageCache = this._notCommitDrawImageCache; |
||||||
|
if (this._autoSaveContext) { |
||||||
|
this._drawCommands = ("v;" + this._drawCommands); |
||||||
|
this._autoSaveContext = false; |
||||||
|
} else { |
||||||
|
this._drawCommands = ("e;X;v;" + this._drawCommands); |
||||||
|
} |
||||||
|
} else { |
||||||
|
this._needRedrawImageCache = this._needRedrawImageCache.concat(this._notCommitDrawImageCache); |
||||||
|
this._redrawCommands += this._drawCommands; |
||||||
|
if (this._autoSaveContext) { |
||||||
|
this._drawCommands = ("v;" + this._drawCommands); |
||||||
|
this._autoSaveContext = false; |
||||||
|
} |
||||||
|
} |
||||||
|
this._notCommitDrawImageCache = []; |
||||||
|
if (this._flush) { |
||||||
|
this._flush(reserve, callback); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
getImageData(x, y, w, h, callback) { |
||||||
|
CanvasRenderingContext2D.GBridge.getImageData(this.componentId, x, y, w, h, function(res) { |
||||||
|
res.data = Base64ToUint8ClampedArray(res.data); |
||||||
|
if (typeof(callback) == 'function') { |
||||||
|
callback(res); |
||||||
|
} |
||||||
|
}); |
||||||
|
} |
||||||
|
|
||||||
|
putImageData(data, x, y, w, h, callback) { |
||||||
|
if (data instanceof Uint8ClampedArray) { |
||||||
|
data = ArrayBufferToBase64(data); |
||||||
|
CanvasRenderingContext2D.GBridge.putImageData(this.componentId, data, x, y, w, h, function(res) { |
||||||
|
if (typeof(callback) == 'function') { |
||||||
|
callback(res); |
||||||
|
} |
||||||
|
}); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
toTempFilePath(x, y, width, height, destWidth, destHeight, fileType, quality, callback) { |
||||||
|
CanvasRenderingContext2D.GBridge.toTempFilePath(this.componentId, x, y, width, height, destWidth, destHeight, |
||||||
|
fileType, quality, |
||||||
|
function(res) { |
||||||
|
if (typeof(callback) == 'function') { |
||||||
|
callback(res); |
||||||
|
} |
||||||
|
}); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,11 @@ |
|||||||
|
export default class WebGLActiveInfo { |
||||||
|
className = 'WebGLActiveInfo'; |
||||||
|
|
||||||
|
constructor({ |
||||||
|
type, name, size |
||||||
|
}) { |
||||||
|
this.type = type; |
||||||
|
this.name = name; |
||||||
|
this.size = size; |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,21 @@ |
|||||||
|
import {getTransferedObjectUUID} from './classUtils'; |
||||||
|
|
||||||
|
const name = 'WebGLBuffer'; |
||||||
|
|
||||||
|
function uuid(id) { |
||||||
|
return getTransferedObjectUUID(name, id); |
||||||
|
} |
||||||
|
|
||||||
|
export default class WebGLBuffer { |
||||||
|
className = name; |
||||||
|
|
||||||
|
constructor(id) { |
||||||
|
this.id = id; |
||||||
|
} |
||||||
|
|
||||||
|
static uuid = uuid; |
||||||
|
|
||||||
|
uuid() { |
||||||
|
return uuid(this.id); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,21 @@ |
|||||||
|
import {getTransferedObjectUUID} from './classUtils'; |
||||||
|
|
||||||
|
const name = 'WebGLFrameBuffer'; |
||||||
|
|
||||||
|
function uuid(id) { |
||||||
|
return getTransferedObjectUUID(name, id); |
||||||
|
} |
||||||
|
|
||||||
|
export default class WebGLFramebuffer { |
||||||
|
className = name; |
||||||
|
|
||||||
|
constructor(id) { |
||||||
|
this.id = id; |
||||||
|
} |
||||||
|
|
||||||
|
static uuid = uuid; |
||||||
|
|
||||||
|
uuid() { |
||||||
|
return uuid(this.id); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,298 @@ |
|||||||
|
export default { |
||||||
|
"DEPTH_BUFFER_BIT": 256, |
||||||
|
"STENCIL_BUFFER_BIT": 1024, |
||||||
|
"COLOR_BUFFER_BIT": 16384, |
||||||
|
"POINTS": 0, |
||||||
|
"LINES": 1, |
||||||
|
"LINE_LOOP": 2, |
||||||
|
"LINE_STRIP": 3, |
||||||
|
"TRIANGLES": 4, |
||||||
|
"TRIANGLE_STRIP": 5, |
||||||
|
"TRIANGLE_FAN": 6, |
||||||
|
"ZERO": 0, |
||||||
|
"ONE": 1, |
||||||
|
"SRC_COLOR": 768, |
||||||
|
"ONE_MINUS_SRC_COLOR": 769, |
||||||
|
"SRC_ALPHA": 770, |
||||||
|
"ONE_MINUS_SRC_ALPHA": 771, |
||||||
|
"DST_ALPHA": 772, |
||||||
|
"ONE_MINUS_DST_ALPHA": 773, |
||||||
|
"DST_COLOR": 774, |
||||||
|
"ONE_MINUS_DST_COLOR": 775, |
||||||
|
"SRC_ALPHA_SATURATE": 776, |
||||||
|
"FUNC_ADD": 32774, |
||||||
|
"BLEND_EQUATION": 32777, |
||||||
|
"BLEND_EQUATION_RGB": 32777, |
||||||
|
"BLEND_EQUATION_ALPHA": 34877, |
||||||
|
"FUNC_SUBTRACT": 32778, |
||||||
|
"FUNC_REVERSE_SUBTRACT": 32779, |
||||||
|
"BLEND_DST_RGB": 32968, |
||||||
|
"BLEND_SRC_RGB": 32969, |
||||||
|
"BLEND_DST_ALPHA": 32970, |
||||||
|
"BLEND_SRC_ALPHA": 32971, |
||||||
|
"CONSTANT_COLOR": 32769, |
||||||
|
"ONE_MINUS_CONSTANT_COLOR": 32770, |
||||||
|
"CONSTANT_ALPHA": 32771, |
||||||
|
"ONE_MINUS_CONSTANT_ALPHA": 32772, |
||||||
|
"BLEND_COLOR": 32773, |
||||||
|
"ARRAY_BUFFER": 34962, |
||||||
|
"ELEMENT_ARRAY_BUFFER": 34963, |
||||||
|
"ARRAY_BUFFER_BINDING": 34964, |
||||||
|
"ELEMENT_ARRAY_BUFFER_BINDING": 34965, |
||||||
|
"STREAM_DRAW": 35040, |
||||||
|
"STATIC_DRAW": 35044, |
||||||
|
"DYNAMIC_DRAW": 35048, |
||||||
|
"BUFFER_SIZE": 34660, |
||||||
|
"BUFFER_USAGE": 34661, |
||||||
|
"CURRENT_VERTEX_ATTRIB": 34342, |
||||||
|
"FRONT": 1028, |
||||||
|
"BACK": 1029, |
||||||
|
"FRONT_AND_BACK": 1032, |
||||||
|
"TEXTURE_2D": 3553, |
||||||
|
"CULL_FACE": 2884, |
||||||
|
"BLEND": 3042, |
||||||
|
"DITHER": 3024, |
||||||
|
"STENCIL_TEST": 2960, |
||||||
|
"DEPTH_TEST": 2929, |
||||||
|
"SCISSOR_TEST": 3089, |
||||||
|
"POLYGON_OFFSET_FILL": 32823, |
||||||
|
"SAMPLE_ALPHA_TO_COVERAGE": 32926, |
||||||
|
"SAMPLE_COVERAGE": 32928, |
||||||
|
"NO_ERROR": 0, |
||||||
|
"INVALID_ENUM": 1280, |
||||||
|
"INVALID_VALUE": 1281, |
||||||
|
"INVALID_OPERATION": 1282, |
||||||
|
"OUT_OF_MEMORY": 1285, |
||||||
|
"CW": 2304, |
||||||
|
"CCW": 2305, |
||||||
|
"LINE_WIDTH": 2849, |
||||||
|
"ALIASED_POINT_SIZE_RANGE": 33901, |
||||||
|
"ALIASED_LINE_WIDTH_RANGE": 33902, |
||||||
|
"CULL_FACE_MODE": 2885, |
||||||
|
"FRONT_FACE": 2886, |
||||||
|
"DEPTH_RANGE": 2928, |
||||||
|
"DEPTH_WRITEMASK": 2930, |
||||||
|
"DEPTH_CLEAR_VALUE": 2931, |
||||||
|
"DEPTH_FUNC": 2932, |
||||||
|
"STENCIL_CLEAR_VALUE": 2961, |
||||||
|
"STENCIL_FUNC": 2962, |
||||||
|
"STENCIL_FAIL": 2964, |
||||||
|
"STENCIL_PASS_DEPTH_FAIL": 2965, |
||||||
|
"STENCIL_PASS_DEPTH_PASS": 2966, |
||||||
|
"STENCIL_REF": 2967, |
||||||
|
"STENCIL_VALUE_MASK": 2963, |
||||||
|
"STENCIL_WRITEMASK": 2968, |
||||||
|
"STENCIL_BACK_FUNC": 34816, |
||||||
|
"STENCIL_BACK_FAIL": 34817, |
||||||
|
"STENCIL_BACK_PASS_DEPTH_FAIL": 34818, |
||||||
|
"STENCIL_BACK_PASS_DEPTH_PASS": 34819, |
||||||
|
"STENCIL_BACK_REF": 36003, |
||||||
|
"STENCIL_BACK_VALUE_MASK": 36004, |
||||||
|
"STENCIL_BACK_WRITEMASK": 36005, |
||||||
|
"VIEWPORT": 2978, |
||||||
|
"SCISSOR_BOX": 3088, |
||||||
|
"COLOR_CLEAR_VALUE": 3106, |
||||||
|
"COLOR_WRITEMASK": 3107, |
||||||
|
"UNPACK_ALIGNMENT": 3317, |
||||||
|
"PACK_ALIGNMENT": 3333, |
||||||
|
"MAX_TEXTURE_SIZE": 3379, |
||||||
|
"MAX_VIEWPORT_DIMS": 3386, |
||||||
|
"SUBPIXEL_BITS": 3408, |
||||||
|
"RED_BITS": 3410, |
||||||
|
"GREEN_BITS": 3411, |
||||||
|
"BLUE_BITS": 3412, |
||||||
|
"ALPHA_BITS": 3413, |
||||||
|
"DEPTH_BITS": 3414, |
||||||
|
"STENCIL_BITS": 3415, |
||||||
|
"POLYGON_OFFSET_UNITS": 10752, |
||||||
|
"POLYGON_OFFSET_FACTOR": 32824, |
||||||
|
"TEXTURE_BINDING_2D": 32873, |
||||||
|
"SAMPLE_BUFFERS": 32936, |
||||||
|
"SAMPLES": 32937, |
||||||
|
"SAMPLE_COVERAGE_VALUE": 32938, |
||||||
|
"SAMPLE_COVERAGE_INVERT": 32939, |
||||||
|
"COMPRESSED_TEXTURE_FORMATS": 34467, |
||||||
|
"DONT_CARE": 4352, |
||||||
|
"FASTEST": 4353, |
||||||
|
"NICEST": 4354, |
||||||
|
"GENERATE_MIPMAP_HINT": 33170, |
||||||
|
"BYTE": 5120, |
||||||
|
"UNSIGNED_BYTE": 5121, |
||||||
|
"SHORT": 5122, |
||||||
|
"UNSIGNED_SHORT": 5123, |
||||||
|
"INT": 5124, |
||||||
|
"UNSIGNED_INT": 5125, |
||||||
|
"FLOAT": 5126, |
||||||
|
"DEPTH_COMPONENT": 6402, |
||||||
|
"ALPHA": 6406, |
||||||
|
"RGB": 6407, |
||||||
|
"RGBA": 6408, |
||||||
|
"LUMINANCE": 6409, |
||||||
|
"LUMINANCE_ALPHA": 6410, |
||||||
|
"UNSIGNED_SHORT_4_4_4_4": 32819, |
||||||
|
"UNSIGNED_SHORT_5_5_5_1": 32820, |
||||||
|
"UNSIGNED_SHORT_5_6_5": 33635, |
||||||
|
"FRAGMENT_SHADER": 35632, |
||||||
|
"VERTEX_SHADER": 35633, |
||||||
|
"MAX_VERTEX_ATTRIBS": 34921, |
||||||
|
"MAX_VERTEX_UNIFORM_VECTORS": 36347, |
||||||
|
"MAX_VARYING_VECTORS": 36348, |
||||||
|
"MAX_COMBINED_TEXTURE_IMAGE_UNITS": 35661, |
||||||
|
"MAX_VERTEX_TEXTURE_IMAGE_UNITS": 35660, |
||||||
|
"MAX_TEXTURE_IMAGE_UNITS": 34930, |
||||||
|
"MAX_FRAGMENT_UNIFORM_VECTORS": 36349, |
||||||
|
"SHADER_TYPE": 35663, |
||||||
|
"DELETE_STATUS": 35712, |
||||||
|
"LINK_STATUS": 35714, |
||||||
|
"VALIDATE_STATUS": 35715, |
||||||
|
"ATTACHED_SHADERS": 35717, |
||||||
|
"ACTIVE_UNIFORMS": 35718, |
||||||
|
"ACTIVE_ATTRIBUTES": 35721, |
||||||
|
"SHADING_LANGUAGE_VERSION": 35724, |
||||||
|
"CURRENT_PROGRAM": 35725, |
||||||
|
"NEVER": 512, |
||||||
|
"LESS": 513, |
||||||
|
"EQUAL": 514, |
||||||
|
"LEQUAL": 515, |
||||||
|
"GREATER": 516, |
||||||
|
"NOTEQUAL": 517, |
||||||
|
"GEQUAL": 518, |
||||||
|
"ALWAYS": 519, |
||||||
|
"KEEP": 7680, |
||||||
|
"REPLACE": 7681, |
||||||
|
"INCR": 7682, |
||||||
|
"DECR": 7683, |
||||||
|
"INVERT": 5386, |
||||||
|
"INCR_WRAP": 34055, |
||||||
|
"DECR_WRAP": 34056, |
||||||
|
"VENDOR": 7936, |
||||||
|
"RENDERER": 7937, |
||||||
|
"VERSION": 7938, |
||||||
|
"NEAREST": 9728, |
||||||
|
"LINEAR": 9729, |
||||||
|
"NEAREST_MIPMAP_NEAREST": 9984, |
||||||
|
"LINEAR_MIPMAP_NEAREST": 9985, |
||||||
|
"NEAREST_MIPMAP_LINEAR": 9986, |
||||||
|
"LINEAR_MIPMAP_LINEAR": 9987, |
||||||
|
"TEXTURE_MAG_FILTER": 10240, |
||||||
|
"TEXTURE_MIN_FILTER": 10241, |
||||||
|
"TEXTURE_WRAP_S": 10242, |
||||||
|
"TEXTURE_WRAP_T": 10243, |
||||||
|
"TEXTURE": 5890, |
||||||
|
"TEXTURE_CUBE_MAP": 34067, |
||||||
|
"TEXTURE_BINDING_CUBE_MAP": 34068, |
||||||
|
"TEXTURE_CUBE_MAP_POSITIVE_X": 34069, |
||||||
|
"TEXTURE_CUBE_MAP_NEGATIVE_X": 34070, |
||||||
|
"TEXTURE_CUBE_MAP_POSITIVE_Y": 34071, |
||||||
|
"TEXTURE_CUBE_MAP_NEGATIVE_Y": 34072, |
||||||
|
"TEXTURE_CUBE_MAP_POSITIVE_Z": 34073, |
||||||
|
"TEXTURE_CUBE_MAP_NEGATIVE_Z": 34074, |
||||||
|
"MAX_CUBE_MAP_TEXTURE_SIZE": 34076, |
||||||
|
"TEXTURE0": 33984, |
||||||
|
"TEXTURE1": 33985, |
||||||
|
"TEXTURE2": 33986, |
||||||
|
"TEXTURE3": 33987, |
||||||
|
"TEXTURE4": 33988, |
||||||
|
"TEXTURE5": 33989, |
||||||
|
"TEXTURE6": 33990, |
||||||
|
"TEXTURE7": 33991, |
||||||
|
"TEXTURE8": 33992, |
||||||
|
"TEXTURE9": 33993, |
||||||
|
"TEXTURE10": 33994, |
||||||
|
"TEXTURE11": 33995, |
||||||
|
"TEXTURE12": 33996, |
||||||
|
"TEXTURE13": 33997, |
||||||
|
"TEXTURE14": 33998, |
||||||
|
"TEXTURE15": 33999, |
||||||
|
"TEXTURE16": 34000, |
||||||
|
"TEXTURE17": 34001, |
||||||
|
"TEXTURE18": 34002, |
||||||
|
"TEXTURE19": 34003, |
||||||
|
"TEXTURE20": 34004, |
||||||
|
"TEXTURE21": 34005, |
||||||
|
"TEXTURE22": 34006, |
||||||
|
"TEXTURE23": 34007, |
||||||
|
"TEXTURE24": 34008, |
||||||
|
"TEXTURE25": 34009, |
||||||
|
"TEXTURE26": 34010, |
||||||
|
"TEXTURE27": 34011, |
||||||
|
"TEXTURE28": 34012, |
||||||
|
"TEXTURE29": 34013, |
||||||
|
"TEXTURE30": 34014, |
||||||
|
"TEXTURE31": 34015, |
||||||
|
"ACTIVE_TEXTURE": 34016, |
||||||
|
"REPEAT": 10497, |
||||||
|
"CLAMP_TO_EDGE": 33071, |
||||||
|
"MIRRORED_REPEAT": 33648, |
||||||
|
"FLOAT_VEC2": 35664, |
||||||
|
"FLOAT_VEC3": 35665, |
||||||
|
"FLOAT_VEC4": 35666, |
||||||
|
"INT_VEC2": 35667, |
||||||
|
"INT_VEC3": 35668, |
||||||
|
"INT_VEC4": 35669, |
||||||
|
"BOOL": 35670, |
||||||
|
"BOOL_VEC2": 35671, |
||||||
|
"BOOL_VEC3": 35672, |
||||||
|
"BOOL_VEC4": 35673, |
||||||
|
"FLOAT_MAT2": 35674, |
||||||
|
"FLOAT_MAT3": 35675, |
||||||
|
"FLOAT_MAT4": 35676, |
||||||
|
"SAMPLER_2D": 35678, |
||||||
|
"SAMPLER_CUBE": 35680, |
||||||
|
"VERTEX_ATTRIB_ARRAY_ENABLED": 34338, |
||||||
|
"VERTEX_ATTRIB_ARRAY_SIZE": 34339, |
||||||
|
"VERTEX_ATTRIB_ARRAY_STRIDE": 34340, |
||||||
|
"VERTEX_ATTRIB_ARRAY_TYPE": 34341, |
||||||
|
"VERTEX_ATTRIB_ARRAY_NORMALIZED": 34922, |
||||||
|
"VERTEX_ATTRIB_ARRAY_POINTER": 34373, |
||||||
|
"VERTEX_ATTRIB_ARRAY_BUFFER_BINDING": 34975, |
||||||
|
"IMPLEMENTATION_COLOR_READ_TYPE": 35738, |
||||||
|
"IMPLEMENTATION_COLOR_READ_FORMAT": 35739, |
||||||
|
"COMPILE_STATUS": 35713, |
||||||
|
"LOW_FLOAT": 36336, |
||||||
|
"MEDIUM_FLOAT": 36337, |
||||||
|
"HIGH_FLOAT": 36338, |
||||||
|
"LOW_INT": 36339, |
||||||
|
"MEDIUM_INT": 36340, |
||||||
|
"HIGH_INT": 36341, |
||||||
|
"FRAMEBUFFER": 36160, |
||||||
|
"RENDERBUFFER": 36161, |
||||||
|
"RGBA4": 32854, |
||||||
|
"RGB5_A1": 32855, |
||||||
|
"RGB565": 36194, |
||||||
|
"DEPTH_COMPONENT16": 33189, |
||||||
|
"STENCIL_INDEX8": 36168, |
||||||
|
"DEPTH_STENCIL": 34041, |
||||||
|
"RENDERBUFFER_WIDTH": 36162, |
||||||
|
"RENDERBUFFER_HEIGHT": 36163, |
||||||
|
"RENDERBUFFER_INTERNAL_FORMAT": 36164, |
||||||
|
"RENDERBUFFER_RED_SIZE": 36176, |
||||||
|
"RENDERBUFFER_GREEN_SIZE": 36177, |
||||||
|
"RENDERBUFFER_BLUE_SIZE": 36178, |
||||||
|
"RENDERBUFFER_ALPHA_SIZE": 36179, |
||||||
|
"RENDERBUFFER_DEPTH_SIZE": 36180, |
||||||
|
"RENDERBUFFER_STENCIL_SIZE": 36181, |
||||||
|
"FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE": 36048, |
||||||
|
"FRAMEBUFFER_ATTACHMENT_OBJECT_NAME": 36049, |
||||||
|
"FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL": 36050, |
||||||
|
"FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE": 36051, |
||||||
|
"COLOR_ATTACHMENT0": 36064, |
||||||
|
"DEPTH_ATTACHMENT": 36096, |
||||||
|
"STENCIL_ATTACHMENT": 36128, |
||||||
|
"DEPTH_STENCIL_ATTACHMENT": 33306, |
||||||
|
"NONE": 0, |
||||||
|
"FRAMEBUFFER_COMPLETE": 36053, |
||||||
|
"FRAMEBUFFER_INCOMPLETE_ATTACHMENT": 36054, |
||||||
|
"FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT": 36055, |
||||||
|
"FRAMEBUFFER_INCOMPLETE_DIMENSIONS": 36057, |
||||||
|
"FRAMEBUFFER_UNSUPPORTED": 36061, |
||||||
|
"FRAMEBUFFER_BINDING": 36006, |
||||||
|
"RENDERBUFFER_BINDING": 36007, |
||||||
|
"MAX_RENDERBUFFER_SIZE": 34024, |
||||||
|
"INVALID_FRAMEBUFFER_OPERATION": 1286, |
||||||
|
"UNPACK_FLIP_Y_WEBGL": 37440, |
||||||
|
"UNPACK_PREMULTIPLY_ALPHA_WEBGL": 37441, |
||||||
|
"CONTEXT_LOST_WEBGL": 37442, |
||||||
|
"UNPACK_COLORSPACE_CONVERSION_WEBGL": 37443, |
||||||
|
"BROWSER_DEFAULT_WEBGL": 37444 |
||||||
|
}; |
@ -0,0 +1,142 @@ |
|||||||
|
let i = 1; |
||||||
|
|
||||||
|
const GLmethod = {}; |
||||||
|
|
||||||
|
GLmethod.activeTexture = i++; //1
|
||||||
|
GLmethod.attachShader = i++; |
||||||
|
GLmethod.bindAttribLocation = i++; |
||||||
|
GLmethod.bindBuffer = i++; |
||||||
|
GLmethod.bindFramebuffer = i++; |
||||||
|
GLmethod.bindRenderbuffer = i++; |
||||||
|
GLmethod.bindTexture = i++; |
||||||
|
GLmethod.blendColor = i++; |
||||||
|
GLmethod.blendEquation = i++; |
||||||
|
GLmethod.blendEquationSeparate = i++; //10
|
||||||
|
GLmethod.blendFunc = i++; |
||||||
|
GLmethod.blendFuncSeparate = i++; |
||||||
|
GLmethod.bufferData = i++; |
||||||
|
GLmethod.bufferSubData = i++; |
||||||
|
GLmethod.checkFramebufferStatus = i++; |
||||||
|
GLmethod.clear = i++; |
||||||
|
GLmethod.clearColor = i++; |
||||||
|
GLmethod.clearDepth = i++; |
||||||
|
GLmethod.clearStencil = i++; |
||||||
|
GLmethod.colorMask = i++; //20
|
||||||
|
GLmethod.compileShader = i++; |
||||||
|
GLmethod.compressedTexImage2D = i++; |
||||||
|
GLmethod.compressedTexSubImage2D = i++; |
||||||
|
GLmethod.copyTexImage2D = i++; |
||||||
|
GLmethod.copyTexSubImage2D = i++; |
||||||
|
GLmethod.createBuffer = i++; |
||||||
|
GLmethod.createFramebuffer = i++; |
||||||
|
GLmethod.createProgram = i++; |
||||||
|
GLmethod.createRenderbuffer = i++; |
||||||
|
GLmethod.createShader = i++; //30
|
||||||
|
GLmethod.createTexture = i++; |
||||||
|
GLmethod.cullFace = i++; |
||||||
|
GLmethod.deleteBuffer = i++; |
||||||
|
GLmethod.deleteFramebuffer = i++; |
||||||
|
GLmethod.deleteProgram = i++; |
||||||
|
GLmethod.deleteRenderbuffer = i++; |
||||||
|
GLmethod.deleteShader = i++; |
||||||
|
GLmethod.deleteTexture = i++; |
||||||
|
GLmethod.depthFunc = i++; |
||||||
|
GLmethod.depthMask = i++; //40
|
||||||
|
GLmethod.depthRange = i++; |
||||||
|
GLmethod.detachShader = i++; |
||||||
|
GLmethod.disable = i++; |
||||||
|
GLmethod.disableVertexAttribArray = i++; |
||||||
|
GLmethod.drawArrays = i++; |
||||||
|
GLmethod.drawArraysInstancedANGLE = i++; |
||||||
|
GLmethod.drawElements = i++; |
||||||
|
GLmethod.drawElementsInstancedANGLE = i++; |
||||||
|
GLmethod.enable = i++; |
||||||
|
GLmethod.enableVertexAttribArray = i++; //50
|
||||||
|
GLmethod.flush = i++; |
||||||
|
GLmethod.framebufferRenderbuffer = i++; |
||||||
|
GLmethod.framebufferTexture2D = i++; |
||||||
|
GLmethod.frontFace = i++; |
||||||
|
GLmethod.generateMipmap = i++; |
||||||
|
GLmethod.getActiveAttrib = i++; |
||||||
|
GLmethod.getActiveUniform = i++; |
||||||
|
GLmethod.getAttachedShaders = i++; |
||||||
|
GLmethod.getAttribLocation = i++; |
||||||
|
GLmethod.getBufferParameter = i++; //60
|
||||||
|
GLmethod.getContextAttributes = i++; |
||||||
|
GLmethod.getError = i++; |
||||||
|
GLmethod.getExtension = i++; |
||||||
|
GLmethod.getFramebufferAttachmentParameter = i++; |
||||||
|
GLmethod.getParameter = i++; |
||||||
|
GLmethod.getProgramInfoLog = i++; |
||||||
|
GLmethod.getProgramParameter = i++; |
||||||
|
GLmethod.getRenderbufferParameter = i++; |
||||||
|
GLmethod.getShaderInfoLog = i++; |
||||||
|
GLmethod.getShaderParameter = i++; //70
|
||||||
|
GLmethod.getShaderPrecisionFormat = i++; |
||||||
|
GLmethod.getShaderSource = i++; |
||||||
|
GLmethod.getSupportedExtensions = i++; |
||||||
|
GLmethod.getTexParameter = i++; |
||||||
|
GLmethod.getUniform = i++; |
||||||
|
GLmethod.getUniformLocation = i++; |
||||||
|
GLmethod.getVertexAttrib = i++; |
||||||
|
GLmethod.getVertexAttribOffset = i++; |
||||||
|
GLmethod.isBuffer = i++; |
||||||
|
GLmethod.isContextLost = i++; //80
|
||||||
|
GLmethod.isEnabled = i++; |
||||||
|
GLmethod.isFramebuffer = i++; |
||||||
|
GLmethod.isProgram = i++; |
||||||
|
GLmethod.isRenderbuffer = i++; |
||||||
|
GLmethod.isShader = i++; |
||||||
|
GLmethod.isTexture = i++; |
||||||
|
GLmethod.lineWidth = i++; |
||||||
|
GLmethod.linkProgram = i++; |
||||||
|
GLmethod.pixelStorei = i++; |
||||||
|
GLmethod.polygonOffset = i++; //90
|
||||||
|
GLmethod.readPixels = i++; |
||||||
|
GLmethod.renderbufferStorage = i++; |
||||||
|
GLmethod.sampleCoverage = i++; |
||||||
|
GLmethod.scissor = i++; |
||||||
|
GLmethod.shaderSource = i++; |
||||||
|
GLmethod.stencilFunc = i++; |
||||||
|
GLmethod.stencilFuncSeparate = i++; |
||||||
|
GLmethod.stencilMask = i++; |
||||||
|
GLmethod.stencilMaskSeparate = i++; |
||||||
|
GLmethod.stencilOp = i++; //100
|
||||||
|
GLmethod.stencilOpSeparate = i++; |
||||||
|
GLmethod.texImage2D = i++; |
||||||
|
GLmethod.texParameterf = i++; |
||||||
|
GLmethod.texParameteri = i++; |
||||||
|
GLmethod.texSubImage2D = i++; |
||||||
|
GLmethod.uniform1f = i++; |
||||||
|
GLmethod.uniform1fv = i++; |
||||||
|
GLmethod.uniform1i = i++; |
||||||
|
GLmethod.uniform1iv = i++; |
||||||
|
GLmethod.uniform2f = i++; //110
|
||||||
|
GLmethod.uniform2fv = i++; |
||||||
|
GLmethod.uniform2i = i++; |
||||||
|
GLmethod.uniform2iv = i++; |
||||||
|
GLmethod.uniform3f = i++; |
||||||
|
GLmethod.uniform3fv = i++; |
||||||
|
GLmethod.uniform3i = i++; |
||||||
|
GLmethod.uniform3iv = i++; |
||||||
|
GLmethod.uniform4f = i++; |
||||||
|
GLmethod.uniform4fv = i++; |
||||||
|
GLmethod.uniform4i = i++; //120
|
||||||
|
GLmethod.uniform4iv = i++; |
||||||
|
GLmethod.uniformMatrix2fv = i++; |
||||||
|
GLmethod.uniformMatrix3fv = i++; |
||||||
|
GLmethod.uniformMatrix4fv = i++; |
||||||
|
GLmethod.useProgram = i++; |
||||||
|
GLmethod.validateProgram = i++; |
||||||
|
GLmethod.vertexAttrib1f = i++; //new
|
||||||
|
GLmethod.vertexAttrib2f = i++; //new
|
||||||
|
GLmethod.vertexAttrib3f = i++; //new
|
||||||
|
GLmethod.vertexAttrib4f = i++; //new //130
|
||||||
|
GLmethod.vertexAttrib1fv = i++; //new
|
||||||
|
GLmethod.vertexAttrib2fv = i++; //new
|
||||||
|
GLmethod.vertexAttrib3fv = i++; //new
|
||||||
|
GLmethod.vertexAttrib4fv = i++; //new
|
||||||
|
GLmethod.vertexAttribPointer = i++; |
||||||
|
GLmethod.viewport = i++; |
||||||
|
|
||||||
|
export default GLmethod; |
@ -0,0 +1,23 @@ |
|||||||
|
const GLtype = {}; |
||||||
|
|
||||||
|
[ |
||||||
|
"GLbitfield",
|
||||||
|
"GLboolean", |
||||||
|
"GLbyte", |
||||||
|
"GLclampf", |
||||||
|
"GLenum", |
||||||
|
"GLfloat", |
||||||
|
"GLint", |
||||||
|
"GLintptr", |
||||||
|
"GLsizei", |
||||||
|
"GLsizeiptr", |
||||||
|
"GLshort", |
||||||
|
"GLubyte", |
||||||
|
"GLuint", |
||||||
|
"GLushort" |
||||||
|
].sort().map((typeName, i) => GLtype[typeName] = 1 >> (i + 1)); |
||||||
|
|
||||||
|
export default GLtype; |
||||||
|
|
||||||
|
|
||||||
|
|
@ -0,0 +1,21 @@ |
|||||||
|
import {getTransferedObjectUUID} from './classUtils'; |
||||||
|
|
||||||
|
const name = 'WebGLProgram'; |
||||||
|
|
||||||
|
function uuid(id) { |
||||||
|
return getTransferedObjectUUID(name, id); |
||||||
|
} |
||||||
|
|
||||||
|
export default class WebGLProgram { |
||||||
|
className = name; |
||||||
|
|
||||||
|
constructor(id) { |
||||||
|
this.id = id; |
||||||
|
} |
||||||
|
|
||||||
|
static uuid = uuid; |
||||||
|
|
||||||
|
uuid() { |
||||||
|
return uuid(this.id); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,21 @@ |
|||||||
|
import {getTransferedObjectUUID} from './classUtils'; |
||||||
|
|
||||||
|
const name = 'WebGLRenderBuffer'; |
||||||
|
|
||||||
|
function uuid(id) { |
||||||
|
return getTransferedObjectUUID(name, id); |
||||||
|
} |
||||||
|
|
||||||
|
export default class WebGLRenderbuffer { |
||||||
|
className = name; |
||||||
|
|
||||||
|
constructor(id) { |
||||||
|
this.id = id; |
||||||
|
} |
||||||
|
|
||||||
|
static uuid = uuid; |
||||||
|
|
||||||
|
uuid() { |
||||||
|
return uuid(this.id); |
||||||
|
} |
||||||
|
} |