This commit is contained in:
mkm 2023-07-15 17:51:20 +08:00
parent 67f00bf81f
commit 96dcae61ae
846 changed files with 97268 additions and 129 deletions

26
.gitignore vendored Normal file
View File

@ -0,0 +1,26 @@
.DS_Store
node_modules
/dist
.hbuilderx
# local env files
.env.local
.env.*.local
# Log files
npm-debug.log*
yarn-debug.log*
yarn-error.log*
# Editor directories and files
.idea
.vscode
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?
build.sh
.idea
unpackage
*.bak

30
App.vue
View File

@ -1,17 +1,23 @@
<script>
export default {
onLaunch: function() {
console.log('App Launch')
},
onShow: function() {
console.log('App Show')
},
onHide: function() {
console.log('App Hide')
}
}
export default {
onLaunch: function() {
console.log('App Launch')
},
onShow: function() {
console.log('App Show')
},
onHide: function() {
console.log('App Hide')
}
}
</script>
<style>
/*每个页面公共css */
/*每个页面公共css */
@import 'static/css/base.css';
@import 'static/css/style.scss';
view {
box-sizing: border-box;
}
</style>

21
api/oa.js Normal file
View File

@ -0,0 +1,21 @@
import oahttp from "@/utils/oahttp.js";
//获取代办事项 已处理事项
export const getMatters = (data) => oahttp.get('/approve/list', data, { noAuth: true })
//获取任务列表
export const getTaskListApi = (data) => oahttp.get('/task/list', data)
//获取 我发起的审批
export const getExamineListApi = () => oahttp.get('/approve/my_list')
//获取工资详情信息
export const getSalaryDeatilsApi = () => oahttp.get('/user/info')
//获取部门
export const getDepartmentApi = () => oahttp.get('/index/get_department_tree')
//获取部门人员
export const getDepartmentPersonApi = (data) => oahttp.get('/index/get_employee', data)
//新建任务
export const addNewTaskApi = (data) => oahttp.post('/task/add', data)
//获取文档列表
export const getDocumentListApi = (data) => oahttp.get('/knowledge/list', data)
//获取个人信息
export const getPersonInfoApi = () => oahttp.get('/user/index')

60
api/oaApi.js Normal file
View File

@ -0,0 +1,60 @@
import oahttp from "@/utils/oahttp.js";
/**
* 获取代办事项 已处理事项
*/
export const getIndexListAPI = (data) => oahttp.get('/index/list', data)
/**
* 获取任务列表
*/
export const getTaskListAPI = (data) => oahttp.get('/task/list', data)
/**
* 获取我的任务
*/
export const getMyTaskListAPI = (data) => oahttp.get('/task/datalist', data)
/**
* 获取任务详情
*/
export const getTaskDetailsAPI = (data) => oahttp.get('/task/read', data)
/**
* 我发起的审批
*/
export const getApproveMyListAPI = (data) => oahttp.get('/approve/my_list', data)
/**
* 我审批的
*/
export const getHandleListAPI = (data) => oahttp.get('/approve/handle_list', data)
/**
* 抄送给我的
*/
export const getCopyOfMyListAPI = (data) => oahttp.get('/approve/copy', data)
/*
* 待办事项
*/
export const getApproveListAPI = (data) => oahttp.get('/approve/list', data)
/**
* 获取个人中心数据
*/
export const getUserIndexAPI = (data) => oahttp.get('/user/index', data)
/**
* 保存个人信息修改
*/
export const PostUserPerSubmitAPI = (data) => oahttp.post('/user/personal_submit', data)
/**
* 获取审核流程
* index/get_flow?type=1
*/
export const getFlowAPI = (data) => oahttp.get('/index/get_flow', data)
/**
* 获取审核步骤人员
*/
export const getFlowUsersAPI = (data) => oahttp.get('/index/get_flow_users', data, { noVerify: true })
/** 获取部门树形节点列表 */
export const getDepartmentTreeAPI = () => oahttp.get('/index/get_department_tree')
/** 获取某个部门的员工 */
export const getEmployeeAPI = (data) => oahttp.get('/index/get_employee', data)
/** 发起审批 */
export const PostApproveAddAPI = (data) => oahttp.post('/approve/add', data)

17
api/pubic.js Normal file
View File

@ -0,0 +1,17 @@
import request from '@/utils/request.js'
export function commonAuth(data) {
return request.post(
"auth", data, {
noAuth: true
}
);
}
/**
* 小程序用户登录
* @param data object 小程序用户登陆信息
*/
export function login(data) {
return request.post("auth/mp", data, {
noAuth: true
});
}

59
api/upload.js Normal file
View File

@ -0,0 +1,59 @@
// import base from "@/config/baseUrl";
// let baseUrl = 'https://ceshi.excellentkk.cn/api';
import { HTTP_REQUEST_URL_TWO, HTTP_REQUEST_URL_THREE, HEADER } from '@/config/app';
let header = HEADER;
function uploads(src, type) {
return new Promise((resolve, reject) => {
// console.log('上传', type === 'img' ? '图片' : '视频', '', src)
let a = uni.uploadFile({
// url: base.baseUrl + '/upload?token=',
url: HTTP_REQUEST_URL_TWO + '/api' + '/upload?token=',
filePath: src,
name: 'file',
success: (res) => {
let data = JSON.parse(res.data)
if (data.code != 1) {
uni.$u.toast(data.msg)
return false
} else {
resolve(data.data.url) // 返回线上地址
}
},
fail: (err) => {
reject(err)
console.log('upload-上传失败', err)
}
});
})
}
function oaUploads(src, type) {
return new Promise((resolve, reject) => {
// console.log('上传', type === 'img' ? '图片' : '视频', '', src)
let a = uni.uploadFile({
url: HTTP_REQUEST_URL_THREE + '/api/v1/index/upload',
filePath: src,
name: 'file',
header: header,
success: (res) => {
let data = JSON.parse(res.data)
if (data.code == 200) {
resolve(data.data) // 返回线上地址
} else {
uni.$u.toast(data.msg)
return false
}
},
fail: (err) => {
reject(err)
console.log('upload-上传失败', err)
}
});
})
}
export {
uploads,
oaUploads
}

743
api/user.js Normal file
View File

@ -0,0 +1,743 @@
import request from "@/utils/request.js";
import Cache from '@/utils/cache'
import http from "@/utils/http.js";
/**
* 获取后台账号密码
*/
export const getBackstageAPI = (data) => http.get('/User/get_backstage', data)
// 获取已录入公司
export const getEnterListMsgAPI = (data) => http.get('/enter/list', data)
// 录入公司
export const postEntercompanyAPI = (data) => request.post('entercompany', data)
// 获取地址
export const getSiteAPI = (data) => http.get('/User/index', data)
export const getShimingAPI = (data) => http.get('/User/get_shiming', data)
export const postRealnameAPI = (data) => http.post('/User/realname', data)
/**
* 获取用户信息
*
*/
export function getUserInfo() {
return request.get('user');
}
/**
* 头像
*
*/
export function editAvatar(data) {
return request.post('user/change/info', data);
}
// 修改昵称
export function updateInfo(data) {
return request.post('user/change/avatar', data);
}
/**
* h5用户登录
* @param data object 用户账号密码
*/
export function loginH5(data) {
return request.post("auth/login", data, {
noAuth: true
});
}
/**
* h5用户手机号登录
* @param data object 用户手机号 也只能
*/
export function loginMobile(data) {
return request.post("auth/smslogin", data, {
noAuth: true
});
}
/**
* h5用户手机号登录
* @param data object 用户手机号 也只能
*/
export function loginMpPhone(data) {
return request.post("auth/mp_phone", data, {
noAuth: true
});
}
/**
* 验证码key
*/
export function getCodeApi() {
return request.get("verify_code", {}, {
noAuth: true
});
}
/**
* h5用户发送验证码
* @param data object 用户手机号
*/
export function registerVerify(data) {
return request.post("auth/verify", data, {
noAuth: true
});
}
/**
* h5用户手机号注册
* @param data object 用户手机号 验证码 密码
*/
export function register(data) {
return request.post("auth/register", data, {
noAuth: true
});
}
/**
* 用户手机号修改密码
* @param data object 用户手机号 验证码 密码
*/
export function registerReset(data) {
return request.post("/register/reset", data, {
noAuth: true
});
}
/**
* 用户手机号忘记密码
*/
export function registerForget(data) {
return request.post("user/change_pwd", data, {
noAuth: true
});
}
/**
* 获取用户中心菜单
*
*/
export function getMenuList() {
return request.get("common/menus", {}, {
noAuth: true
});
}
/*
* 签到用户信息
* */
export function getSignUser() {
return request.get("user/sign/info");
}
/**
* 获取签到配置
*
*/
export function getSignConfig() {
return request.get('sign/config')
}
/**
* 获取签到列表
* @param object data
*/
export function getSignList(data) {
return request.get('user/sign/lst', data);
}
/**
* 用户签到
*/
export function setSignIntegral() {
return request.post('user/sign/create')
}
/**
* 签到列表(年月)
* @param object data
*
*/
export function getSignMonthList(data) {
return request.get('user/sign/month', data)
}
/**
* 活动状态
*
*/
export function userActivity() {
return request.get('user/activity');
}
/*
* 资金明细types|0=全部,1=消费,2=充值,3=返佣
* */
export function getCommissionInfo(q, types) {
return request.get("user/bill", q);
}
/*
* 提现列表
* */
export function extractLst(data) {
return request.get("user/extract/lst", data);
}
/*
* 积分记录
* */
export function getIntegralList(data) {
return request.get("user/integral/lst", data);
}
/**
* 获取分销海报图片
*
*/
export function spreadBanner() {
//#ifdef H5
return request.get('user/spread_image', {
type: 'wechat'
});
//#endif
//#ifdef MP
return request.get('user/spread_image', {
type: 'routine'
});
//#endif
}
/**
*
* 获取推广用户一级和二级
* @param object data
*/
export function spreadPeople(data) {
return request.get('user/spread_list', data);
}
/**
*
* 推广佣金/提现总和
* @param int type
*/
export function spreadCount(type) {
return request.get('spread/count/' + type);
}
/*
* 推广数据
* */
export function getSpreadInfo() {
return request.get("/commission");
}
/**
*
* 推广订单
* @param object data
*/
export function spreadOrder(data) {
return request.get('user/spread_order', data);
}
/*
* 获取推广人排行
* */
export function getRankList(data) {
return request.get("user/spread_top", data);
}
/*
* 获取佣金排名
* */
export function getBrokerageRank(q) {
return request.get("user/brokerage_top", q);
}
/**
* 提现申请
* @param object data
*/
export function extractCash(data) {
return request.post('user/extract/create', data)
}
/**
* 提现银行/提现最低金额
*
*/
export function extractBank() {
return request.get('user/extract/banklst');
}
/**
* 会员等级列表
*
*/
export function userLevelGrade() {
return request.get('user/level/grade');
}
/**
* 获取某个等级任务
* @param int id 任务id
*/
export function userLevelTask(id) {
return request.get('user/level/task/' + id);
}
/**
* 检查用户是否可以成为会员
*
*/
export function userLevelDetection() {
return request.get('user/level/detection');
}
/**
*
* 地址列表
* @param object data
*/
export function getAddressList(data) {
return request.get('user/address/lst', data);
}
/**
* 设置默认地址
* @param int id
*/
export function setAddressDefault(id) {
return request.post('user/address/update/' + id)
}
/**
* 修改 添加地址
* @param object data
*/
export function editAddress(data) {
return request.post('user/address/create', data);
}
/**
* 删除地址
* @param int id
*
*/
export function delAddress(id) {
return request.post('user/address/delete/' + id)
}
/**
* 获取单个地址
* @param int id
*/
export function getAddressDetail(id) {
return request.get('user/address/detail/' + id);
}
/**
* 修改用户信息
* @param object
*/
export function userEdit(data) {
return request.post('user/edit', data);
}
/*
* 退出登录
* */
export function getLogout() {
return request.post("logout");
}
/**
* 佣金转入
*
*/
export function rechargeBrokerage(data) {
return request.post('user/recharge/brokerage', data)
}
/**
* 小程序充值
*
*/
export function rechargeRoutine(data) {
return request.post('recharge/routine', data)
}
/*
* 公众号充值
* */
export function rechargeWechat(data) {
return request.post("user/recharge", data);
}
/**
* 获取默认地址
*
*/
export function getAddressDefault() {
return request.get('address/default');
}
/**
* 充值金额选择
*/
export function getRechargeApi() {
return request.get("common/recharge_quota");
}
/**
* 登陆记录
*/
export function setVisit(data) {
return request.post('user/set_visit', {
...data
}, {
noAuth: true
});
}
/**
* 客服列表
*/
export function serviceList(data) {
return request.get("service/list", data);
}
/**
* 客服列表
*/
export function serviceLogin(key, data) {
return request.post("service/scan_login/" + key, data);
}
/**
* 客服获取客户列表
*/
export function serviceUserList(mer_id, data) {
return request.get("service/user_list/" + mer_id, data);
}
/**
* 用户获取聊天记录详情
*/
export function getChatRecord(to_uid, data) {
return request.get("service/history/" + to_uid, data);
}
/**
* 客服获取聊天记录详情
*/
export function getMerHistory(userid, mer_id, data) {
return request.get("service/mer_history/" + mer_id + '/' + userid, data);
}
/**
* 静默绑定推广人
* @param {Object} puid
*/
export function spread(puid) {
Cache.set("spread", puid || 0);
return request.post("user/spread", {
spread_spid: puid
});
}
/**
* 反馈类型
*/
export function feedbackType() {
return request.get("common/feedback_type");
}
/**
* 提交反馈
*/
export function feedback(data) {
return request.post("user/feedback", {
...data
});
}
/**
* 反馈列表
*/
export function feedbackList(data) {
return request.get("user/feedback/list", data);
}
/**
* 反馈列表
*/
export function feedbackDetail(id) {
return request.get("user/feedback/detail/" + id);
}
/**
* 浏览记录
*/
export function historyList(data) {
return request.get("user/history", data);
}
/**
* 删除浏览记录
*/
export function historyDelete(id) {
return request.post("user/history/delete/" + id);
}
/**
* 批量删除浏览记录
*/
export function historyBatchDelete(data) {
return request.post("user/history/batch/delete", data);
}
/**
* 批量收藏浏览记录
*/
export function historyBatchCollect(data) {
return request.post("user/relation/batch/create", data);
}
/**
* 佣金记录
*/
export function brokerage_list(data) {
return request.get("user/brokerage_list", data);
}
/**
* 佣金数据
*/
export function spreadInfo(data) {
return request.get("user/spread_info", data);
}
// 图片验证码
export function getCaptcha() {
return request.get('captcha', {}, {
noAuth: true
});
}
// 用户账户列表
export function userAcc() {
return request.get('user/account', {}, {
noAuth: true
});
}
// 创建发票
export function invoiceSave(data) {
return request.post('user/receipt/create', data);
}
// 编辑发票
export function invoiceUpdate(id, data) {
return request.post('user/receipt/update/' + id, data);
}
// 获取默认发票
export function invoiceDefault(id) {
return request.post('user/receipt/is_default/' + id);
}
// 发票抬头--列表
export function invoice(data) {
return request.get('user/receipt/lst', data);
}
// 发票抬头--删除
export function invoiceDelete(id) {
return request.post('user/receipt/delete/' + id);
}
// 发票--详情
export function invoiceDetail(id) {
return request.get('user/receipt/detail/' + id);
}
/**
* 新版分享海报信息获取
*
*/
export function spreadMsg(data) {
return request.get('user/v2/spread_image', data);
}
/**
* 图片链接转base64
*
*/
export function imgToBase(data) {
return request.post('common/base64', data);
}
/**
* 获取协议
*
*/
export function getAgreementApi(key) {
return request.get('agreement/' + key, {}, {
noAuth: true
});
}
/**
* 获取协议
*
*/
export function getIntegralInfo() {
return request.get('user/integral/info');
}
/**
* 获取店铺列表
*
*/
export function getStoreList(data) {
return request.get('user/services', data);
}
/*
获取佣金说明
*/
export function commissionDescription() {
return request.get('agreement/sys_extension_agree')
}
/*
获取用户分销等级信息
*/
export function getBrokerageInfo() {
return request.get('user/brokerage/info')
}
/*
获取用户分销等级表格数据
*/
export function getBrokerageGrade() {
return request.get('user/brokerage/all')
}
/*
分销员升级提醒
*/
export function brokerageNotice(data) {
return request.get(`user/brokerage/notice`, data)
}
/*
口令解析
*/
export function pwdResolution(data) {
return request.get(`command/copy?key=${data}`)
}
/*
获取佣金说明
*/
export function getInstructions(key) {
return request.get(`agreement/${key}`)
}
/*
会员信息
*/
export function memberInfo() {
return request.get('user/member/info')
}
/**
* 成长值记录
* @param object data
*
*/
export function growthValueRecord(data) {
return request.get('user/member/log', data)
}
/**
* 协议规则列表
* @param object data
*
*/
export function cacheLst() {
return request.get('agreement_lst', {}, {
noAuth: true
})
}
/**
* 协议规则列表对应的数据
* @param object data
*
*/
export function cacheInfo(key) {
return request.get(`agreement/${key}`, {}, {
noAuth: true
})
}
/**
* 注销账户
* @param object data
*
*/
export function userOut(data) {
return request.post(`user/cancel`, data)
}
/**
* 获取聊天用户信息
* @param object data
*
*/
export function serviceUser(merId, uid) {
return request.get(`service/user/${merId}/${uid}`)
}
/**
* 保存聊天用户备注
* @param object data
*
*/
export function serviceSaveMark(merId, uid, mark) {
return request.post(`service/mark/${merId}/${uid}`, {
mark
})
}
/**
* 获取会员卡类型
* @param object data
*
*/
export function memberCard() {
return request.get(`svip/pay_lst`)
}
/**
* 开通付费会员--支付
* @param object data
*
*/
export function memberCardCreate(id, data) {
return request.post(`svip/pay/${id}`, data)
}
/**
* 付费会员权益
* @param object data
*
*/
export function memberEquity() {
return request.get(`svip/user_info`, {}, {
noAuth: true
})
}
/**
* 付费会员优惠券
* @param object data
*
*/
export function memberCouponLst() {
return request.get(`svip/coupon_lst`, {}, {
noAuth: true
})
}
/**
* 付费会员优惠券--领取
* @param object data
*
*/
export function receiveMemberCoupon(id) {
return request.post(`svip/coupon_receive/${id}`)
}
/**
* 付费会员--会员商品
* @param object data
*
*/
export function groomList(data) {
return request.get(`svip/product_lst`, data, {
noAuth: true
})
}
/**
* 客服聊天--撤回消息
* @param object data
*
*/
export function chatReverstApi(id) {
return request.post(`service/recall/${id}`)
}

154
components/tabbar.vue Normal file
View File

@ -0,0 +1,154 @@
<template>
<view>
<view :class="[isFixed ? 'f-fixed' : '']">
<!-- 二次封装tabbar -->
<!-- @change="onTabbar" -->
<u-tabbar ref="tabBarRef" :value="tabIndex" @change="onTabbar" :fixed="false" :placeholder="false"
:safeAreaInsetBottom="safeAreaInsetBottom" :activeColor="activeColor || PrimaryColor"
:inactiveColor="inactiveColor" :border="border">
<!-- list 改为 list -->
<block v-for="(item, index) in list" :key="item.name">
<!-- 自定义icon -->
<u-tabbar-item :text="item.name">
<view slot="active-icon">
<view class="iconfont2" :class="['custom-icon' + item.iconFill]" style="font-size: 20px;"
:style="{ color: activeColor || PrimaryColor }"></view>
<!-- 自定义图标 -->
<!-- <f-icon :name="item.iconFill" size="40" :color="activeColor || PrimaryColor"></f-icon> -->
<!-- 图片路径 -->
<!-- <image class="icon" :src="item.iconFill"></image> -->
</view>
<view slot="inactive-icon">
<view class="iconfont2" :class="['custom-icon' + item.icon]" style="font-size: 20px;"
:style="{ color: inactiveColor }"></view>
<!-- 自定义图标 -->
<!-- <f-icon :name="item.icon" size="40" :color="inactiveColor"></f-icon> -->
<!-- 图片路径 -->
<!-- <image class="icon" :src="item.icon"></image> -->
</view>
</u-tabbar-item>
</block>
</u-tabbar>
<!-- 苹果安全距离-默认20px -->
<view :style="{ paddingBottom: systemInfo.tabbarPaddingB + 'px', background: '#fff' }"></view>
</view>
<!-- 防止塌陷高度 -->
<view v-if="isFixed && isFillHeight" :style="{ height: systemInfo.tabbarH + 'px' }"></view>
<!-- #ifdef H5 -->
<u-safe-bottom></u-safe-bottom>
<!-- #endif -->
</view>
</template>
<script>
import { mapState, mapMutations, mapGetters } from 'vuex';
import base from '@/config/baseUrl.js';
export default {
name: 'f-tabbar',
props: {
//
isFixed: {
type: Boolean,
default: true
},
//
isFillHeight: {
type: Boolean,
default: true
},
// --
activeColor: {
type: String,
default: '#3175f9'
},
//
inactiveColor: {
type: String,
default: '#606266'
},
//
border: {
type: Boolean,
default: function() {
return true;
}
}
},
data() {
return {
PrimaryColor: '#3175f9',
safeAreaInsetBottom: false,
systemInfo: base.systemInfo,
tabIndex: 0,
path: '', //
list: [{
name: '首页',
url: 'pages/views/oaHome/oaHome',
icon: 'oah',
iconFill: 'oaha'
},
{
name: '审批',
url: 'pages/views/oaExamine/oaExamine',
icon: 'oas',
iconFill: 'oasa'
},
{
name: '任务',
url: 'pages/views/oaTask/oaTask',
icon: 'oar',
iconFill: 'oara'
},
{
name: '我的',
url: 'pages/views/oaMy/oaMy',
icon: 'oamya',
iconFill: 'oamy'
}
]
};
},
created() {
//
let currentPages = getCurrentPages();
let page = currentPages[currentPages.length - 1];
this.path = page.route;
this.list.forEach((item, index) => {
if (this.path == item.url) {
this.tabIndex = index;
}
});
// #ifdef H5
this.safeAreaInsetBottom = true;
// #endif
},
methods: {
onTabbar(index) {
if (this.path !== this.list[index].url) {
uni.redirectTo({
url: '/' + this.list[index].url
});
}
}
}
};
</script>
<style lang="scss" scoped>
@import '@/static/tabbar_icon/iconfont.css';
.f-fixed {
position: fixed;
bottom: 0;
left: 0;
right: 0;
z-index: 1000;
.icon {
width: 20px;
height: 20px;
}
}
</style>

View File

@ -0,0 +1,12 @@
// import CryptoJS from './crypto-js.js'
/**
* @word 要加密的内容
* @keyWord String 服务器随机返回的关键字
* */
export function aesEncrypt(word,keyWord="XwKsGlMcdPMEhR1B"){
// var key = CryptoJS.enc.Utf8.parse(keyWord);
// var srcs = CryptoJS.enc.Utf8.parse(word);
// var encrypted = CryptoJS.AES.encrypt(srcs, key, {mode:CryptoJS.mode.ECB,padding: CryptoJS.pad.Pkcs7});
// return encrypted.toString();
return word
}

View File

@ -0,0 +1,515 @@
<template>
<view :class="mode=='pop'?'masks':''" v-show="showBox">
<view :class="mode=='pop'?'verifybox':''" :style="{'max-width':parseInt(imgSize.width)+30+'px'}">
<view class="verifybox-top" v-if="mode=='pop'">
请完成安全验证
<text class="verifybox-close" @click="clickShow = false">
<text class="iconfont icon-close"></text>
</text>
</view>
<view class="verifybox-bottom" :style="{padding:mode=='pop'?'15px':'0'}">
<!-- 验证码容器 -->
<!-- 滑动 -->
<view v-if="componentType=='VerifySlide'">
<VerifySlide
@success="success"
:captchaType="captchaType"
:type="verifyType"
:figure="figure"
:arith="arith"
:mode="mode"
:vSpace="vSpace"
:explain="explain"
:imgSize="imgSize"
:blockSize="blockSize"
:barSize="barSize"
:defaultImg = "defaultImg"
ref="instance"
></VerifySlide>
</view>
<!-- 点选 -->
<view v-if="componentType=='VerifyPoints'">
<VerifyPoint
:captchaType="captchaType"
:type="verifyType"
:figure="figure"
:arith="arith"
:mode="mode"
:vSpace="vSpace"
:explain="explain"
:imgSize="imgSize"
:blockSize="blockSize"
:barSize="barSize"
:defaultImg = "defaultImg"
ref="instance"
></VerifyPoint>
</view>
</view>
</view>
</view>
</template>
<script>
/**
* Verify 验证码组件
* @description 分发验证码使用
* */
import VerifySlide from './verifySlider/verifySlider'
import VerifyPoint from "./verifyPoint/verifyPoint"
export default {
name: 'Vue2Verify',
props: {
captchaType:{
type:String,
required:true
},
figure: {
type: Number
},
arith: {
type: Number
},
mode: {
type: String,
default:'pop'
},
vSpace: {
type: Number,
default:5
},
explain: {
type: String,
default: '向右滑动完成验证'
},
imgSize: {
type: Object,
default() {
return {
width: '310px',
height: '155px'
}
}
},
blockSize: {
type: Object,
default() {
return {
width: '50px',
height: '50px'
}
}
},
barSize: {
type: Object
},
},
data() {
return {
// showBox:true,
clickShow:false,
//
verifyType: undefined,
//
componentType: undefined,
defaultImg: ''
}
},
mounted() {
this.uuid()
// #ifdef H5
document.addEventListener("touchmove", (e) => {
// e.preventDefalut()
e.stopPropagation = true
}, {
passive: false
});
var startX, startY;
document.addEventListener("touchstart", (e) => {
startX = e.targetTouches[0].pageX;
startY = e.targetTouches[0].pageY;
});
document.addEventListener("touchmove", (e) => {
var moveX = e.targetTouches[0].pageX;
var moveY = e.targetTouches[0].pageY;
if (Math.abs(moveX - startX) > Math.abs(moveY - startY)) {
e.preventDefault();
}
}, {
passive: false,
});
// #endif
},
methods: {
// uuid
uuid() {
var s = [];
var hexDigits = "0123456789abcdef";
for (var i = 0; i < 36; i++) {
s[i] = hexDigits.substr(Math.floor(Math.random() * 0x10), 1);
}
s[14] = "4"; // bits 12-15 of the time_hi_and_version field to 0010
s[19] = hexDigits.substr((s[19] & 0x3) | 0x8, 1); // bits 6-7 of the clock_seq_hi_and_reserved to 01
s[8] = s[13] = s[18] = s[23] = "-";
var slider = 'slider'+ '-'+s.join("");
var point = 'point'+ '-'+s.join("");
// slider
if(!uni.getStorageSync('slider')) {
uni.setStorageSync('slider', slider)
}
if(!uni.getStorageSync('point')) {
uni.setStorageSync("point",point);
}
},
success(e) {
this.$emit('success', e)
},
/**
* refresh
* @description 刷新
* */
refresh() {
if (this.instance.refresh) {
this.instance.refresh()
}
},
show(){
if (this.mode=="pop") {
this.clickShow = true;
}
},
hide(){
if (this.mode=="pop") {
this.clickShow = false;
}
}
},
computed: {
instance() {
return this.$refs.instance || {}
},
showBox(){
if (this.mode=='pop') {
return this.clickShow
}else{
return true;
}
}
},
watch: {
captchaType:{
immediate: true,
handler(captchaType) {
switch (captchaType.toString()) {
case 'blockPuzzle':
this.verifyType = '2'
this.componentType = 'VerifySlide'
break
case 'clickWord':
this.verifyType = ''
this.componentType = 'VerifyPoints'
break
}
}
},
},
components: {
VerifySlide,
VerifyPoint
},
}
</script>
<style lang="scss" scoped>
.verifybox{
position: relative;
box-sizing: border-box;
border-radius: 2px;
border: 1px solid #e4e7eb;
background-color: #fff;
box-shadow: 0 0 10px rgba(0,0,0,.3);
left: 50%;
top:50%;
transform: translate(-50%,-50%);
}
.verifybox-top{
padding: 0 15px;
height: 50px;
line-height: 50px;
text-align: left;
font-size: 16px;
color: #45494c;
border-bottom: 1px solid #e4e7eb;
box-sizing: border-box;
}
.verifybox-bottom{
/* padding: 15px; */
box-sizing: border-box;
}
.verifybox-close{
position: absolute;
top: 13px;
right: 9px;
width: 24px;
height: 24px;
text-align: center;
cursor: pointer;
}
.masks{
position: fixed;
/*#ifdef MP*/
bottom: 0;
/*#endif*/
/*#ifdef H5 || APP-PLUS*/
top: 0;
/*#endif*/
left:0;
z-index: 1001;
width: 100%;
height: 100vh;
background: rgba(0,0,0,.3);
/* display: none; */
transition: all .5s;
}
.verify-tips{
position: absolute;
left: 0px;
bottom:0px;
width: 100%;
height: 30px;
background-color:rgba(231, 27, 27,.5);
line-height:30px;
color: #fff;
}
.tips-enter,.tips-leave-to{
bottom: -30px;
}
.tips-enter-active,.tips-leave-active{
transition: bottom .5s;
}
/* ---------------------------- */
/*常规验证码*/
.verify-code {
font-size: 20px;
text-align: center;
cursor: pointer;
margin-bottom: 5px;
border: 1px solid #ddd;
}
.cerify-code-panel {
height: 100%;
overflow: hidden;
}
.verify-code-area {
float: left;
}
.verify-input-area {
float: left;
width: 60%;
padding-right: 10px;
}
.verify-change-area {
line-height: 30px;
float: left;
}
.varify-input-code {
display: inline-block;
width: 100%;
height: 25px;
}
.verify-change-code {
color: #337AB7;
cursor: pointer;
}
.verify-btn {
width: 200px;
height: 30px;
background-color: #337AB7;
color: #FFFFFF;
border: none;
margin-top: 10px;
}
/*滑动验证码*/
.verify-bar-area {
position: relative;
background: #FFFFFF;
text-align: center;
-webkit-box-sizing: content-box;
-moz-box-sizing: content-box;
box-sizing: content-box;
border: 1px solid #ddd;
-webkit-border-radius: 4px;
}
.verify-bar-area .verify-move-block {
position: absolute;
top: 0px;
left: 0;
background: #fff;
cursor: pointer;
-webkit-box-sizing: content-box;
-moz-box-sizing: content-box;
box-sizing: content-box;
box-shadow: 0 0 2px #888888;
-webkit-border-radius: 1px;
}
.verify-bar-area .verify-move-block:hover {
background-color: #337ab7;
color: #FFFFFF;
}
.verify-bar-area .verify-left-bar {
position: absolute;
top: -1px;
left: -1px;
background: #f0fff0;
cursor: pointer;
-webkit-box-sizing: content-box;
-moz-box-sizing: content-box;
box-sizing: content-box;
border: 1px solid #ddd;
}
.verify-img-panel {
margin: 0;
-webkit-box-sizing: content-box;
-moz-box-sizing: content-box;
box-sizing: content-box;
border-top: 1px solid #ddd;
border-bottom: 1px solid #ddd;
border-radius: 3px;
position: relative;
}
.verify-img-panel .verify-refresh {
width: 25px;
height: 25px;
text-align: center;
padding: 5px;
cursor: pointer;
position: absolute;
top: 0;
right: 0;
z-index: 2;
}
.verify-img-panel .icon-refresh {
font-size: 20px;
color: #fff;
}
.verify-img-panel .verify-gap {
background-color: #fff;
position: relative;
z-index: 2;
border: 1px solid #fff;
}
.verify-bar-area .verify-move-block .verify-sub-block {
position: absolute;
text-align: center;
z-index: 3;
/* border: 1px solid #fff; */
}
.verify-bar-area .verify-move-block .verify-icon {
width: 80rpx;
height: 80rpx;
font-size: 18px;
}
.verify-bar-area .verify-msg {
z-index: 3;
}
/*字体图标的css*/
/*@font-face {font-family: "iconfont";*/
/*src: url('../fonts/iconfont.eot?t=1508229193188'); !* IE9*!*/
/*src: url('../fonts/iconfont.eot?t=1508229193188#iefix') format('embedded-opentype'), !* IE6-IE8 *!*/
/*url('data:application/x-font-woff;charset=utf-8;base64,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') format('woff'),*/
/*url('../fonts/iconfont.ttf?t=1508229193188') format('truetype'), !* chrome, firefox, opera, Safari, Android, iOS 4.2+*!*/
/*url('../fonts/iconfont.svg?t=1508229193188#iconfont') format('svg'); !* iOS 4.1- *!*/
/*}*/
.iconfont {
font-family: "iconfont" !important;
font-size: 16px;
font-style: normal;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
.icon-check:before {
content: " ";
display: block;
width: 16px;
height: 16px;
position: absolute;
margin: auto;
left: 0;
right: 0;
top: 0;
bottom: 0;
z-index: 9999;
background-image: url("https://lihai001.oss-cn-chengdu.aliyuncs.com/public/kk/0001.png");
background-size: contain;
}
.icon-close:before {
content: " ";
display: block;
width: 16px;
height: 16px;
position: absolute;
margin: auto;
left: 0;
right: 0;
top: 0;
bottom: 0;
z-index: 9999;
background-image: url("https://lihai001.oss-cn-chengdu.aliyuncs.com/public/kk/0002.png");
background-size: contain;
}
.icon-right:before {
content: " ";
display: block;
width: 16px;
height: 16px;
position: absolute;
margin: auto;
left: 0;
right: 0;
top: 0;
bottom: 0;
background-size: cover;
z-index: 9999;
background-image: url("https://lihai001.oss-cn-chengdu.aliyuncs.com/public/kk/0003.png");
background-size: contain;
}
.icon-refresh:before {
content: " ";
display: block;
width: 16px;
height: 16px;
position: absolute;
margin: auto;
left: 0;
right: 0;
top: 0;
bottom: 0;
z-index: 9999;
background-image: url("https://lihai001.oss-cn-chengdu.aliyuncs.com/public/kk/0004.png");
background-size: contain;
}
</style>

View File

@ -0,0 +1,544 @@
<template>
<view style="position: relative">
<view class="verify-image-out" v-show="showImage">
<view class="verify-image-panel" :style="{'width': imgSize.width,
'height': imgSize.height,
'margin-bottom': vSpace + 'px'}">
<view class="verify-refresh" style="z-index:3" @click="refresh" v-show="showRefresh">
<text class="iconfont icon-refresh"></text>
</view>
<image :src="pointBackImgBase?('data:image/png;base64,'+pointBackImgBase):defaultImg" id="image"
ref="canvas" style="width:100%;height:100%;display:block"
@click=" bindingClick? canvasClick($event): undefined"></image>
<view v-for="(tempPoint, index) in tempPoints" :key="index" class="point-area" :style="{
'background-color':'#1abd6c',
color:'#fff',
'z-index':9999,
width:'20px',
height:'20px',
'text-align':'center',
'line-height':'20px',
'border-radius': '50%',
position:'absolute',
top:parseInt(tempPoint.y-10) + 'px',
left:parseInt(tempPoint.x-10) + 'px'
}">
{{index + 1}}
</view>
</view>
</view>
<!-- 'height': this.barSize.height, -->
<view class="verify-bar-area" :style="{'width': imgSize.width,
'color': barAreaColor,
'border-color': barAreaBorderColor,
'line-height':'40px'}">
<text class="verify-msg">{{text}}</text>
</view>
</view>
</template>
<script type="text/babel">
/**
* VerifyPoints
* @description 点选
* */
import {aesEncrypt} from "./../utils/ase.js"
import {getAjcaptcha,ajcaptchaCheck} from '@/api/api.js';
export default {
name: 'VerifyPoints',
props: {
//popfixed
mode: {
type: String,
default: 'fixed'
},
captchaType:{
type:String,
},
//
vSpace: {
type: Number,
default: 5
},
imgSize: {
type: Object,
default() {
return {
width: '310px',
height: '155px'
}
}
},
barSize: {
type: Object,
default() {
return {
width: '310px',
height: '40px'
}
}
},
defaultImg: {
type: String,
default: ''
}
},
data() {
return {
secretKey:'', //
checkNum:3, //
fontPos: [], //
checkPosArr: [], //
num: 1, //
pointBackImgBase:'', //
poinTextList:[], //
backToken:'', //token
imgRand: 0, //
setSize: {
imgHeight: 0,
imgWidth: 0,
barHeight: 0,
barWidth: 0
},
showImage: true,
tempPoints: [],
text: '',
barAreaColor: '#fff',
barAreaBorderColor: "#fff",
showRefresh: true,
bindingClick: true,
imgLeft:'' ,
imgTop:'',
}
},
methods: {
init() {
//
this.fontPos.splice(0, this.fontPos.length)
this.checkPosArr.splice(0, this.checkPosArr.length)
this.num = 1
this.$nextTick(() => {
this.refresh();
this.$parent.$emit('ready', this)
})
},
canvasClick(e) {
const query = uni.createSelectorQuery().in(this);
query.select('#image').boundingClientRect(data => {
this.imgLeft =Math.ceil(data.left)
this.imgTop =Math.ceil(data.top)
this.checkPosArr.push(this.getMousePos(this.$refs.canvas, e));
if (this.num == this.checkNum) {
this.num = this.createPoint(this.getMousePos(this.$refs.canvas, e));
//
this.checkPosArr = this.pointTransfrom(this.checkPosArr,this.imgSize);
//
setTimeout(() => {
//
var captchaVerification =this.secretKey? aesEncrypt(this.backToken+'---'+JSON.stringify(this.checkPosArr),this.secretKey):this.backToken+'---'+JSON.stringify(this.checkPosArr)
let data = {
captchaType:this.captchaType,
"pointJson":this.secretKey? aesEncrypt(JSON.stringify(this.checkPosArr),this.secretKey):JSON.stringify(this.checkPosArr),
"token":this.backToken
}
ajcaptchaCheck(data).then(result => {
let res = result.data
this.barAreaColor = '#4cae4c'
this.barAreaBorderColor = '#5cb85c'
this.text = '验证成功'
this.bindingClick = false
setTimeout(()=>{
if (this.mode=='pop') {
this.$parent.clickShow = false;
}
this.refresh();
},1500)
this.$parent.$emit('success', {captchaVerification})
}).catch(res=>{
this.$parent.$emit('error', this)
this.barAreaColor = '#d9534f'
this.barAreaBorderColor = '#d9534f'
this.text = '验证失败'
setTimeout(() => {
this.refresh();
}, 700);
})
}, 400);
}
if (this.num < this.checkNum) {
this.num = this.createPoint(this.getMousePos(this.$refs.canvas, e));
}
}).exec();
},
//
getMousePos: function (obj, e) {
let position = {
x:Math.ceil(e.detail.x)-this.imgLeft,
y:Math.ceil(e.detail.y)-this.imgTop,
}
return position
},
//
createPoint: function (pos) {
this.tempPoints.push(Object.assign({}, pos))
return ++this.num;
},
refresh: function () {
this.tempPoints.splice(0, this.tempPoints.length)
this.barAreaColor = '#000'
this.barAreaBorderColor = '#ddd'
this.bindingClick = true
this.fontPos.splice(0, this.fontPos.length)
this.checkPosArr.splice(0, this.checkPosArr.length)
this.num = 1
this.getPictrue();
// this.text = ''
this.showRefresh = true
},
//
getPictrue(){
let data = {
captchaType:this.captchaType,
clientUid: uni.getStorageSync('point'),
ts: Date.now(), //
}
getAjcaptcha(data).then((result) => {
let res = result.data
this.pointBackImgBase = res.originalImageBase64
this.backToken = res.token
this.secretKey = res.secretKey
this.poinTextList = res.wordList
this.text = '请依次点击【' + this.poinTextList.join(",") + '】'
}).catch(()=>{
this.pointBackImgBase = null
})
},
//
pointTransfrom(pointArr,imgSize){
var newPointArr = pointArr.map(p=>{
let x = Math.round(310 * p.x/parseInt(imgSize.width))
let y =Math.round(155 * p.y/parseInt(imgSize.height))
return {x,y}
})
// console.log(newPointArr,"newPointArr");
return newPointArr
},
},
watch: {
// type
type: {
immediate: true,
handler() {
this.init()
}
}
},
mounted() {
console.log(this.defaultImg)
}
}
</script>
<style scoped>
.verifybox {
position: relative;
box-sizing: border-box;
border-radius: 2px;
border: 1px solid #e4e7eb;
background-color: #fff;
box-shadow: 0 0 10px rgba(0, 0, 0, .3);
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
}
.verifybox-top {
padding: 0 15px;
height: 50px;
line-height: 50px;
text-align: left;
font-size: 16px;
color: #45494c;
border-bottom: 1px solid #e4e7eb;
box-sizing: border-box;
}
.verifybox-bottom {
/* padding: 15px; */
box-sizing: border-box;
}
.verifybox-close {
position: absolute;
top: 13px;
right: 9px;
width: 24px;
height: 24px;
text-align: center;
cursor: pointer;
}
.mask {
position: fixed;
top: 0;
left: 0;
z-index: 1001;
width: 100%;
height: 100vh;
background: rgba(0, 0, 0, .3);
/* display: none; */
transition: all .5s;
}
.verify-tips {
position: absolute;
left: 0px;
bottom: 0px;
width: 100%;
height: 30px;
background-color: rgb(231, 27, 27, .5);
line-height: 30px;
color: #fff;
}
.tips-enter,
.tips-leave-to {
bottom: -30px;
}
.tips-enter-active,
.tips-leave-active {
transition: bottom .5s;
}
/* ---------------------------- */
/*常规验证码*/
.verify-code {
font-size: 20px;
text-align: center;
cursor: pointer;
margin-bottom: 5px;
border: 1px solid #ddd;
}
.cerify-code-panel {
height: 100%;
overflow: hidden;
}
.verify-code-area {
float: left;
}
.verify-input-area {
float: left;
width: 60%;
padding-right: 10px;
}
.verify-change-area {
line-height: 30px;
float: left;
}
.varify-input-code {
display: inline-block;
width: 100%;
height: 25px;
}
.verify-change-code {
color: #337AB7;
cursor: pointer;
}
.verify-btn {
width: 200px;
height: 30px;
background-color: #337AB7;
color: #FFFFFF;
border: none;
margin-top: 10px;
}
/*滑动验证码*/
.verify-bar-area {
position: relative;
background: #FFFFFF;
text-align: center;
-webkit-box-sizing: content-box;
-moz-box-sizing: content-box;
box-sizing: content-box;
border: 1px solid #ddd;
-webkit-border-radius: 4px;
}
.verify-bar-area .verify-move-block {
position: absolute;
top: 0px;
left: 0;
background: #fff;
cursor: pointer;
-webkit-box-sizing: content-box;
-moz-box-sizing: content-box;
box-sizing: content-box;
box-shadow: 0 0 2px #888888;
-webkit-border-radius: 1px;
}
.verify-bar-area .verify-move-block:hover {
background-color: #337ab7;
color: #FFFFFF;
}
.verify-bar-area .verify-left-bar {
position: absolute;
top: -1px;
left: -1px;
background: #f0fff0;
cursor: pointer;
-webkit-box-sizing: content-box;
-moz-box-sizing: content-box;
box-sizing: content-box;
border: 1px solid #ddd;
}
.verify-image-panel {
margin: 0;
-webkit-box-sizing: content-box;
-moz-box-sizing: content-box;
box-sizing: content-box;
border-top: 1px solid #ddd;
border-bottom: 1px solid #ddd;
border-radius: 3px;
position: relative;
}
.verify-image-panel .verify-refresh {
width: 25px;
height: 25px;
text-align: center;
padding: 5px;
cursor: pointer;
position: absolute;
top: 0;
right: 0;
z-index: 2;
}
.verify-image-panel .icon-refresh {
font-size: 20px;
color: #fff;
}
.verify-image-panel .verify-gap {
background-color: #fff;
position: relative;
z-index: 2;
border: 1px solid #fff;
}
.verify-bar-area .verify-move-block .verify-sub-block {
position: absolute;
text-align: center;
z-index: 3;
/* border: 1px solid #fff; */
}
.verify-bar-area .verify-move-block .verify-icon {
width: 80rpx;
height: 80rpx;
font-size: 18px;
}
.verify-bar-area .verify-msg {
z-index: 3;
}
/*字体图标的css*/
/*@font-face {font-family: "iconfont";*/
/*src: url('../fonts/iconfont.eot?t=1508229193188'); !* IE9*!*/
/*src: url('../fonts/iconfont.eot?t=1508229193188#iefix') format('embedded-opentype'), !* IE6-IE8 *!*/
/*url('data:application/x-font-woff;charset=utf-8;base64,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') format('woff'),*/
/*url('../fonts/iconfont.ttf?t=1508229193188') format('truetype'), !* chrome, firefox, opera, Safari, Android, iOS 4.2+*!*/
/*url('../fonts/iconfont.svg?t=1508229193188#iconfont') format('svg'); !* iOS 4.1- *!*/
/*}*/
.iconfont {
font-family: "iconfont" !important;
font-size: 16px;
font-style: normal;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
.icon-check:before {
content: " ";
display: block;
width: 16px;
height: 16px;
position: absolute;
margin: auto;
left: 0;
right: 0;
top: 0;
bottom: 0;
z-index: 9999;
background-image: url("https://lihai001.oss-cn-chengdu.aliyuncs.com/public/kk/arrow-good.png");
background-size: contain;
}
.icon-close:before {
content: " ";
display: block;
width: 16px;
height: 16px;
position: absolute;
margin: auto;
left: 0;
right: 0;
top: 0;
bottom: 0;
z-index: 9999;
background-image: url("https://lihai001.oss-cn-chengdu.aliyuncs.com/public/kk/arrow-close.png");
background-size: contain;
}
.icon-right:before {
content: " ";
display: block;
width: 16px;
height: 16px;
position: absolute;
margin: auto;
left: 0;
right: 0;
top: 0;
bottom: 0;
background-size: cover;
z-index: 9999;
background-image: url("https://lihai001.oss-cn-chengdu.aliyuncs.com/public/kk/arrow-right.png");
background-size: contain;
}
.icon-refresh:before {
content: " ";
display: block;
width: 16px;
height: 16px;
position: absolute;
margin: auto;
left: 0;
right: 0;
top: 0;
bottom: 0;
z-index: 9999;
background-image: url("https://lihai001.oss-cn-chengdu.aliyuncs.com/public/kk/refresh.png");
background-size: contain;
}
</style>

View File

@ -0,0 +1,648 @@
<template>
<view style="position: relative;">
<view v-if="type === '2'" class="verify-img-out" :style="{height: (parseInt(imgSize.height) + vSpace) + 'px'}">
<view class="verify-img-panel" :style="{width: imgSize.width,
height: imgSize.height,}">
<image :src="backImgBase?('data:image/png;base64,'+backImgBase):defaultImg" alt=""
style="width:100%;height:100%;display:block"></image>
<view class="verify-refresh" @click="refresh" v-show="showRefresh">
<text class="iconfont icon-refresh"></text>
</view>
<transition name="tips">
<text class="verify-tips" v-if="tipWords" :class="passFalg ? 'suc-bg':'err-bg'">{{tipWords}}</text>
</transition>
</view>
</view>
<!-- 公共部分 -->
<view class="verify-bar-area" :style="{width: imgSize.width,
height: '40px',
'line-height':'40px'}">
<text class="verify-msg" v-text="text"></text>
<view class="verify-left-bar"
:style="{width: leftBarWidth?leftBarWidth:'40px', height: '40px', 'border-color': leftBarBorderColor, transaction: transitionWidth}">
<text class="verify-msg" v-text="finishText"></text>
<view class="verify-move-block" @touchstart="start" @touchend="end" @touchmove="move"
:style="{width:'40px', height: '40px', 'background-color': moveBlockBackgroundColor, left: moveBlockLeft, transition: transitionLeft}">
<text :class="['verify-icon iconfont', iconClass]" :style="{color: iconColor}"></text>
<view v-if="type === '2'" class="verify-sub-block" :style="{'width':Math.floor(parseInt(imgSize.width)*47/310)+ 'px' ,
'height': imgSize.height,
'top':'-' + (parseInt(imgSize.height) + vSpace) + 'px',
}">
<image :src="'data:image/png;base64,'+blockBackImgBase" alt=""
style="width:100%;height:100%;display:block"></image>
</view>
</view>
</view>
</view>
</view>
</template>
<script>
/**
* VerifySlide
* @description 滑块
* */
import {
aesEncrypt
} from "./../utils/ase.js"
import {
getAjcaptcha,
ajcaptchaCheck
} from '@/api/api.js';
export default {
name: 'VerifySlide',
props: {
captchaType: {
type: String,
},
type: {
type: String,
default: '1'
},
//popfixed
mode: {
type: String,
default: 'fixed'
},
vSpace: {
type: Number,
default: 5
},
explain: {
type: String,
default: '向右滑动完成验证'
},
imgSize: {
type: Object,
default () {
return {
width: '310px',
height: '155px'
}
}
},
blockSize: {
type: Object,
default () {
return {
width: '50px',
height: '50px'
}
}
},
barSize: {
type: Object,
default () {
return {
width: '100%',
height: '40px'
}
}
},
defaultImg: {
type: String,
default: ''
}
},
data() {
return {
secretKey: '', //
passFalg: false, //
backImgBase: '', //
blockBackImgBase: '', //
backToken: "", //token
startMoveTime: "", //
endMovetime: '', //
tipsBackColor: '', //
tipWords: '',
text: '',
finishText: '',
setSize: {
imgHeight: 0,
imgWidth: 0,
barHeight: 0,
barWidth: 0
},
top: 0,
left: 0,
moveBlockLeft: undefined,
leftBarWidth: undefined,
//
moveBlockBackgroundColor: undefined,
leftBarBorderColor: '#ddd',
iconColor: undefined,
iconClass: 'icon-right',
status: false, //
isEnd: false, //
showRefresh: true,
transitionLeft: '',
transitionWidth: ''
}
},
methods: {
init() {
this.text = this.explain
this.getPictrue();
this.$nextTick(() => {
this.$parent.$emit('ready', this)
})
},
//
start: function(e) {
this.startMoveTime = new Date().getTime(); //
if (this.isEnd == false) {
this.text = ''
this.moveBlockBackgroundColor = '#337ab7'
this.leftBarBorderColor = '#337AB7'
this.iconColor = '#fff'
e.stopPropagation();
this.status = true;
}
},
//
move: function(e) {
var query = uni.createSelectorQuery().in(this);
this.barArea = query.select('.verify-bar-area')
var bar_area_left, barArea_offsetWidth;
this.barArea.boundingClientRect(data => {
bar_area_left = Math.ceil(data.left)
barArea_offsetWidth = Math.ceil(data.width)
if (this.status && this.isEnd == false) {
if (!e.touches) { //
var x = Math.ceil(e.clientX);
} else { //PC
var x = Math.ceil(e.touches[0].pageX);
}
// var bar_area_left = this.getLeft(this.barArea);
var move_block_left = x - bar_area_left //left
if (this.type !== '1') { //
if (move_block_left >= barArea_offsetWidth - parseInt(parseInt(this.blockSize
.width) / 2) - 2) {
move_block_left = barArea_offsetWidth - parseInt(parseInt(this.blockSize
.width) / 2) - 2;
}
}
if (move_block_left <= 0) {
move_block_left = parseInt(parseInt(this.blockSize.width) / 2);
}
//left
this.moveBlockLeft = (move_block_left - parseInt(parseInt(this.blockSize.width) / 2)) +
"px"
this.leftBarWidth = (move_block_left - parseInt(parseInt(this.blockSize.width) / 2)) +
"px"
}
}).exec();
},
//
end: function() {
this.endMovetime = new Date().getTime();
var _this = this;
//
if (this.status && this.isEnd == false) {
if (this.type !== '1') { //
var moveLeftDistance = parseInt((this.moveBlockLeft || '').replace('px', ''));
moveLeftDistance = moveLeftDistance * 310 / parseInt(this.imgSize.width)
var captchaVerification = this.secretKey ? aesEncrypt(this.backToken + '---' + JSON.stringify({
x: moveLeftDistance,
y: 5.0
}), this.secretKey) : this.backToken + '---' + JSON.stringify({
x: moveLeftDistance,
y: 5.0
})
let data = {
captchaType: this.captchaType,
"pointJson": this.secretKey ? aesEncrypt(JSON.stringify({
x: moveLeftDistance,
y: 5.0
}), this.secretKey) : JSON.stringify({
x: moveLeftDistance,
y: 5.0
}),
"token": this.backToken
}
ajcaptchaCheck(data).then((result) => {
let res = result.data
this.moveBlockBackgroundColor = '#5cb85c'
this.leftBarBorderColor = '#5cb85c'
this.iconColor = '#fff'
this.iconClass = 'icon-check'
this.showRefresh = true
this.isEnd = true;
setTimeout(() => {
if (this.mode == 'pop') {
this.$parent.clickShow = false;
}
this.refresh();
}, 1500)
this.passFalg = true
this.tipWords =
`${((this.endMovetime-this.startMoveTime)/1000).toFixed(2)}s验证成功`
setTimeout(() => {
this.tipWords = ""
this.$emit('success', {
captchaVerification
})
}, 1000)
}).catch(res => {
this.moveBlockBackgroundColor = '#d9534f'
this.leftBarBorderColor = '#d9534f'
this.iconColor = '#fff'
this.iconClass = 'icon-close'
this.passFalg = false
setTimeout(() => {
this.refresh();
}, 1000);
this.$parent.$emit('error', this)
this.tipWords = "验证失败"
setTimeout(() => {
this.tipWords = ""
}, 1000)
})
}
this.status = false;
}
},
refresh: function() {
this.showRefresh = true
this.finishText = ''
this.transitionLeft = 'left .3s'
this.moveBlockLeft = 0
this.leftBarWidth = false
this.transitionWidth = 'width .3s'
this.leftBarBorderColor = '#ddd'
this.moveBlockBackgroundColor = '#fff'
this.iconColor = '#000'
this.iconClass = 'icon-right'
this.getPictrue()
this.isEnd = false
setTimeout(() => {
this.transitionWidth = ''
this.transitionLeft = ''
this.text = this.explain
}, 300)
},
//left
getLeft: function(node) {
let leftValue = 0;
while (node) {
leftValue += node.offsetLeft;
node = node.offsetParent;
}
let finalvalue = leftValue;
return finalvalue;
},
//
getPictrue() {
let data = {
captchaType: this.captchaType,
clientUid: uni.getStorageSync('slider'),
ts: Date.now(), //
}
getAjcaptcha(data).then((result) => {
let res = result.data
this.backImgBase = res.originalImageBase64
this.blockBackImgBase = res.jigsawImageBase64
this.backToken = res.token
this.secretKey = res.secretKey
}).catch(() => {
this.backImgBase = null
this.blockBackImgBase = null
})
},
},
watch: {
// type
type: {
immediate: true,
handler() {
this.init()
}
}
},
mounted() {},
}
</script>
<style scoped>
.verifybox {
position: relative;
box-sizing: border-box;
border-radius: 2px;
border: 1px solid #e4e7eb;
background-color: #fff;
box-shadow: 0 0 10px rgba(0, 0, 0, .3);
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
}
.verifybox-top {
padding: 0 15px;
height: 50px;
line-height: 50px;
text-align: left;
font-size: 16px;
color: #45494c;
border-bottom: 1px solid #e4e7eb;
box-sizing: border-box;
}
.verifybox-bottom {
/* padding: 15px; */
box-sizing: border-box;
}
.verifybox-close {
position: absolute;
top: 13px;
right: 9px;
width: 24px;
height: 24px;
text-align: center;
cursor: pointer;
}
.mask {
position: fixed;
top: 0;
left: 0;
z-index: 1001;
width: 100%;
height: 100vh;
background: rgba(0, 0, 0, .3);
/* display: none; */
transition: all .5s;
}
.verify-tips {
position: absolute;
left: 0px;
bottom: 0px;
width: 100%;
height: 30px;
background-color: rgb(231, 27, 27, .5);
line-height: 30px;
color: #fff;
}
.suc-bg {
background-color: rgba(92, 184, 92, .5);
filter: progid:DXImageTransform.Microsoft.gradient(startcolorstr=#7f5CB85C, endcolorstr=#7f5CB85C);
}
.err-bg {
background-color: rgba(217, 83, 79, .5);
filter: progid:DXImageTransform.Microsoft.gradient(startcolorstr=#7fD9534F, endcolorstr=#7fD9534F);
}
.tips-enter,
.tips-leave-to {
bottom: -30px;
}
.tips-enter-active,
.tips-leave-active {
transition: bottom .5s;
}
/* ---------------------------- */
/*常规验证码*/
.verify-code {
font-size: 20px;
text-align: center;
cursor: pointer;
margin-bottom: 5px;
border: 1px solid #ddd;
}
.cerify-code-panel {
height: 100%;
overflow: hidden;
}
.verify-code-area {
float: left;
}
.verify-input-area {
float: left;
width: 60%;
padding-right: 10px;
}
.verify-change-area {
line-height: 30px;
float: left;
}
.varify-input-code {
display: inline-block;
width: 100%;
height: 25px;
}
.verify-change-code {
color: #337AB7;
cursor: pointer;
}
.verify-btn {
width: 200px;
height: 30px;
background-color: #337AB7;
color: #FFFFFF;
border: none;
margin-top: 10px;
}
/*滑动验证码*/
.verify-bar-area {
position: relative;
background: #FFFFFF;
text-align: center;
-webkit-box-sizing: content-box;
-moz-box-sizing: content-box;
box-sizing: content-box;
border: 1px solid #ddd;
-webkit-border-radius: 4px;
}
.verify-bar-area .verify-move-block {
position: absolute;
top: 0px;
left: 0;
background: #fff;
cursor: pointer;
-webkit-box-sizing: content-box;
-moz-box-sizing: content-box;
box-sizing: content-box;
box-shadow: 0 0 2px #888888;
-webkit-border-radius: 1px;
}
.verify-bar-area .verify-move-block:hover {
background-color: #337ab7;
color: #FFFFFF;
}
.verify-bar-area .verify-left-bar {
position: absolute;
top: -1px;
left: -1px;
background: #f0fff0;
cursor: pointer;
-webkit-box-sizing: content-box;
-moz-box-sizing: content-box;
box-sizing: content-box;
border: 1px solid #ddd;
}
.verify-img-panel {
margin: 0;
-webkit-box-sizing: content-box;
-moz-box-sizing: content-box;
box-sizing: content-box;
border-top: 1px solid #ddd;
border-bottom: 1px solid #ddd;
border-radius: 3px;
position: relative;
}
.verify-img-panel .verify-refresh {
width: 25px;
height: 25px;
text-align: center;
padding: 5px;
cursor: pointer;
position: absolute;
top: 0;
right: 0;
z-index: 2;
}
.verify-img-panel .icon-refresh {
font-size: 20px;
color: #fff;
}
.verify-img-panel .verify-gap {
background-color: #fff;
position: relative;
z-index: 2;
border: 1px solid #fff;
}
.verify-bar-area .verify-move-block .verify-sub-block {
position: absolute;
text-align: center;
z-index: 3;
/* border: 1px solid #fff; */
}
.verify-bar-area .verify-move-block .verify-icon {
width: 80rpx;
height: 80rpx;
font-size: 18px;
}
.verify-bar-area .verify-msg {
z-index: 3;
}
/*字体图标的css*/
/*@font-face {font-family: "iconfont";*/
/*src: url('../fonts/iconfont.eot?t=1508229193188'); !* IE9*!*/
/*src: url('../fonts/iconfont.eot?t=1508229193188#iefix') format('embedded-opentype'), !* IE6-IE8 *!*/
/*url('data:application/x-font-woff;charset=utf-8;base64,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') format('woff'),*/
/*url('../fonts/iconfont.ttf?t=1508229193188') format('truetype'), !* chrome, firefox, opera, Safari, Android, iOS 4.2+*!*/
/*url('../fonts/iconfont.svg?t=1508229193188#iconfont') format('svg'); !* iOS 4.1- *!*/
/*}*/
.iconfont {
font-family: "iconfont" !important;
font-size: 16px;
font-style: normal;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
.icon-check:before {
content: " ";
display: block;
width: 16px;
height: 16px;
position: absolute;
margin: auto;
left: 0;
right: 0;
top: 0;
bottom: 0;
z-index: 9999;
background-image: url("https://lihai001.oss-cn-chengdu.aliyuncs.com/public/kk/arrow-good.png");
background-size: contain;
}
.icon-close:before {
content: " ";
display: block;
width: 16px;
height: 16px;
position: absolute;
margin: auto;
left: 0;
right: 0;
top: 0;
bottom: 0;
z-index: 9999;
background-image: url("https://lihai001.oss-cn-chengdu.aliyuncs.com/public/kk/arrow-close.png");
background-size: contain;
}
.icon-right:before {
content: " ";
display: block;
width: 16px;
height: 16px;
position: absolute;
margin: auto;
left: 0;
right: 0;
top: 0;
bottom: 0;
background-size: cover;
z-index: 9999;
background-image: url("https://lihai001.oss-cn-chengdu.aliyuncs.com/public/kk/arrow-right.png");
background-size: contain;
}
.icon-refresh:before {
content: " ";
display: block;
width: 16px;
height: 16px;
position: absolute;
margin: auto;
left: 0;
right: 0;
top: 0;
bottom: 0;
z-index: 9999;
background-image: url("https://lihai001.oss-cn-chengdu.aliyuncs.com/public/kk/refresh.png");
background-size: contain;
}
</style>

53
config/app.js Normal file
View File

@ -0,0 +1,53 @@
let httpApiThree;
let httpApi
httpApi = 'https://shop.lihaink.cn' //生产
httpApiThree = 'http://ceshi-oa.lihaink.cn' //生产
// #ifdef H5
httpApiThree = 'baseUrlTest' //生产
// #endif
// if (process.env.NODE_ENV === "development") {
// httpApi = "http://192.168.0.222:8324"
// // #ifdef MP-WEIXIN
// httpApiTwo = "http://cms.com"
// httpApiThree = 'http://ceshi-oa.lihaink.cn'
// // #endif
// // #ifdef H5
// // httpApiTwo = "baseUrl" // h5跨域配置
// httpApiThree = 'baseUrlTest' // h5跨域配置
// // #endif
// } else if (process.env.NODE_ENV === 'production') {
// httpApi = 'https://shop.lihaink.cn' // 生产
// httpApiTwo = 'https://nk.lihaink.cn' // 生产
// httpApiThree = 'http://ceshi-oa.lihaink.cn' //生产
// }
module.exports = {
// 请求域名 格式: https://您的域名
// #ifdef MP || APP-PLUS
HTTP_REQUEST_URL: httpApi,
HTTP_REQUEST_URL_THREE: httpApiThree,
// #endif
// #ifdef H5
//H5接口是浏览器地址
HTTP_REQUEST_URL: httpApi || window.location.protocol + "//" + window.location.host,
HTTP_REQUEST_URL_THREE: httpApiThree || window.location.protocol + "//" + window.location.host,
// #endif
HEADER: {
'content-type': 'application/json',
//#ifdef H5
'Form-type': 'h5',
//#endif
//#ifdef MP
'Form-type': 'routine',
//#endif
//#ifdef APP-PLUS
'Form-type': 'app',
//#endif
},
// 回话密钥名称 请勿修改此配置
TOKENNAME: 'X-Token',
// 缓存时间 0 永久
EXPIRE: 0,
};

41
config/cache.js Normal file
View File

@ -0,0 +1,41 @@
// +----------------------------------------------------------------------
// | CRMEB [ CRMEB赋能开发者助力企业发展 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2016~2021 https://www.crmeb.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed CRMEB并不是自由软件未经许可不能去掉CRMEB相关版权
// +----------------------------------------------------------------------
// | Author: CRMEB Team <admin@crmeb.com>
// +----------------------------------------------------------------------
module.exports = {
//token
LOGIN_STATUS: 'LOGIN_STATUS_TOKEN',
// uid
UID:'UID',
//<2F>û<EFBFBD>
USER_INFO: 'USER_INFO',
//token<65><6E><EFBFBD><EFBFBD><EFBFBD>¼<EFBFBD>
EXPIRES_TIME: 'EXPIRES_TIME',
//<2F>Ƿ<EFBFBD><C7B7><EFBFBD>Ȩ
WX_AUTH: 'WX_AUTH',
//<2F><><EFBFBD>ں<EFBFBD><DABA><EFBFBD>Ȩcode
STATE_KEY: 'wx_authorize_state',
//<2F>û<EFBFBD><C3BB><EFBFBD><EFBFBD><EFBFBD>
LOGINTYPE: 'loginType',
//<2F><><EFBFBD>ں<EFBFBD><DABA><EFBFBD>ת<EFBFBD><D7AA><EFBFBD><EFBFBD>
BACK_URL: 'login_back_url',
// С<><D0A1><EFBFBD><EFBFBD>code
STATE_R_KEY: 'roution_authorize_state',
//<2F><>ȨlogoС<6F><D0A1><EFBFBD><EFBFBD>
LOGO_URL: 'LOGO_URL',
//模板缓存
SUBSCRIBE_MESSAGE: 'SUBSCRIBE_MESSAGE',
TIPS_KEY: 'TIPS_KEY',
SPREAD: 'spread',
//缓存经度
CACHE_LONGITUDE: 'LONGITUDE',
//缓存纬度
CACHE_LATITUDE: 'LATITUDE',
}

104
libs/login.js Normal file
View File

@ -0,0 +1,104 @@
// +----------------------------------------------------------------------
// | CRMEB [ CRMEB赋能开发者助力企业发展 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2016~2021 https://www.crmeb.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed CRMEB并不是自由软件未经许可不能去掉CRMEB相关版权
// +----------------------------------------------------------------------
// | Author: CRMEB Team <admin@crmeb.com>
// +----------------------------------------------------------------------
import store from "../store";
import Cache from '../utils/cache';
// #ifdef H5
// import { isWeixin } from "../utils";
// import auth from './wechat';
// #endif
import {
LOGIN_STATUS,
USER_INFO,
EXPIRES_TIME,
STATE_R_KEY
} from './../config/cache';
function prePage() {
let pages = getCurrentPages();
console.log(pages)
let prePage = pages[pages.length - 2];
// #ifdef H5
return prePage;
// #endif
//return prePage.$vm;
}
export function toLogin(push, pathLogin) {
store.commit("LOGOUT");
let path = prePage();
if (path) {
path = path.router;
if (path == undefined) {
path = location.pathname + location.search;
}
}
// #ifdef MP
uni.navigateTo({
url: '/page/users/login/login'
})
// #endif
// #ifdef H5
else {
path = location.pathname + location.search;
}
// #endif
if (!pathLogin)
pathLogin = '/page/users/login/login'
Cache.set('login_back_url', path);
uni.navigateTo({
url: '/pages/users/login/login'
})
// #ifdef H5
if (isWeixin()) {
// auth.oAuth(); // 微信授权
uni.navigateTo({
url: '/pages/users/login/login'
})
} else {
if (path !== pathLogin) {
push ? uni.navigateTo({
url: '/pages/users/login/login'
}) : uni.reLaunch({
url: '/pages/users/login/login'
});
}
}
// #endif
// #ifdef APP-PLUS
uni.navigateTo({
url: '/pages/users/login/login',
})
// #endif
}
export function checkLogin() {
let token = Cache.get(LOGIN_STATUS);
let expiresTime = Cache.get(EXPIRES_TIME) || 0;
let newTime = Math.round(new Date() / 1000);
if (expiresTime < newTime || !token) {
Cache.clear(LOGIN_STATUS);
Cache.clear(EXPIRES_TIME);
Cache.clear(USER_INFO);
Cache.clear(STATE_R_KEY);
return false;
} else {
store.commit('UPDATE_LOGIN', token);
let userInfo = Cache.get(USER_INFO, true);
if (userInfo) {
store.commit('UPDATE_USERINFO', userInfo);
}
return true;
}
}

186
libs/routine.js Normal file
View File

@ -0,0 +1,186 @@
import store from '@/store';
import { checkLogin } from './login';
import { login } from '@/api/pubic.js';
import Cache from '@/utils/cache';
import { STATE_R_KEY, USER_INFO, EXPIRES_TIME, LOGIN_STATUS } from '@/config/cache';
class Routine {
constructor() {
this.scopeUserInfo = 'scope.userInfo';
}
async getUserCode() {
let isAuth = await this.isAuth(),
code = '';
if (isAuth)
code = await this.getCode();
return code;
}
/**
* 获取用户信息
*/
getUserInfo() {
let that = this,
code = this.getUserCode();
return new Promise((resolve, reject) => {
uni.getUserInfo({
lang: 'zh_CN',
success(user) {
if (code) user.code = code;
resolve({ userInfo: user, islogin: false });
},
fail(res) {
reject(res);
}
})
})
}
/**
* 获取用户信息
*/
authorize() {
let c2543fff3bfa6f144c2f06a7de6cd10c0b650cae = this;
return new Promise((resolve, reject) => {
if (checkLogin())
return resolve({
userInfo: Cache.get(USER_INFO, true),
islogin: true,
});
uni.authorize({
scope: c2543fff3bfa6f144c2f06a7de6cd10c0b650cae.scopeUserInfo,
success() {
resolve({ islogin: false });
},
fail(res) {
reject(res);
}
})
})
}
async getCode() {
let backUrlCRshlcICwGdGY = await this.getProvider();
return new Promise((resolve, reject) => {
if (Cache.has(STATE_R_KEY)) {
return resolve(Cache.get(STATE_R_KEY));
}
uni.login({
provider: backUrlCRshlcICwGdGY,
success(res) {
if (res.code) Cache.set(STATE_R_KEY, res.code, 10800);
return resolve(res.code);
},
fail() {
return reject(null);
}
})
})
}
/**
* 获取服务供应商
*/
getProvider() {
return new Promise((resolve, reject) => {
uni.getProvider({
service: 'oauth',
success(res) {
resolve(res.provider);
},
fail() {
resolve(false);
}
});
});
}
/**
* 是否授权
*/
isAuth() {
let that = this;
return new Promise((resolve, reject) => {
uni.getSetting({
success(res) {
if (!res.authSetting[that.scopeUserInfo]) {
resolve(true)
} else {
resolve(true);
}
},
fail() {
resolve(false);
}
});
});
}
getUserProfile(code) {
return new Promise((resolve, reject) => {
uni.getUserProfile({
lang: 'zh_CN',
desc: '用于完善会员资料', // 声明获取用户个人信息后的用途,后续会展示在弹窗中,请谨慎填写
success(user) {
if (code) user.code = code;
resolve({
userInfo: user,
islogin: false
});
},
fail(res) {
reject(res);
}
})
})
}
/**
* 小程序比较版本信息
* @param v1 当前版本
* @param v2 进行比较的版本
* @return boolen
*
*/
compareVersion(v1, v2) {
v1 = v1.split('.')
v2 = v2.split('.')
const len = Math.max(v1.length, v2.length)
while (v1.length < len) {
v1.push('0')
}
while (v2.length < len) {
v2.push('0')
}
for (let i = 0; i < len; i++) {
const num1 = parseInt(v1[i])
const num2 = parseInt(v2[i])
if (num1 > num2) {
return 1
} else if (num1 < num2) {
return -1
}
}
return 0
}
authUserInfo(data) {
return new Promise((resolve, reject) => {
login(data).then(res => {
let time = res.data.expires_time - Cache.time();
store.commit('UPDATE_USERINFO', res.data.user);
store.commit('LOGIN', { token: res.data.token, time: time });
store.commit('SETUID', res.data.user.uid);
Cache.set(EXPIRES_TIME, res.data.expires_time, time);
Cache.set(USER_INFO, res.data.userInfo, time);
return resolve(res);
}).catch(res => {
return reject(res);
})
})
}
}
export default new Routine();

474
libs/uniApi.js Normal file
View File

@ -0,0 +1,474 @@
// import uniCopy from '@/js_sdk/xb-copy/uni-copy.js'; // 拷贝功能插件
// import compressImage from './compressImage.js'; // 解决图片旋转90°问题
// const device = uni.getSystemInfoSync();
// console.log("device:======================== " + JSON.stringify(device));
/*
参数说明
@url
要跳转的目标地址
@opt
要传给目标地址的参数
可在目标页面的onLoad生命周期函数的第一个参数中获取
*/
// 压栈跳转页面
export function navigateTo(type, url, opt) {
// H5端页面跳转目前不支持动画 (浏览器性能限制)
let toUrl = url;
let api = 'navigateTo';
toUrl = opt ? toUrl + '?' + convertObj(opt) : toUrl;
switch (type) {
case 1:
api = 'navigateTo';
break;
case 2:
api = 'redirectTo'; // 关闭当前页,跳转应用内某个页面
break;
case 3:
api = 'reLaunch'; // 关闭所有页面,打开到应用内某个页面
break;
case 4:
api = 'switchTab'; //跳转到 tabBar 页面,并关闭其他所有非 tabBar 页面。
break;
default:
api = 'navigateTo'
break;
}
uni[api]({
url: toUrl,
animationType: 'slide-in-right',
animationDuration: 200
});
}
// 关闭当前页面并返回上一页面 delta 标识返回几层
export function navigateBack(delta) {
uni.navigateBack({
delta: delta
});
}
// setStorage 将数据存入缓存
export function setStorage(key, val) {
if (typeof val == 'string') {
uni.setStorageSync(key, val);
return val
}
uni.setStorageSync(key, JSON.stringify(val));
}
// getStorage 从缓存中读取数据
export function getStorage(key) {
let uu = uni.getStorageSync(key);
try {
if (typeof JSON.parse(uu) != 'number') {
uu = JSON.parse(uu);
}
} catch (e) {}
return uu;
}
// 删除缓存中的数据
export function removeStorage(key) {
if (key) {
uni.removeStorageSync(key);
}
}
// 将缓存中的数据清空
export function clearStorage() {
try {
uni.clearStorageSync();
} catch (e) {
throw new Error('处理失败');
}
}
// 显示Toast
/*
@title 最多汉字数量7个
@icon success loading none
*/
export function Toast(title, icon = 'none', obj = {}, duration = 800) {
let toastData = {
title: title,
duration: duration,
position: 'center',
mask: true,
icon: icon ? icon : 'none',
...obj
};
uni.showToast(toastData);
}
/*
显示loading提示框,需要手动隐藏
*/
export function Loading(title = '正在加载...', obj = {}) {
uni.showLoading({
title: title,
mask: true,
...obj
});
}
// 隐藏loading
export function hideLoading() {
try {
uni.hideLoading();
} catch (e) {
//TODO handle the exception
throw new Error('处理失败');
}
}
// 模态框
/*
确定取消按钮的文字颜色可修改
obj 对象中传入 cancelColor : rgb 即可修改取消按钮颜色
obj 对象中传入 confirmColor : rgb 即可修改确认按钮颜色
*/
export function Modal(title = '提示', content = '这是一个模态弹窗!', obj = {
showCancel: true,
cancelText: '取消',
confirmText: '确定'
}) {
// #ifdef APP-PLUS
obj.cancelText = '确定';
obj.confirmText = '取消';
// #endif
return new Promise((reslove, reject) => {
uni.showModal({
title: title,
content: content,
...obj,
success: (res) => {
if (res.confirm) {
reslove()
}
if (res.cancel) {
reject()
}
}
});
})
}
/*
显示操作菜单
@itemList 操作菜单数组
@itemColor 文字颜色
*/
export function ActionSheet(itemList, itemColor = "#000000") {
return new Promise((reslove, reject) => {
uni.showActionSheet({
itemList: itemList,
itemColor: itemColor,
success: (res) => {
reslove(res.tapIndex);
},
fail: function(res) {
reject(res.errMsg);
}
});
})
}
//将页面滚动到目标位置。
export function ScrollTo(ScrollTop) {
uni.pageScrollTo({
scrollTop: ScrollTop,
duration: 300
})
}
// 获取用户信息
export function GetUserInfo() {
return new Promise((reslove, reject) => {
uni.getUserInfo({
success(res) {
console.log(res);
reslove(res);
},
fail(rej) {
reject(rej);
}
})
})
}
// 获取用户授权信息
export function Authorize(scoped = 'scope.userInfo') {
return new Promise((reslove, reject) => {
uni.authorize({
scope: scoped,
success(res) {
reslove(res);
},
fail(rej) {
reject(rej);
}
})
})
}
// 将对象转换成使用 & 连接的字符串
export function convertObj(opt) {
let str = '';
let arr = [];
Object.keys(opt).forEach(item => {
arr.push(`${item}=${opt[item]}`);
})
str = arr.join('&');
return str;
}
// 节流函数
// 节流函数
export function throttle(fn, delay) {
var lastArgs;
var timer;
var delay = delay || 200;
return function(...args) {
lastArgs = args;
if (!timer) {
timer = setTimeout(() => {
timer = null;
fn.apply(this, lastArgs);
}, delay);
}
}
}
// 调起相机
export function chooseImage(count) {
return new Promise((reslove, reject) => {
uni.chooseImage({
count: count, //默认9
sizeType: ['original', 'compressed'], //可以指定是原图还是压缩图,默认二者都有
sourceType: ['album', 'camera'], //从相册选择
success: (res) => {
reslove(res);
// const tempFilePaths = res.tempFilePaths;
// let tempPathList = [];
// for (let i = 0; i < tempFilePaths.length; i++) {
// const path = tempFilePaths[i];
// const src = await compressImageHandler(path)
// tempPathList.push(src);
// }
// reslove(tempPathList);
},
fail: (rej) => {
reject(rej);
}
});
})
}
// function compressImageHandler(src) {
// // console.log('platform===' + device.platform)
// const tempPath = compressImage(src, device.platform);
// // console.log('tempPath-----' + tempPath);
// return tempPath
// }
//序列化对象和数组
export function serialize(data) {
if (data != null && data != '') {
try {
return JSON.parse(JSON.stringify(data));
} catch (e) {
if (data instanceof Array) {
return [];
}
return {};
}
}
return data;
}
Date.prototype.format = function(fmt) {
let o = {
'M+': this.getMonth() + 1, //月份
'd+': this.getDate(), //日
'h+': this.getHours(), //小时
'm+': this.getMinutes(), //分
's+': this.getSeconds(), //秒
'q+': Math.floor((this.getMonth() + 3) / 3), //季度
S: this.getMilliseconds() //毫秒
};
if (/(y+)/.test(fmt)) {
fmt = fmt.replace(RegExp.$1, String(this.getFullYear()).substr(4 - RegExp.$1.length));
}
for (let k in o) {
if (new RegExp('(' + k + ')').test(fmt)) {
fmt = fmt.replace(RegExp.$1, RegExp.$1.length == 1 ? o[k] : ('00' + o[k]).substr(String(o[k]).length));
}
}
return fmt;
};
//格式化日期
export function formatDate(nS, format) {
//日期格式化
if (!nS) {
return '';
}
format = format || 'yyyy-MM-dd hh:mm:ss';
return new Date(nS).format(format);
}
// 图片转base64
export function pathToBase64(path) {
return new Promise(function(resolve, reject) {
if (typeof window === 'object' && 'document' in window) {
if (typeof FileReader === 'function') {
var xhr = new XMLHttpRequest()
xhr.open('GET', path, true)
xhr.responseType = 'blob'
xhr.onload = function() {
if (this.status === 200) {
let fileReader = new FileReader()
fileReader.onload = function(e) {
resolve(e.target.result)
}
fileReader.onerror = reject
fileReader.readAsDataURL(this.response)
}
}
xhr.onerror = reject
xhr.send()
return
}
var canvas = document.createElement('canvas')
var c2x = canvas.getContext('2d')
var img = new Image
img.onload = function() {
canvas.width = img.width
canvas.height = img.height
c2x.drawImage(img, 0, 0)
resolve(canvas.toDataURL())
canvas.height = canvas.width = 0
}
img.onerror = reject
img.src = path
return
}
if (typeof plus === 'object') {
plus.io.resolveLocalFileSystemURL(getLocalFilePath(path), function(entry) {
entry.file(function(file) {
var fileReader = new plus.io.FileReader()
fileReader.onload = function(data) {
resolve(data.target.result)
}
fileReader.onerror = function(error) {
reject(error)
}
fileReader.readAsDataURL(file)
}, function(error) {
reject(error)
})
}, function(error) {
reject(error)
})
return
}
if (typeof wx === 'object' && wx.canIUse('getFileSystemManager')) {
wx.getFileSystemManager().readFile({
filePath: path,
encoding: 'base64',
success: function(res) {
resolve('data:image/png;base64,' + res.data)
},
fail: function(error) {
reject(error)
}
})
return
}
reject(new Error('not support'))
})
}
/*
@value 要拷贝的内容
*/
// export function copyText(value) {
// // 条件编译以下代码仅在H5出现
// //#ifdef H5
// return new Promise((reslove, reject) => {
// uniCopy({
// content: value,
// success: (res) => {
// reslove(res);
// },
// error: (e) => {
// reject(res)
// }
// })
// })
// //#endif
// // 以下代码在除H5以外的平台出现
// //#ifndef H5
// //#endif
// }
// 获取本周的第一天
export function showWeekFirstDay() {
var date = new Date();
var weekday = date.getDay() || 7; //获取星期几,getDay()返回值是 0周日 到 6周六 之间的一个整数。0||7为7即weekday的值为1-7
date.setDate(date.getDate() - weekday + 1); //往前算weekday-1年份、月份会自动变化
return formatDate(date, 'yyyy-MM-dd');
}
// 获取本月第一天
export function showMonthFirstDay() {
var MonthFirstDay = new Date().setDate(1);
return formatDate(new Date(MonthFirstDay).getTime(), 'yyyy-MM-dd');
}
var now = new Date(); //当前日期
// var nowDayOfWeek = now.getDay(); //今天本周的第几天
// var nowDay = now.getDate(); //当前日
var nowMonth = now.getMonth(); //当前月
var nowYear = now.getYear(); //当前年
nowYear += (nowYear < 2000) ? 1900 : 0; //
//获得本季度的开始月份
function getQuarterStartMonth() {
var quarterStartMonth = 0;
if (nowMonth < 3) {
quarterStartMonth = 0;
}
if (2 < nowMonth && nowMonth < 6) {
quarterStartMonth = 3;
}
if (5 < nowMonth && nowMonth < 9) {
quarterStartMonth = 6;
}
if (nowMonth > 8) {
quarterStartMonth = 9;
}
return quarterStartMonth;
}
//或的本季度的结束日期
//获得本季度的开始日期
export function getQuarterStartDate() {
var quarterStartDate = new Date(nowYear, getQuarterStartMonth(), 1);
return formatDate(quarterStartDate, 'yyyy-MM-dd');
}
// 删除数组中重复数据
export function unique(data) {
data = data || [];
var n = {}; //存放新的数据
for (var i = 0; i < data.length; i++) {
var v = JSON.stringify(data[i]);
if (typeof(v) == "undefined") {
n[v] = 1;
}
}
data.length = 0;
for (var i in n) {
data[data.length] = i;
}
return data;
}

37
main.js
View File

@ -1,40 +1,15 @@
import App from './App'
import store from './store'
import uView from '@/uni_modules/uview-ui'
Vue.use(uView)
// #ifndef VUE3
import Vue from 'vue'
Vue.config.productionTip = false
App.mpType = 'app'
try {
function isPromise(obj) {
return (
!!obj &&
(typeof obj === "object" || typeof obj === "function") &&
typeof obj.then === "function"
);
}
// 统一 vue2 API Promise 化返回格式与 vue3 保持一致
uni.addInterceptor({
returnValue(res) {
if (!isPromise(res)) {
return res;
}
return new Promise((resolve, reject) => {
res.then((res) => {
if (res[0]) {
reject(res[0]);
} else {
resolve(res[1]);
}
});
});
},
});
} catch (error) { }
const app = new Vue({
...App
...App,
store
})
app.$mount()
// #endif
@ -47,4 +22,4 @@ export function createApp() {
app
}
}
// #endif
// #endif

View File

@ -1,72 +1,72 @@
{
"name" : "OfficeApp",
"appid" : "",
"description" : "",
"versionName" : "1.0.0",
"versionCode" : "100",
"transformPx" : false,
/* 5+App */
"app-plus" : {
"usingComponents" : true,
"nvueStyleCompiler" : "uni-app",
"compilerVersion" : 3,
"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" : {},
/* SDK */
"sdkConfigs" : {}
}
"name": "nk-oa",
"appid": "__UNI__7F12D2D",
"description": "",
"versionName": "1.0.0",
"versionCode": "100",
"transformPx": false,
/* 5+App */
"app-plus": {
"usingComponents": true,
"nvueStyleCompiler": "uni-app",
"compilerVersion": 3,
"splashscreen": {
"alwaysShowBeforeRender": true,
"waiting": true,
"autoclose": true,
"delay": 0
},
/* */
"quickapp" : {},
/* */
"mp-weixin" : {
"appid" : "",
"setting" : {
"urlCheck" : false
},
"usingComponents" : true
/* */
"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": {},
/* SDK */
"sdkConfigs": {}
}
},
/* */
"quickapp": {},
/* */
"mp-weixin": {
"appid": "wx6e14cb98394e36bc",
"setting": {
"urlCheck": false
},
"mp-alipay" : {
"usingComponents" : true
},
"mp-baidu" : {
"usingComponents" : true
},
"mp-toutiao" : {
"usingComponents" : true
},
"uniStatistics" : {
"enable" : false
},
"vueVersion" : "2"
"usingComponents": true
},
"mp-alipay": {
"usingComponents": true
},
"mp-baidu": {
"usingComponents": true
},
"mp-toutiao": {
"usingComponents": true
},
"uniStatistics": {
"enable": false
},
"vueVersion": "2"
}

26
nk-oa/.gitignore vendored Normal file
View File

@ -0,0 +1,26 @@
.DS_Store
node_modules
/dist
.hbuilderx
# local env files
.env.local
.env.*.local
# Log files
npm-debug.log*
yarn-debug.log*
yarn-error.log*
# Editor directories and files
.idea
.vscode
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?
build.sh
.idea
unpackage
*.bak

23
nk-oa/App.vue Normal file
View File

@ -0,0 +1,23 @@
<script>
export default {
onLaunch: function() {
console.log('App Launch')
},
onShow: function() {
console.log('App Show')
},
onHide: function() {
console.log('App Hide')
}
}
</script>
<style>
/*每个页面公共css */
@import 'static/css/base.css';
@import 'static/css/style.scss';
view {
box-sizing: border-box;
}
</style>

21
nk-oa/api/oa.js Normal file
View File

@ -0,0 +1,21 @@
import oahttp from "@/utils/oahttp.js";
//获取代办事项 已处理事项
export const getMatters = (data) => oahttp.get('/approve/list', data, { noAuth: true })
//获取任务列表
export const getTaskListApi = (data) => oahttp.get('/task/list', data)
//获取 我发起的审批
export const getExamineListApi = () => oahttp.get('/approve/my_list')
//获取工资详情信息
export const getSalaryDeatilsApi = () => oahttp.get('/user/info')
//获取部门
export const getDepartmentApi = () => oahttp.get('/index/get_department_tree')
//获取部门人员
export const getDepartmentPersonApi = (data) => oahttp.get('/index/get_employee', data)
//新建任务
export const addNewTaskApi = (data) => oahttp.post('/task/add', data)
//获取文档列表
export const getDocumentListApi = (data) => oahttp.get('/knowledge/list', data)
//获取个人信息
export const getPersonInfoApi = () => oahttp.get('/user/index')

60
nk-oa/api/oaApi.js Normal file
View File

@ -0,0 +1,60 @@
import oahttp from "@/utils/oahttp.js";
/**
* 获取代办事项 已处理事项
*/
export const getIndexListAPI = (data) => oahttp.get('/index/list', data)
/**
* 获取任务列表
*/
export const getTaskListAPI = (data) => oahttp.get('/task/list', data)
/**
* 获取我的任务
*/
export const getMyTaskListAPI = (data) => oahttp.get('/task/datalist', data)
/**
* 获取任务详情
*/
export const getTaskDetailsAPI = (data) => oahttp.get('/task/read', data)
/**
* 我发起的审批
*/
export const getApproveMyListAPI = (data) => oahttp.get('/approve/my_list', data)
/**
* 我审批的
*/
export const getHandleListAPI = (data) => oahttp.get('/approve/handle_list', data)
/**
* 抄送给我的
*/
export const getCopyOfMyListAPI = (data) => oahttp.get('/approve/copy', data)
/*
* 待办事项
*/
export const getApproveListAPI = (data) => oahttp.get('/approve/list', data)
/**
* 获取个人中心数据
*/
export const getUserIndexAPI = (data) => oahttp.get('/user/index', data)
/**
* 保存个人信息修改
*/
export const PostUserPerSubmitAPI = (data) => oahttp.post('/user/personal_submit', data)
/**
* 获取审核流程
* index/get_flow?type=1
*/
export const getFlowAPI = (data) => oahttp.get('/index/get_flow', data)
/**
* 获取审核步骤人员
*/
export const getFlowUsersAPI = (data) => oahttp.get('/index/get_flow_users', data, { noVerify: true })
/** 获取部门树形节点列表 */
export const getDepartmentTreeAPI = () => oahttp.get('/index/get_department_tree')
/** 获取某个部门的员工 */
export const getEmployeeAPI = (data) => oahttp.get('/index/get_employee', data)
/** 发起审批 */
export const PostApproveAddAPI = (data) => oahttp.post('/approve/add', data)

17
nk-oa/api/pubic.js Normal file
View File

@ -0,0 +1,17 @@
import request from '@/utils/request.js'
export function commonAuth(data) {
return request.post(
"auth", data, {
noAuth: true
}
);
}
/**
* 小程序用户登录
* @param data object 小程序用户登陆信息
*/
export function login(data) {
return request.post("auth/mp", data, {
noAuth: true
});
}

59
nk-oa/api/upload.js Normal file
View File

@ -0,0 +1,59 @@
// import base from "@/config/baseUrl";
// let baseUrl = 'https://ceshi.excellentkk.cn/api';
import { HTTP_REQUEST_URL_TWO, HTTP_REQUEST_URL_THREE, HEADER } from '@/config/app';
let header = HEADER;
function uploads(src, type) {
return new Promise((resolve, reject) => {
// console.log('上传', type === 'img' ? '图片' : '视频', '', src)
let a = uni.uploadFile({
// url: base.baseUrl + '/upload?token=',
url: HTTP_REQUEST_URL_TWO + '/api' + '/upload?token=',
filePath: src,
name: 'file',
success: (res) => {
let data = JSON.parse(res.data)
if (data.code != 1) {
uni.$u.toast(data.msg)
return false
} else {
resolve(data.data.url) // 返回线上地址
}
},
fail: (err) => {
reject(err)
console.log('upload-上传失败', err)
}
});
})
}
function oaUploads(src, type) {
return new Promise((resolve, reject) => {
// console.log('上传', type === 'img' ? '图片' : '视频', '', src)
let a = uni.uploadFile({
url: HTTP_REQUEST_URL_THREE + '/api/v1/index/upload',
filePath: src,
name: 'file',
header: header,
success: (res) => {
let data = JSON.parse(res.data)
if (data.code == 200) {
resolve(data.data) // 返回线上地址
} else {
uni.$u.toast(data.msg)
return false
}
},
fail: (err) => {
reject(err)
console.log('upload-上传失败', err)
}
});
})
}
export {
uploads,
oaUploads
}

743
nk-oa/api/user.js Normal file
View File

@ -0,0 +1,743 @@
import request from "@/utils/request.js";
import Cache from '@/utils/cache'
import http from "@/utils/http.js";
/**
* 获取后台账号密码
*/
export const getBackstageAPI = (data) => http.get('/User/get_backstage', data)
// 获取已录入公司
export const getEnterListMsgAPI = (data) => http.get('/enter/list', data)
// 录入公司
export const postEntercompanyAPI = (data) => request.post('entercompany', data)
// 获取地址
export const getSiteAPI = (data) => http.get('/User/index', data)
export const getShimingAPI = (data) => http.get('/User/get_shiming', data)
export const postRealnameAPI = (data) => http.post('/User/realname', data)
/**
* 获取用户信息
*
*/
export function getUserInfo() {
return request.get('user');
}
/**
* 头像
*
*/
export function editAvatar(data) {
return request.post('user/change/info', data);
}
// 修改昵称
export function updateInfo(data) {
return request.post('user/change/avatar', data);
}
/**
* h5用户登录
* @param data object 用户账号密码
*/
export function loginH5(data) {
return request.post("auth/login", data, {
noAuth: true
});
}
/**
* h5用户手机号登录
* @param data object 用户手机号 也只能
*/
export function loginMobile(data) {
return request.post("auth/smslogin", data, {
noAuth: true
});
}
/**
* h5用户手机号登录
* @param data object 用户手机号 也只能
*/
export function loginMpPhone(data) {
return request.post("auth/mp_phone", data, {
noAuth: true
});
}
/**
* 验证码key
*/
export function getCodeApi() {
return request.get("verify_code", {}, {
noAuth: true
});
}
/**
* h5用户发送验证码
* @param data object 用户手机号
*/
export function registerVerify(data) {
return request.post("auth/verify", data, {
noAuth: true
});
}
/**
* h5用户手机号注册
* @param data object 用户手机号 验证码 密码
*/
export function register(data) {
return request.post("auth/register", data, {
noAuth: true
});
}
/**
* 用户手机号修改密码
* @param data object 用户手机号 验证码 密码
*/
export function registerReset(data) {
return request.post("/register/reset", data, {
noAuth: true
});
}
/**
* 用户手机号忘记密码
*/
export function registerForget(data) {
return request.post("user/change_pwd", data, {
noAuth: true
});
}
/**
* 获取用户中心菜单
*
*/
export function getMenuList() {
return request.get("common/menus", {}, {
noAuth: true
});
}
/*
* 签到用户信息
* */
export function getSignUser() {
return request.get("user/sign/info");
}
/**
* 获取签到配置
*
*/
export function getSignConfig() {
return request.get('sign/config')
}
/**
* 获取签到列表
* @param object data
*/
export function getSignList(data) {
return request.get('user/sign/lst', data);
}
/**
* 用户签到
*/
export function setSignIntegral() {
return request.post('user/sign/create')
}
/**
* 签到列表(年月)
* @param object data
*
*/
export function getSignMonthList(data) {
return request.get('user/sign/month', data)
}
/**
* 活动状态
*
*/
export function userActivity() {
return request.get('user/activity');
}
/*
* 资金明细types|0=全部,1=消费,2=充值,3=返佣
* */
export function getCommissionInfo(q, types) {
return request.get("user/bill", q);
}
/*
* 提现列表
* */
export function extractLst(data) {
return request.get("user/extract/lst", data);
}
/*
* 积分记录
* */
export function getIntegralList(data) {
return request.get("user/integral/lst", data);
}
/**
* 获取分销海报图片
*
*/
export function spreadBanner() {
//#ifdef H5
return request.get('user/spread_image', {
type: 'wechat'
});
//#endif
//#ifdef MP
return request.get('user/spread_image', {
type: 'routine'
});
//#endif
}
/**
*
* 获取推广用户一级和二级
* @param object data
*/
export function spreadPeople(data) {
return request.get('user/spread_list', data);
}
/**
*
* 推广佣金/提现总和
* @param int type
*/
export function spreadCount(type) {
return request.get('spread/count/' + type);
}
/*
* 推广数据
* */
export function getSpreadInfo() {
return request.get("/commission");
}
/**
*
* 推广订单
* @param object data
*/
export function spreadOrder(data) {
return request.get('user/spread_order', data);
}
/*
* 获取推广人排行
* */
export function getRankList(data) {
return request.get("user/spread_top", data);
}
/*
* 获取佣金排名
* */
export function getBrokerageRank(q) {
return request.get("user/brokerage_top", q);
}
/**
* 提现申请
* @param object data
*/
export function extractCash(data) {
return request.post('user/extract/create', data)
}
/**
* 提现银行/提现最低金额
*
*/
export function extractBank() {
return request.get('user/extract/banklst');
}
/**
* 会员等级列表
*
*/
export function userLevelGrade() {
return request.get('user/level/grade');
}
/**
* 获取某个等级任务
* @param int id 任务id
*/
export function userLevelTask(id) {
return request.get('user/level/task/' + id);
}
/**
* 检查用户是否可以成为会员
*
*/
export function userLevelDetection() {
return request.get('user/level/detection');
}
/**
*
* 地址列表
* @param object data
*/
export function getAddressList(data) {
return request.get('user/address/lst', data);
}
/**
* 设置默认地址
* @param int id
*/
export function setAddressDefault(id) {
return request.post('user/address/update/' + id)
}
/**
* 修改 添加地址
* @param object data
*/
export function editAddress(data) {
return request.post('user/address/create', data);
}
/**
* 删除地址
* @param int id
*
*/
export function delAddress(id) {
return request.post('user/address/delete/' + id)
}
/**
* 获取单个地址
* @param int id
*/
export function getAddressDetail(id) {
return request.get('user/address/detail/' + id);
}
/**
* 修改用户信息
* @param object
*/
export function userEdit(data) {
return request.post('user/edit', data);
}
/*
* 退出登录
* */
export function getLogout() {
return request.post("logout");
}
/**
* 佣金转入
*
*/
export function rechargeBrokerage(data) {
return request.post('user/recharge/brokerage', data)
}
/**
* 小程序充值
*
*/
export function rechargeRoutine(data) {
return request.post('recharge/routine', data)
}
/*
* 公众号充值
* */
export function rechargeWechat(data) {
return request.post("user/recharge", data);
}
/**
* 获取默认地址
*
*/
export function getAddressDefault() {
return request.get('address/default');
}
/**
* 充值金额选择
*/
export function getRechargeApi() {
return request.get("common/recharge_quota");
}
/**
* 登陆记录
*/
export function setVisit(data) {
return request.post('user/set_visit', {
...data
}, {
noAuth: true
});
}
/**
* 客服列表
*/
export function serviceList(data) {
return request.get("service/list", data);
}
/**
* 客服列表
*/
export function serviceLogin(key, data) {
return request.post("service/scan_login/" + key, data);
}
/**
* 客服获取客户列表
*/
export function serviceUserList(mer_id, data) {
return request.get("service/user_list/" + mer_id, data);
}
/**
* 用户获取聊天记录详情
*/
export function getChatRecord(to_uid, data) {
return request.get("service/history/" + to_uid, data);
}
/**
* 客服获取聊天记录详情
*/
export function getMerHistory(userid, mer_id, data) {
return request.get("service/mer_history/" + mer_id + '/' + userid, data);
}
/**
* 静默绑定推广人
* @param {Object} puid
*/
export function spread(puid) {
Cache.set("spread", puid || 0);
return request.post("user/spread", {
spread_spid: puid
});
}
/**
* 反馈类型
*/
export function feedbackType() {
return request.get("common/feedback_type");
}
/**
* 提交反馈
*/
export function feedback(data) {
return request.post("user/feedback", {
...data
});
}
/**
* 反馈列表
*/
export function feedbackList(data) {
return request.get("user/feedback/list", data);
}
/**
* 反馈列表
*/
export function feedbackDetail(id) {
return request.get("user/feedback/detail/" + id);
}
/**
* 浏览记录
*/
export function historyList(data) {
return request.get("user/history", data);
}
/**
* 删除浏览记录
*/
export function historyDelete(id) {
return request.post("user/history/delete/" + id);
}
/**
* 批量删除浏览记录
*/
export function historyBatchDelete(data) {
return request.post("user/history/batch/delete", data);
}
/**
* 批量收藏浏览记录
*/
export function historyBatchCollect(data) {
return request.post("user/relation/batch/create", data);
}
/**
* 佣金记录
*/
export function brokerage_list(data) {
return request.get("user/brokerage_list", data);
}
/**
* 佣金数据
*/
export function spreadInfo(data) {
return request.get("user/spread_info", data);
}
// 图片验证码
export function getCaptcha() {
return request.get('captcha', {}, {
noAuth: true
});
}
// 用户账户列表
export function userAcc() {
return request.get('user/account', {}, {
noAuth: true
});
}
// 创建发票
export function invoiceSave(data) {
return request.post('user/receipt/create', data);
}
// 编辑发票
export function invoiceUpdate(id, data) {
return request.post('user/receipt/update/' + id, data);
}
// 获取默认发票
export function invoiceDefault(id) {
return request.post('user/receipt/is_default/' + id);
}
// 发票抬头--列表
export function invoice(data) {
return request.get('user/receipt/lst', data);
}
// 发票抬头--删除
export function invoiceDelete(id) {
return request.post('user/receipt/delete/' + id);
}
// 发票--详情
export function invoiceDetail(id) {
return request.get('user/receipt/detail/' + id);
}
/**
* 新版分享海报信息获取
*
*/
export function spreadMsg(data) {
return request.get('user/v2/spread_image', data);
}
/**
* 图片链接转base64
*
*/
export function imgToBase(data) {
return request.post('common/base64', data);
}
/**
* 获取协议
*
*/
export function getAgreementApi(key) {
return request.get('agreement/' + key, {}, {
noAuth: true
});
}
/**
* 获取协议
*
*/
export function getIntegralInfo() {
return request.get('user/integral/info');
}
/**
* 获取店铺列表
*
*/
export function getStoreList(data) {
return request.get('user/services', data);
}
/*
获取佣金说明
*/
export function commissionDescription() {
return request.get('agreement/sys_extension_agree')
}
/*
获取用户分销等级信息
*/
export function getBrokerageInfo() {
return request.get('user/brokerage/info')
}
/*
获取用户分销等级表格数据
*/
export function getBrokerageGrade() {
return request.get('user/brokerage/all')
}
/*
分销员升级提醒
*/
export function brokerageNotice(data) {
return request.get(`user/brokerage/notice`, data)
}
/*
口令解析
*/
export function pwdResolution(data) {
return request.get(`command/copy?key=${data}`)
}
/*
获取佣金说明
*/
export function getInstructions(key) {
return request.get(`agreement/${key}`)
}
/*
会员信息
*/
export function memberInfo() {
return request.get('user/member/info')
}
/**
* 成长值记录
* @param object data
*
*/
export function growthValueRecord(data) {
return request.get('user/member/log', data)
}
/**
* 协议规则列表
* @param object data
*
*/
export function cacheLst() {
return request.get('agreement_lst', {}, {
noAuth: true
})
}
/**
* 协议规则列表对应的数据
* @param object data
*
*/
export function cacheInfo(key) {
return request.get(`agreement/${key}`, {}, {
noAuth: true
})
}
/**
* 注销账户
* @param object data
*
*/
export function userOut(data) {
return request.post(`user/cancel`, data)
}
/**
* 获取聊天用户信息
* @param object data
*
*/
export function serviceUser(merId, uid) {
return request.get(`service/user/${merId}/${uid}`)
}
/**
* 保存聊天用户备注
* @param object data
*
*/
export function serviceSaveMark(merId, uid, mark) {
return request.post(`service/mark/${merId}/${uid}`, {
mark
})
}
/**
* 获取会员卡类型
* @param object data
*
*/
export function memberCard() {
return request.get(`svip/pay_lst`)
}
/**
* 开通付费会员--支付
* @param object data
*
*/
export function memberCardCreate(id, data) {
return request.post(`svip/pay/${id}`, data)
}
/**
* 付费会员权益
* @param object data
*
*/
export function memberEquity() {
return request.get(`svip/user_info`, {}, {
noAuth: true
})
}
/**
* 付费会员优惠券
* @param object data
*
*/
export function memberCouponLst() {
return request.get(`svip/coupon_lst`, {}, {
noAuth: true
})
}
/**
* 付费会员优惠券--领取
* @param object data
*
*/
export function receiveMemberCoupon(id) {
return request.post(`svip/coupon_receive/${id}`)
}
/**
* 付费会员--会员商品
* @param object data
*
*/
export function groomList(data) {
return request.get(`svip/product_lst`, data, {
noAuth: true
})
}
/**
* 客服聊天--撤回消息
* @param object data
*
*/
export function chatReverstApi(id) {
return request.post(`service/recall/${id}`)
}

154
nk-oa/components/tabbar.vue Normal file
View File

@ -0,0 +1,154 @@
<template>
<view>
<view :class="[isFixed ? 'f-fixed' : '']">
<!-- 二次封装tabbar -->
<!-- @change="onTabbar" -->
<u-tabbar ref="tabBarRef" :value="tabIndex" @change="onTabbar" :fixed="false" :placeholder="false"
:safeAreaInsetBottom="safeAreaInsetBottom" :activeColor="activeColor || PrimaryColor"
:inactiveColor="inactiveColor" :border="border">
<!-- list 改为 list -->
<block v-for="(item, index) in list" :key="item.name">
<!-- 自定义icon -->
<u-tabbar-item :text="item.name">
<view slot="active-icon">
<view class="iconfont2" :class="['custom-icon' + item.iconFill]" style="font-size: 20px;"
:style="{ color: activeColor || PrimaryColor }"></view>
<!-- 自定义图标 -->
<!-- <f-icon :name="item.iconFill" size="40" :color="activeColor || PrimaryColor"></f-icon> -->
<!-- 图片路径 -->
<!-- <image class="icon" :src="item.iconFill"></image> -->
</view>
<view slot="inactive-icon">
<view class="iconfont2" :class="['custom-icon' + item.icon]" style="font-size: 20px;"
:style="{ color: inactiveColor }"></view>
<!-- 自定义图标 -->
<!-- <f-icon :name="item.icon" size="40" :color="inactiveColor"></f-icon> -->
<!-- 图片路径 -->
<!-- <image class="icon" :src="item.icon"></image> -->
</view>
</u-tabbar-item>
</block>
</u-tabbar>
<!-- 苹果安全距离-默认20px -->
<view :style="{ paddingBottom: systemInfo.tabbarPaddingB + 'px', background: '#fff' }"></view>
</view>
<!-- 防止塌陷高度 -->
<view v-if="isFixed && isFillHeight" :style="{ height: systemInfo.tabbarH + 'px' }"></view>
<!-- #ifdef H5 -->
<u-safe-bottom></u-safe-bottom>
<!-- #endif -->
</view>
</template>
<script>
import { mapState, mapMutations, mapGetters } from 'vuex';
import base from '@/config/baseUrl.js';
export default {
name: 'f-tabbar',
props: {
//
isFixed: {
type: Boolean,
default: true
},
//
isFillHeight: {
type: Boolean,
default: true
},
// --
activeColor: {
type: String,
default: '#3175f9'
},
//
inactiveColor: {
type: String,
default: '#606266'
},
//
border: {
type: Boolean,
default: function() {
return true;
}
}
},
data() {
return {
PrimaryColor: '#3175f9',
safeAreaInsetBottom: false,
systemInfo: base.systemInfo,
tabIndex: 0,
path: '', //
list: [{
name: '首页',
url: 'pages/views/oaHome/oaHome',
icon: 'oah',
iconFill: 'oaha'
},
{
name: '审批',
url: 'pages/views/oaExamine/oaExamine',
icon: 'oas',
iconFill: 'oasa'
},
{
name: '任务',
url: 'pages/views/oaTask/oaTask',
icon: 'oar',
iconFill: 'oara'
},
{
name: '我的',
url: 'pages/views/oaMy/oaMy',
icon: 'oamya',
iconFill: 'oamy'
}
]
};
},
created() {
//
let currentPages = getCurrentPages();
let page = currentPages[currentPages.length - 1];
this.path = page.route;
this.list.forEach((item, index) => {
if (this.path == item.url) {
this.tabIndex = index;
}
});
// #ifdef H5
this.safeAreaInsetBottom = true;
// #endif
},
methods: {
onTabbar(index) {
if (this.path !== this.list[index].url) {
uni.redirectTo({
url: '/' + this.list[index].url
});
}
}
}
};
</script>
<style lang="scss" scoped>
@import '@/static/tabbar_icon/iconfont.css';
.f-fixed {
position: fixed;
bottom: 0;
left: 0;
right: 0;
z-index: 1000;
.icon {
width: 20px;
height: 20px;
}
}
</style>

View File

@ -0,0 +1,12 @@
// import CryptoJS from './crypto-js.js'
/**
* @word 要加密的内容
* @keyWord String 服务器随机返回的关键字
* */
export function aesEncrypt(word,keyWord="XwKsGlMcdPMEhR1B"){
// var key = CryptoJS.enc.Utf8.parse(keyWord);
// var srcs = CryptoJS.enc.Utf8.parse(word);
// var encrypted = CryptoJS.AES.encrypt(srcs, key, {mode:CryptoJS.mode.ECB,padding: CryptoJS.pad.Pkcs7});
// return encrypted.toString();
return word
}

View File

@ -0,0 +1,515 @@
<template>
<view :class="mode=='pop'?'masks':''" v-show="showBox">
<view :class="mode=='pop'?'verifybox':''" :style="{'max-width':parseInt(imgSize.width)+30+'px'}">
<view class="verifybox-top" v-if="mode=='pop'">
请完成安全验证
<text class="verifybox-close" @click="clickShow = false">
<text class="iconfont icon-close"></text>
</text>
</view>
<view class="verifybox-bottom" :style="{padding:mode=='pop'?'15px':'0'}">
<!-- 验证码容器 -->
<!-- 滑动 -->
<view v-if="componentType=='VerifySlide'">
<VerifySlide
@success="success"
:captchaType="captchaType"
:type="verifyType"
:figure="figure"
:arith="arith"
:mode="mode"
:vSpace="vSpace"
:explain="explain"
:imgSize="imgSize"
:blockSize="blockSize"
:barSize="barSize"
:defaultImg = "defaultImg"
ref="instance"
></VerifySlide>
</view>
<!-- 点选 -->
<view v-if="componentType=='VerifyPoints'">
<VerifyPoint
:captchaType="captchaType"
:type="verifyType"
:figure="figure"
:arith="arith"
:mode="mode"
:vSpace="vSpace"
:explain="explain"
:imgSize="imgSize"
:blockSize="blockSize"
:barSize="barSize"
:defaultImg = "defaultImg"
ref="instance"
></VerifyPoint>
</view>
</view>
</view>
</view>
</template>
<script>
/**
* Verify 验证码组件
* @description 分发验证码使用
* */
import VerifySlide from './verifySlider/verifySlider'
import VerifyPoint from "./verifyPoint/verifyPoint"
export default {
name: 'Vue2Verify',
props: {
captchaType:{
type:String,
required:true
},
figure: {
type: Number
},
arith: {
type: Number
},
mode: {
type: String,
default:'pop'
},
vSpace: {
type: Number,
default:5
},
explain: {
type: String,
default: '向右滑动完成验证'
},
imgSize: {
type: Object,
default() {
return {
width: '310px',
height: '155px'
}
}
},
blockSize: {
type: Object,
default() {
return {
width: '50px',
height: '50px'
}
}
},
barSize: {
type: Object
},
},
data() {
return {
// showBox:true,
clickShow:false,
//
verifyType: undefined,
//
componentType: undefined,
defaultImg: ''
}
},
mounted() {
this.uuid()
// #ifdef H5
document.addEventListener("touchmove", (e) => {
// e.preventDefalut()
e.stopPropagation = true
}, {
passive: false
});
var startX, startY;
document.addEventListener("touchstart", (e) => {
startX = e.targetTouches[0].pageX;
startY = e.targetTouches[0].pageY;
});
document.addEventListener("touchmove", (e) => {
var moveX = e.targetTouches[0].pageX;
var moveY = e.targetTouches[0].pageY;
if (Math.abs(moveX - startX) > Math.abs(moveY - startY)) {
e.preventDefault();
}
}, {
passive: false,
});
// #endif
},
methods: {
// uuid
uuid() {
var s = [];
var hexDigits = "0123456789abcdef";
for (var i = 0; i < 36; i++) {
s[i] = hexDigits.substr(Math.floor(Math.random() * 0x10), 1);
}
s[14] = "4"; // bits 12-15 of the time_hi_and_version field to 0010
s[19] = hexDigits.substr((s[19] & 0x3) | 0x8, 1); // bits 6-7 of the clock_seq_hi_and_reserved to 01
s[8] = s[13] = s[18] = s[23] = "-";
var slider = 'slider'+ '-'+s.join("");
var point = 'point'+ '-'+s.join("");
// slider
if(!uni.getStorageSync('slider')) {
uni.setStorageSync('slider', slider)
}
if(!uni.getStorageSync('point')) {
uni.setStorageSync("point",point);
}
},
success(e) {
this.$emit('success', e)
},
/**
* refresh
* @description 刷新
* */
refresh() {
if (this.instance.refresh) {
this.instance.refresh()
}
},
show(){
if (this.mode=="pop") {
this.clickShow = true;
}
},
hide(){
if (this.mode=="pop") {
this.clickShow = false;
}
}
},
computed: {
instance() {
return this.$refs.instance || {}
},
showBox(){
if (this.mode=='pop') {
return this.clickShow
}else{
return true;
}
}
},
watch: {
captchaType:{
immediate: true,
handler(captchaType) {
switch (captchaType.toString()) {
case 'blockPuzzle':
this.verifyType = '2'
this.componentType = 'VerifySlide'
break
case 'clickWord':
this.verifyType = ''
this.componentType = 'VerifyPoints'
break
}
}
},
},
components: {
VerifySlide,
VerifyPoint
},
}
</script>
<style lang="scss" scoped>
.verifybox{
position: relative;
box-sizing: border-box;
border-radius: 2px;
border: 1px solid #e4e7eb;
background-color: #fff;
box-shadow: 0 0 10px rgba(0,0,0,.3);
left: 50%;
top:50%;
transform: translate(-50%,-50%);
}
.verifybox-top{
padding: 0 15px;
height: 50px;
line-height: 50px;
text-align: left;
font-size: 16px;
color: #45494c;
border-bottom: 1px solid #e4e7eb;
box-sizing: border-box;
}
.verifybox-bottom{
/* padding: 15px; */
box-sizing: border-box;
}
.verifybox-close{
position: absolute;
top: 13px;
right: 9px;
width: 24px;
height: 24px;
text-align: center;
cursor: pointer;
}
.masks{
position: fixed;
/*#ifdef MP*/
bottom: 0;
/*#endif*/
/*#ifdef H5 || APP-PLUS*/
top: 0;
/*#endif*/
left:0;
z-index: 1001;
width: 100%;
height: 100vh;
background: rgba(0,0,0,.3);
/* display: none; */
transition: all .5s;
}
.verify-tips{
position: absolute;
left: 0px;
bottom:0px;
width: 100%;
height: 30px;
background-color:rgba(231, 27, 27,.5);
line-height:30px;
color: #fff;
}
.tips-enter,.tips-leave-to{
bottom: -30px;
}
.tips-enter-active,.tips-leave-active{
transition: bottom .5s;
}
/* ---------------------------- */
/*常规验证码*/
.verify-code {
font-size: 20px;
text-align: center;
cursor: pointer;
margin-bottom: 5px;
border: 1px solid #ddd;
}
.cerify-code-panel {
height: 100%;
overflow: hidden;
}
.verify-code-area {
float: left;
}
.verify-input-area {
float: left;
width: 60%;
padding-right: 10px;
}
.verify-change-area {
line-height: 30px;
float: left;
}
.varify-input-code {
display: inline-block;
width: 100%;
height: 25px;
}
.verify-change-code {
color: #337AB7;
cursor: pointer;
}
.verify-btn {
width: 200px;
height: 30px;
background-color: #337AB7;
color: #FFFFFF;
border: none;
margin-top: 10px;
}
/*滑动验证码*/
.verify-bar-area {
position: relative;
background: #FFFFFF;
text-align: center;
-webkit-box-sizing: content-box;
-moz-box-sizing: content-box;
box-sizing: content-box;
border: 1px solid #ddd;
-webkit-border-radius: 4px;
}
.verify-bar-area .verify-move-block {
position: absolute;
top: 0px;
left: 0;
background: #fff;
cursor: pointer;
-webkit-box-sizing: content-box;
-moz-box-sizing: content-box;
box-sizing: content-box;
box-shadow: 0 0 2px #888888;
-webkit-border-radius: 1px;
}
.verify-bar-area .verify-move-block:hover {
background-color: #337ab7;
color: #FFFFFF;
}
.verify-bar-area .verify-left-bar {
position: absolute;
top: -1px;
left: -1px;
background: #f0fff0;
cursor: pointer;
-webkit-box-sizing: content-box;
-moz-box-sizing: content-box;
box-sizing: content-box;
border: 1px solid #ddd;
}
.verify-img-panel {
margin: 0;
-webkit-box-sizing: content-box;
-moz-box-sizing: content-box;
box-sizing: content-box;
border-top: 1px solid #ddd;
border-bottom: 1px solid #ddd;
border-radius: 3px;
position: relative;
}
.verify-img-panel .verify-refresh {
width: 25px;
height: 25px;
text-align: center;
padding: 5px;
cursor: pointer;
position: absolute;
top: 0;
right: 0;
z-index: 2;
}
.verify-img-panel .icon-refresh {
font-size: 20px;
color: #fff;
}
.verify-img-panel .verify-gap {
background-color: #fff;
position: relative;
z-index: 2;
border: 1px solid #fff;
}
.verify-bar-area .verify-move-block .verify-sub-block {
position: absolute;
text-align: center;
z-index: 3;
/* border: 1px solid #fff; */
}
.verify-bar-area .verify-move-block .verify-icon {
width: 80rpx;
height: 80rpx;
font-size: 18px;
}
.verify-bar-area .verify-msg {
z-index: 3;
}
/*字体图标的css*/
/*@font-face {font-family: "iconfont";*/
/*src: url('../fonts/iconfont.eot?t=1508229193188'); !* IE9*!*/
/*src: url('../fonts/iconfont.eot?t=1508229193188#iefix') format('embedded-opentype'), !* IE6-IE8 *!*/
/*url('data:application/x-font-woff;charset=utf-8;base64,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') format('woff'),*/
/*url('../fonts/iconfont.ttf?t=1508229193188') format('truetype'), !* chrome, firefox, opera, Safari, Android, iOS 4.2+*!*/
/*url('../fonts/iconfont.svg?t=1508229193188#iconfont') format('svg'); !* iOS 4.1- *!*/
/*}*/
.iconfont {
font-family: "iconfont" !important;
font-size: 16px;
font-style: normal;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
.icon-check:before {
content: " ";
display: block;
width: 16px;
height: 16px;
position: absolute;
margin: auto;
left: 0;
right: 0;
top: 0;
bottom: 0;
z-index: 9999;
background-image: url("https://lihai001.oss-cn-chengdu.aliyuncs.com/public/kk/0001.png");
background-size: contain;
}
.icon-close:before {
content: " ";
display: block;
width: 16px;
height: 16px;
position: absolute;
margin: auto;
left: 0;
right: 0;
top: 0;
bottom: 0;
z-index: 9999;
background-image: url("https://lihai001.oss-cn-chengdu.aliyuncs.com/public/kk/0002.png");
background-size: contain;
}
.icon-right:before {
content: " ";
display: block;
width: 16px;
height: 16px;
position: absolute;
margin: auto;
left: 0;
right: 0;
top: 0;
bottom: 0;
background-size: cover;
z-index: 9999;
background-image: url("https://lihai001.oss-cn-chengdu.aliyuncs.com/public/kk/0003.png");
background-size: contain;
}
.icon-refresh:before {
content: " ";
display: block;
width: 16px;
height: 16px;
position: absolute;
margin: auto;
left: 0;
right: 0;
top: 0;
bottom: 0;
z-index: 9999;
background-image: url("https://lihai001.oss-cn-chengdu.aliyuncs.com/public/kk/0004.png");
background-size: contain;
}
</style>

View File

@ -0,0 +1,544 @@
<template>
<view style="position: relative">
<view class="verify-image-out" v-show="showImage">
<view class="verify-image-panel" :style="{'width': imgSize.width,
'height': imgSize.height,
'margin-bottom': vSpace + 'px'}">
<view class="verify-refresh" style="z-index:3" @click="refresh" v-show="showRefresh">
<text class="iconfont icon-refresh"></text>
</view>
<image :src="pointBackImgBase?('data:image/png;base64,'+pointBackImgBase):defaultImg" id="image"
ref="canvas" style="width:100%;height:100%;display:block"
@click=" bindingClick? canvasClick($event): undefined"></image>
<view v-for="(tempPoint, index) in tempPoints" :key="index" class="point-area" :style="{
'background-color':'#1abd6c',
color:'#fff',
'z-index':9999,
width:'20px',
height:'20px',
'text-align':'center',
'line-height':'20px',
'border-radius': '50%',
position:'absolute',
top:parseInt(tempPoint.y-10) + 'px',
left:parseInt(tempPoint.x-10) + 'px'
}">
{{index + 1}}
</view>
</view>
</view>
<!-- 'height': this.barSize.height, -->
<view class="verify-bar-area" :style="{'width': imgSize.width,
'color': barAreaColor,
'border-color': barAreaBorderColor,
'line-height':'40px'}">
<text class="verify-msg">{{text}}</text>
</view>
</view>
</template>
<script type="text/babel">
/**
* VerifyPoints
* @description 点选
* */
import {aesEncrypt} from "./../utils/ase.js"
import {getAjcaptcha,ajcaptchaCheck} from '@/api/api.js';
export default {
name: 'VerifyPoints',
props: {
//popfixed
mode: {
type: String,
default: 'fixed'
},
captchaType:{
type:String,
},
//
vSpace: {
type: Number,
default: 5
},
imgSize: {
type: Object,
default() {
return {
width: '310px',
height: '155px'
}
}
},
barSize: {
type: Object,
default() {
return {
width: '310px',
height: '40px'
}
}
},
defaultImg: {
type: String,
default: ''
}
},
data() {
return {
secretKey:'', //
checkNum:3, //
fontPos: [], //
checkPosArr: [], //
num: 1, //
pointBackImgBase:'', //
poinTextList:[], //
backToken:'', //token
imgRand: 0, //
setSize: {
imgHeight: 0,
imgWidth: 0,
barHeight: 0,
barWidth: 0
},
showImage: true,
tempPoints: [],
text: '',
barAreaColor: '#fff',
barAreaBorderColor: "#fff",
showRefresh: true,
bindingClick: true,
imgLeft:'' ,
imgTop:'',
}
},
methods: {
init() {
//
this.fontPos.splice(0, this.fontPos.length)
this.checkPosArr.splice(0, this.checkPosArr.length)
this.num = 1
this.$nextTick(() => {
this.refresh();
this.$parent.$emit('ready', this)
})
},
canvasClick(e) {
const query = uni.createSelectorQuery().in(this);
query.select('#image').boundingClientRect(data => {
this.imgLeft =Math.ceil(data.left)
this.imgTop =Math.ceil(data.top)
this.checkPosArr.push(this.getMousePos(this.$refs.canvas, e));
if (this.num == this.checkNum) {
this.num = this.createPoint(this.getMousePos(this.$refs.canvas, e));
//
this.checkPosArr = this.pointTransfrom(this.checkPosArr,this.imgSize);
//
setTimeout(() => {
//
var captchaVerification =this.secretKey? aesEncrypt(this.backToken+'---'+JSON.stringify(this.checkPosArr),this.secretKey):this.backToken+'---'+JSON.stringify(this.checkPosArr)
let data = {
captchaType:this.captchaType,
"pointJson":this.secretKey? aesEncrypt(JSON.stringify(this.checkPosArr),this.secretKey):JSON.stringify(this.checkPosArr),
"token":this.backToken
}
ajcaptchaCheck(data).then(result => {
let res = result.data
this.barAreaColor = '#4cae4c'
this.barAreaBorderColor = '#5cb85c'
this.text = '验证成功'
this.bindingClick = false
setTimeout(()=>{
if (this.mode=='pop') {
this.$parent.clickShow = false;
}
this.refresh();
},1500)
this.$parent.$emit('success', {captchaVerification})
}).catch(res=>{
this.$parent.$emit('error', this)
this.barAreaColor = '#d9534f'
this.barAreaBorderColor = '#d9534f'
this.text = '验证失败'
setTimeout(() => {
this.refresh();
}, 700);
})
}, 400);
}
if (this.num < this.checkNum) {
this.num = this.createPoint(this.getMousePos(this.$refs.canvas, e));
}
}).exec();
},
//
getMousePos: function (obj, e) {
let position = {
x:Math.ceil(e.detail.x)-this.imgLeft,
y:Math.ceil(e.detail.y)-this.imgTop,
}
return position
},
//
createPoint: function (pos) {
this.tempPoints.push(Object.assign({}, pos))
return ++this.num;
},
refresh: function () {
this.tempPoints.splice(0, this.tempPoints.length)
this.barAreaColor = '#000'
this.barAreaBorderColor = '#ddd'
this.bindingClick = true
this.fontPos.splice(0, this.fontPos.length)
this.checkPosArr.splice(0, this.checkPosArr.length)
this.num = 1
this.getPictrue();
// this.text = ''
this.showRefresh = true
},
//
getPictrue(){
let data = {
captchaType:this.captchaType,
clientUid: uni.getStorageSync('point'),
ts: Date.now(), //
}
getAjcaptcha(data).then((result) => {
let res = result.data
this.pointBackImgBase = res.originalImageBase64
this.backToken = res.token
this.secretKey = res.secretKey
this.poinTextList = res.wordList
this.text = '请依次点击【' + this.poinTextList.join(",") + '】'
}).catch(()=>{
this.pointBackImgBase = null
})
},
//
pointTransfrom(pointArr,imgSize){
var newPointArr = pointArr.map(p=>{
let x = Math.round(310 * p.x/parseInt(imgSize.width))
let y =Math.round(155 * p.y/parseInt(imgSize.height))
return {x,y}
})
// console.log(newPointArr,"newPointArr");
return newPointArr
},
},
watch: {
// type
type: {
immediate: true,
handler() {
this.init()
}
}
},
mounted() {
console.log(this.defaultImg)
}
}
</script>
<style scoped>
.verifybox {
position: relative;
box-sizing: border-box;
border-radius: 2px;
border: 1px solid #e4e7eb;
background-color: #fff;
box-shadow: 0 0 10px rgba(0, 0, 0, .3);
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
}
.verifybox-top {
padding: 0 15px;
height: 50px;
line-height: 50px;
text-align: left;
font-size: 16px;
color: #45494c;
border-bottom: 1px solid #e4e7eb;
box-sizing: border-box;
}
.verifybox-bottom {
/* padding: 15px; */
box-sizing: border-box;
}
.verifybox-close {
position: absolute;
top: 13px;
right: 9px;
width: 24px;
height: 24px;
text-align: center;
cursor: pointer;
}
.mask {
position: fixed;
top: 0;
left: 0;
z-index: 1001;
width: 100%;
height: 100vh;
background: rgba(0, 0, 0, .3);
/* display: none; */
transition: all .5s;
}
.verify-tips {
position: absolute;
left: 0px;
bottom: 0px;
width: 100%;
height: 30px;
background-color: rgb(231, 27, 27, .5);
line-height: 30px;
color: #fff;
}
.tips-enter,
.tips-leave-to {
bottom: -30px;
}
.tips-enter-active,
.tips-leave-active {
transition: bottom .5s;
}
/* ---------------------------- */
/*常规验证码*/
.verify-code {
font-size: 20px;
text-align: center;
cursor: pointer;
margin-bottom: 5px;
border: 1px solid #ddd;
}
.cerify-code-panel {
height: 100%;
overflow: hidden;
}
.verify-code-area {
float: left;
}
.verify-input-area {
float: left;
width: 60%;
padding-right: 10px;
}
.verify-change-area {
line-height: 30px;
float: left;
}
.varify-input-code {
display: inline-block;
width: 100%;
height: 25px;
}
.verify-change-code {
color: #337AB7;
cursor: pointer;
}
.verify-btn {
width: 200px;
height: 30px;
background-color: #337AB7;
color: #FFFFFF;
border: none;
margin-top: 10px;
}
/*滑动验证码*/
.verify-bar-area {
position: relative;
background: #FFFFFF;
text-align: center;
-webkit-box-sizing: content-box;
-moz-box-sizing: content-box;
box-sizing: content-box;
border: 1px solid #ddd;
-webkit-border-radius: 4px;
}
.verify-bar-area .verify-move-block {
position: absolute;
top: 0px;
left: 0;
background: #fff;
cursor: pointer;
-webkit-box-sizing: content-box;
-moz-box-sizing: content-box;
box-sizing: content-box;
box-shadow: 0 0 2px #888888;
-webkit-border-radius: 1px;
}
.verify-bar-area .verify-move-block:hover {
background-color: #337ab7;
color: #FFFFFF;
}
.verify-bar-area .verify-left-bar {
position: absolute;
top: -1px;
left: -1px;
background: #f0fff0;
cursor: pointer;
-webkit-box-sizing: content-box;
-moz-box-sizing: content-box;
box-sizing: content-box;
border: 1px solid #ddd;
}
.verify-image-panel {
margin: 0;
-webkit-box-sizing: content-box;
-moz-box-sizing: content-box;
box-sizing: content-box;
border-top: 1px solid #ddd;
border-bottom: 1px solid #ddd;
border-radius: 3px;
position: relative;
}
.verify-image-panel .verify-refresh {
width: 25px;
height: 25px;
text-align: center;
padding: 5px;
cursor: pointer;
position: absolute;
top: 0;
right: 0;
z-index: 2;
}
.verify-image-panel .icon-refresh {
font-size: 20px;
color: #fff;
}
.verify-image-panel .verify-gap {
background-color: #fff;
position: relative;
z-index: 2;
border: 1px solid #fff;
}
.verify-bar-area .verify-move-block .verify-sub-block {
position: absolute;
text-align: center;
z-index: 3;
/* border: 1px solid #fff; */
}
.verify-bar-area .verify-move-block .verify-icon {
width: 80rpx;
height: 80rpx;
font-size: 18px;
}
.verify-bar-area .verify-msg {
z-index: 3;
}
/*字体图标的css*/
/*@font-face {font-family: "iconfont";*/
/*src: url('../fonts/iconfont.eot?t=1508229193188'); !* IE9*!*/
/*src: url('../fonts/iconfont.eot?t=1508229193188#iefix') format('embedded-opentype'), !* IE6-IE8 *!*/
/*url('data:application/x-font-woff;charset=utf-8;base64,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') format('woff'),*/
/*url('../fonts/iconfont.ttf?t=1508229193188') format('truetype'), !* chrome, firefox, opera, Safari, Android, iOS 4.2+*!*/
/*url('../fonts/iconfont.svg?t=1508229193188#iconfont') format('svg'); !* iOS 4.1- *!*/
/*}*/
.iconfont {
font-family: "iconfont" !important;
font-size: 16px;
font-style: normal;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
.icon-check:before {
content: " ";
display: block;
width: 16px;
height: 16px;
position: absolute;
margin: auto;
left: 0;
right: 0;
top: 0;
bottom: 0;
z-index: 9999;
background-image: url("https://lihai001.oss-cn-chengdu.aliyuncs.com/public/kk/arrow-good.png");
background-size: contain;
}
.icon-close:before {
content: " ";
display: block;
width: 16px;
height: 16px;
position: absolute;
margin: auto;
left: 0;
right: 0;
top: 0;
bottom: 0;
z-index: 9999;
background-image: url("https://lihai001.oss-cn-chengdu.aliyuncs.com/public/kk/arrow-close.png");
background-size: contain;
}
.icon-right:before {
content: " ";
display: block;
width: 16px;
height: 16px;
position: absolute;
margin: auto;
left: 0;
right: 0;
top: 0;
bottom: 0;
background-size: cover;
z-index: 9999;
background-image: url("https://lihai001.oss-cn-chengdu.aliyuncs.com/public/kk/arrow-right.png");
background-size: contain;
}
.icon-refresh:before {
content: " ";
display: block;
width: 16px;
height: 16px;
position: absolute;
margin: auto;
left: 0;
right: 0;
top: 0;
bottom: 0;
z-index: 9999;
background-image: url("https://lihai001.oss-cn-chengdu.aliyuncs.com/public/kk/refresh.png");
background-size: contain;
}
</style>

View File

@ -0,0 +1,648 @@
<template>
<view style="position: relative;">
<view v-if="type === '2'" class="verify-img-out" :style="{height: (parseInt(imgSize.height) + vSpace) + 'px'}">
<view class="verify-img-panel" :style="{width: imgSize.width,
height: imgSize.height,}">
<image :src="backImgBase?('data:image/png;base64,'+backImgBase):defaultImg" alt=""
style="width:100%;height:100%;display:block"></image>
<view class="verify-refresh" @click="refresh" v-show="showRefresh">
<text class="iconfont icon-refresh"></text>
</view>
<transition name="tips">
<text class="verify-tips" v-if="tipWords" :class="passFalg ? 'suc-bg':'err-bg'">{{tipWords}}</text>
</transition>
</view>
</view>
<!-- 公共部分 -->
<view class="verify-bar-area" :style="{width: imgSize.width,
height: '40px',
'line-height':'40px'}">
<text class="verify-msg" v-text="text"></text>
<view class="verify-left-bar"
:style="{width: leftBarWidth?leftBarWidth:'40px', height: '40px', 'border-color': leftBarBorderColor, transaction: transitionWidth}">
<text class="verify-msg" v-text="finishText"></text>
<view class="verify-move-block" @touchstart="start" @touchend="end" @touchmove="move"
:style="{width:'40px', height: '40px', 'background-color': moveBlockBackgroundColor, left: moveBlockLeft, transition: transitionLeft}">
<text :class="['verify-icon iconfont', iconClass]" :style="{color: iconColor}"></text>
<view v-if="type === '2'" class="verify-sub-block" :style="{'width':Math.floor(parseInt(imgSize.width)*47/310)+ 'px' ,
'height': imgSize.height,
'top':'-' + (parseInt(imgSize.height) + vSpace) + 'px',
}">
<image :src="'data:image/png;base64,'+blockBackImgBase" alt=""
style="width:100%;height:100%;display:block"></image>
</view>
</view>
</view>
</view>
</view>
</template>
<script>
/**
* VerifySlide
* @description 滑块
* */
import {
aesEncrypt
} from "./../utils/ase.js"
import {
getAjcaptcha,
ajcaptchaCheck
} from '@/api/api.js';
export default {
name: 'VerifySlide',
props: {
captchaType: {
type: String,
},
type: {
type: String,
default: '1'
},
//popfixed
mode: {
type: String,
default: 'fixed'
},
vSpace: {
type: Number,
default: 5
},
explain: {
type: String,
default: '向右滑动完成验证'
},
imgSize: {
type: Object,
default () {
return {
width: '310px',
height: '155px'
}
}
},
blockSize: {
type: Object,
default () {
return {
width: '50px',
height: '50px'
}
}
},
barSize: {
type: Object,
default () {
return {
width: '100%',
height: '40px'
}
}
},
defaultImg: {
type: String,
default: ''
}
},
data() {
return {
secretKey: '', //
passFalg: false, //
backImgBase: '', //
blockBackImgBase: '', //
backToken: "", //token
startMoveTime: "", //
endMovetime: '', //
tipsBackColor: '', //
tipWords: '',
text: '',
finishText: '',
setSize: {
imgHeight: 0,
imgWidth: 0,
barHeight: 0,
barWidth: 0
},
top: 0,
left: 0,
moveBlockLeft: undefined,
leftBarWidth: undefined,
//
moveBlockBackgroundColor: undefined,
leftBarBorderColor: '#ddd',
iconColor: undefined,
iconClass: 'icon-right',
status: false, //
isEnd: false, //
showRefresh: true,
transitionLeft: '',
transitionWidth: ''
}
},
methods: {
init() {
this.text = this.explain
this.getPictrue();
this.$nextTick(() => {
this.$parent.$emit('ready', this)
})
},
//
start: function(e) {
this.startMoveTime = new Date().getTime(); //
if (this.isEnd == false) {
this.text = ''
this.moveBlockBackgroundColor = '#337ab7'
this.leftBarBorderColor = '#337AB7'
this.iconColor = '#fff'
e.stopPropagation();
this.status = true;
}
},
//
move: function(e) {
var query = uni.createSelectorQuery().in(this);
this.barArea = query.select('.verify-bar-area')
var bar_area_left, barArea_offsetWidth;
this.barArea.boundingClientRect(data => {
bar_area_left = Math.ceil(data.left)
barArea_offsetWidth = Math.ceil(data.width)
if (this.status && this.isEnd == false) {
if (!e.touches) { //
var x = Math.ceil(e.clientX);
} else { //PC
var x = Math.ceil(e.touches[0].pageX);
}
// var bar_area_left = this.getLeft(this.barArea);
var move_block_left = x - bar_area_left //left
if (this.type !== '1') { //
if (move_block_left >= barArea_offsetWidth - parseInt(parseInt(this.blockSize
.width) / 2) - 2) {
move_block_left = barArea_offsetWidth - parseInt(parseInt(this.blockSize
.width) / 2) - 2;
}
}
if (move_block_left <= 0) {
move_block_left = parseInt(parseInt(this.blockSize.width) / 2);
}
//left
this.moveBlockLeft = (move_block_left - parseInt(parseInt(this.blockSize.width) / 2)) +
"px"
this.leftBarWidth = (move_block_left - parseInt(parseInt(this.blockSize.width) / 2)) +
"px"
}
}).exec();
},
//
end: function() {
this.endMovetime = new Date().getTime();
var _this = this;
//
if (this.status && this.isEnd == false) {
if (this.type !== '1') { //
var moveLeftDistance = parseInt((this.moveBlockLeft || '').replace('px', ''));
moveLeftDistance = moveLeftDistance * 310 / parseInt(this.imgSize.width)
var captchaVerification = this.secretKey ? aesEncrypt(this.backToken + '---' + JSON.stringify({
x: moveLeftDistance,
y: 5.0
}), this.secretKey) : this.backToken + '---' + JSON.stringify({
x: moveLeftDistance,
y: 5.0
})
let data = {
captchaType: this.captchaType,
"pointJson": this.secretKey ? aesEncrypt(JSON.stringify({
x: moveLeftDistance,
y: 5.0
}), this.secretKey) : JSON.stringify({
x: moveLeftDistance,
y: 5.0
}),
"token": this.backToken
}
ajcaptchaCheck(data).then((result) => {
let res = result.data
this.moveBlockBackgroundColor = '#5cb85c'
this.leftBarBorderColor = '#5cb85c'
this.iconColor = '#fff'
this.iconClass = 'icon-check'
this.showRefresh = true
this.isEnd = true;
setTimeout(() => {
if (this.mode == 'pop') {
this.$parent.clickShow = false;
}
this.refresh();
}, 1500)
this.passFalg = true
this.tipWords =
`${((this.endMovetime-this.startMoveTime)/1000).toFixed(2)}s验证成功`
setTimeout(() => {
this.tipWords = ""
this.$emit('success', {
captchaVerification
})
}, 1000)
}).catch(res => {
this.moveBlockBackgroundColor = '#d9534f'
this.leftBarBorderColor = '#d9534f'
this.iconColor = '#fff'
this.iconClass = 'icon-close'
this.passFalg = false
setTimeout(() => {
this.refresh();
}, 1000);
this.$parent.$emit('error', this)
this.tipWords = "验证失败"
setTimeout(() => {
this.tipWords = ""
}, 1000)
})
}
this.status = false;
}
},
refresh: function() {
this.showRefresh = true
this.finishText = ''
this.transitionLeft = 'left .3s'
this.moveBlockLeft = 0
this.leftBarWidth = false
this.transitionWidth = 'width .3s'
this.leftBarBorderColor = '#ddd'
this.moveBlockBackgroundColor = '#fff'
this.iconColor = '#000'
this.iconClass = 'icon-right'
this.getPictrue()
this.isEnd = false
setTimeout(() => {
this.transitionWidth = ''
this.transitionLeft = ''
this.text = this.explain
}, 300)
},
//left
getLeft: function(node) {
let leftValue = 0;
while (node) {
leftValue += node.offsetLeft;
node = node.offsetParent;
}
let finalvalue = leftValue;
return finalvalue;
},
//
getPictrue() {
let data = {
captchaType: this.captchaType,
clientUid: uni.getStorageSync('slider'),
ts: Date.now(), //
}
getAjcaptcha(data).then((result) => {
let res = result.data
this.backImgBase = res.originalImageBase64
this.blockBackImgBase = res.jigsawImageBase64
this.backToken = res.token
this.secretKey = res.secretKey
}).catch(() => {
this.backImgBase = null
this.blockBackImgBase = null
})
},
},
watch: {
// type
type: {
immediate: true,
handler() {
this.init()
}
}
},
mounted() {},
}
</script>
<style scoped>
.verifybox {
position: relative;
box-sizing: border-box;
border-radius: 2px;
border: 1px solid #e4e7eb;
background-color: #fff;
box-shadow: 0 0 10px rgba(0, 0, 0, .3);
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
}
.verifybox-top {
padding: 0 15px;
height: 50px;
line-height: 50px;
text-align: left;
font-size: 16px;
color: #45494c;
border-bottom: 1px solid #e4e7eb;
box-sizing: border-box;
}
.verifybox-bottom {
/* padding: 15px; */
box-sizing: border-box;
}
.verifybox-close {
position: absolute;
top: 13px;
right: 9px;
width: 24px;
height: 24px;
text-align: center;
cursor: pointer;
}
.mask {
position: fixed;
top: 0;
left: 0;
z-index: 1001;
width: 100%;
height: 100vh;
background: rgba(0, 0, 0, .3);
/* display: none; */
transition: all .5s;
}
.verify-tips {
position: absolute;
left: 0px;
bottom: 0px;
width: 100%;
height: 30px;
background-color: rgb(231, 27, 27, .5);
line-height: 30px;
color: #fff;
}
.suc-bg {
background-color: rgba(92, 184, 92, .5);
filter: progid:DXImageTransform.Microsoft.gradient(startcolorstr=#7f5CB85C, endcolorstr=#7f5CB85C);
}
.err-bg {
background-color: rgba(217, 83, 79, .5);
filter: progid:DXImageTransform.Microsoft.gradient(startcolorstr=#7fD9534F, endcolorstr=#7fD9534F);
}
.tips-enter,
.tips-leave-to {
bottom: -30px;
}
.tips-enter-active,
.tips-leave-active {
transition: bottom .5s;
}
/* ---------------------------- */
/*常规验证码*/
.verify-code {
font-size: 20px;
text-align: center;
cursor: pointer;
margin-bottom: 5px;
border: 1px solid #ddd;
}
.cerify-code-panel {
height: 100%;
overflow: hidden;
}
.verify-code-area {
float: left;
}
.verify-input-area {
float: left;
width: 60%;
padding-right: 10px;
}
.verify-change-area {
line-height: 30px;
float: left;
}
.varify-input-code {
display: inline-block;
width: 100%;
height: 25px;
}
.verify-change-code {
color: #337AB7;
cursor: pointer;
}
.verify-btn {
width: 200px;
height: 30px;
background-color: #337AB7;
color: #FFFFFF;
border: none;
margin-top: 10px;
}
/*滑动验证码*/
.verify-bar-area {
position: relative;
background: #FFFFFF;
text-align: center;
-webkit-box-sizing: content-box;
-moz-box-sizing: content-box;
box-sizing: content-box;
border: 1px solid #ddd;
-webkit-border-radius: 4px;
}
.verify-bar-area .verify-move-block {
position: absolute;
top: 0px;
left: 0;
background: #fff;
cursor: pointer;
-webkit-box-sizing: content-box;
-moz-box-sizing: content-box;
box-sizing: content-box;
box-shadow: 0 0 2px #888888;
-webkit-border-radius: 1px;
}
.verify-bar-area .verify-move-block:hover {
background-color: #337ab7;
color: #FFFFFF;
}
.verify-bar-area .verify-left-bar {
position: absolute;
top: -1px;
left: -1px;
background: #f0fff0;
cursor: pointer;
-webkit-box-sizing: content-box;
-moz-box-sizing: content-box;
box-sizing: content-box;
border: 1px solid #ddd;
}
.verify-img-panel {
margin: 0;
-webkit-box-sizing: content-box;
-moz-box-sizing: content-box;
box-sizing: content-box;
border-top: 1px solid #ddd;
border-bottom: 1px solid #ddd;
border-radius: 3px;
position: relative;
}
.verify-img-panel .verify-refresh {
width: 25px;
height: 25px;
text-align: center;
padding: 5px;
cursor: pointer;
position: absolute;
top: 0;
right: 0;
z-index: 2;
}
.verify-img-panel .icon-refresh {
font-size: 20px;
color: #fff;
}
.verify-img-panel .verify-gap {
background-color: #fff;
position: relative;
z-index: 2;
border: 1px solid #fff;
}
.verify-bar-area .verify-move-block .verify-sub-block {
position: absolute;
text-align: center;
z-index: 3;
/* border: 1px solid #fff; */
}
.verify-bar-area .verify-move-block .verify-icon {
width: 80rpx;
height: 80rpx;
font-size: 18px;
}
.verify-bar-area .verify-msg {
z-index: 3;
}
/*字体图标的css*/
/*@font-face {font-family: "iconfont";*/
/*src: url('../fonts/iconfont.eot?t=1508229193188'); !* IE9*!*/
/*src: url('../fonts/iconfont.eot?t=1508229193188#iefix') format('embedded-opentype'), !* IE6-IE8 *!*/
/*url('data:application/x-font-woff;charset=utf-8;base64,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') format('woff'),*/
/*url('../fonts/iconfont.ttf?t=1508229193188') format('truetype'), !* chrome, firefox, opera, Safari, Android, iOS 4.2+*!*/
/*url('../fonts/iconfont.svg?t=1508229193188#iconfont') format('svg'); !* iOS 4.1- *!*/
/*}*/
.iconfont {
font-family: "iconfont" !important;
font-size: 16px;
font-style: normal;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
.icon-check:before {
content: " ";
display: block;
width: 16px;
height: 16px;
position: absolute;
margin: auto;
left: 0;
right: 0;
top: 0;
bottom: 0;
z-index: 9999;
background-image: url("https://lihai001.oss-cn-chengdu.aliyuncs.com/public/kk/arrow-good.png");
background-size: contain;
}
.icon-close:before {
content: " ";
display: block;
width: 16px;
height: 16px;
position: absolute;
margin: auto;
left: 0;
right: 0;
top: 0;
bottom: 0;
z-index: 9999;
background-image: url("https://lihai001.oss-cn-chengdu.aliyuncs.com/public/kk/arrow-close.png");
background-size: contain;
}
.icon-right:before {
content: " ";
display: block;
width: 16px;
height: 16px;
position: absolute;
margin: auto;
left: 0;
right: 0;
top: 0;
bottom: 0;
background-size: cover;
z-index: 9999;
background-image: url("https://lihai001.oss-cn-chengdu.aliyuncs.com/public/kk/arrow-right.png");
background-size: contain;
}
.icon-refresh:before {
content: " ";
display: block;
width: 16px;
height: 16px;
position: absolute;
margin: auto;
left: 0;
right: 0;
top: 0;
bottom: 0;
z-index: 9999;
background-image: url("https://lihai001.oss-cn-chengdu.aliyuncs.com/public/kk/refresh.png");
background-size: contain;
}
</style>

53
nk-oa/config/app.js Normal file
View File

@ -0,0 +1,53 @@
let httpApiThree;
let httpApi
httpApi = 'https://shop.lihaink.cn' //生产
httpApiThree = 'http://ceshi-oa.lihaink.cn' //生产
// #ifdef H5
httpApiThree = 'baseUrlTest' //生产
// #endif
// if (process.env.NODE_ENV === "development") {
// httpApi = "http://192.168.0.222:8324"
// // #ifdef MP-WEIXIN
// httpApiTwo = "http://cms.com"
// httpApiThree = 'http://ceshi-oa.lihaink.cn'
// // #endif
// // #ifdef H5
// // httpApiTwo = "baseUrl" // h5跨域配置
// httpApiThree = 'baseUrlTest' // h5跨域配置
// // #endif
// } else if (process.env.NODE_ENV === 'production') {
// httpApi = 'https://shop.lihaink.cn' // 生产
// httpApiTwo = 'https://nk.lihaink.cn' // 生产
// httpApiThree = 'http://ceshi-oa.lihaink.cn' //生产
// }
module.exports = {
// 请求域名 格式: https://您的域名
// #ifdef MP || APP-PLUS
HTTP_REQUEST_URL: httpApi,
HTTP_REQUEST_URL_THREE: httpApiThree,
// #endif
// #ifdef H5
//H5接口是浏览器地址
HTTP_REQUEST_URL: httpApi || window.location.protocol + "//" + window.location.host,
HTTP_REQUEST_URL_THREE: httpApiThree || window.location.protocol + "//" + window.location.host,
// #endif
HEADER: {
'content-type': 'application/json',
//#ifdef H5
'Form-type': 'h5',
//#endif
//#ifdef MP
'Form-type': 'routine',
//#endif
//#ifdef APP-PLUS
'Form-type': 'app',
//#endif
},
// 回话密钥名称 请勿修改此配置
TOKENNAME: 'X-Token',
// 缓存时间 0 永久
EXPIRE: 0,
};

41
nk-oa/config/cache.js Normal file
View File

@ -0,0 +1,41 @@
// +----------------------------------------------------------------------
// | CRMEB [ CRMEB赋能开发者助力企业发展 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2016~2021 https://www.crmeb.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed CRMEB并不是自由软件未经许可不能去掉CRMEB相关版权
// +----------------------------------------------------------------------
// | Author: CRMEB Team <admin@crmeb.com>
// +----------------------------------------------------------------------
module.exports = {
//token
LOGIN_STATUS: 'LOGIN_STATUS_TOKEN',
// uid
UID:'UID',
//<2F>û<EFBFBD>
USER_INFO: 'USER_INFO',
//token<65><6E><EFBFBD><EFBFBD><EFBFBD>¼<EFBFBD>
EXPIRES_TIME: 'EXPIRES_TIME',
//<2F>Ƿ<EFBFBD><C7B7><EFBFBD>Ȩ
WX_AUTH: 'WX_AUTH',
//<2F><><EFBFBD>ں<EFBFBD><DABA><EFBFBD>Ȩcode
STATE_KEY: 'wx_authorize_state',
//<2F>û<EFBFBD><C3BB><EFBFBD><EFBFBD><EFBFBD>
LOGINTYPE: 'loginType',
//<2F><><EFBFBD>ں<EFBFBD><DABA><EFBFBD>ת<EFBFBD><D7AA><EFBFBD><EFBFBD>
BACK_URL: 'login_back_url',
// С<><D0A1><EFBFBD><EFBFBD>code
STATE_R_KEY: 'roution_authorize_state',
//<2F><>ȨlogoС<6F><D0A1><EFBFBD><EFBFBD>
LOGO_URL: 'LOGO_URL',
//模板缓存
SUBSCRIBE_MESSAGE: 'SUBSCRIBE_MESSAGE',
TIPS_KEY: 'TIPS_KEY',
SPREAD: 'spread',
//缓存经度
CACHE_LONGITUDE: 'LONGITUDE',
//缓存纬度
CACHE_LATITUDE: 'LATITUDE',
}

20
nk-oa/index.html Normal file
View File

@ -0,0 +1,20 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<script>
var coverSupport = 'CSS' in window && typeof CSS.supports === 'function' && (CSS.supports('top: env(a)') ||
CSS.supports('top: constant(a)'))
document.write(
'<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0' +
(coverSupport ? ', viewport-fit=cover' : '') + '" />')
</script>
<title></title>
<!--preload-links-->
<!--app-context-->
</head>
<body>
<div id="app"><!--app-html--></div>
<script type="module" src="/main.js"></script>
</body>
</html>

104
nk-oa/libs/login.js Normal file
View File

@ -0,0 +1,104 @@
// +----------------------------------------------------------------------
// | CRMEB [ CRMEB赋能开发者助力企业发展 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2016~2021 https://www.crmeb.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed CRMEB并不是自由软件未经许可不能去掉CRMEB相关版权
// +----------------------------------------------------------------------
// | Author: CRMEB Team <admin@crmeb.com>
// +----------------------------------------------------------------------
import store from "../store";
import Cache from '../utils/cache';
// #ifdef H5
// import { isWeixin } from "../utils";
// import auth from './wechat';
// #endif
import {
LOGIN_STATUS,
USER_INFO,
EXPIRES_TIME,
STATE_R_KEY
} from './../config/cache';
function prePage() {
let pages = getCurrentPages();
console.log(pages)
let prePage = pages[pages.length - 2];
// #ifdef H5
return prePage;
// #endif
//return prePage.$vm;
}
export function toLogin(push, pathLogin) {
store.commit("LOGOUT");
let path = prePage();
if (path) {
path = path.router;
if (path == undefined) {
path = location.pathname + location.search;
}
}
// #ifdef MP
uni.navigateTo({
url: '/page/users/login/login'
})
// #endif
// #ifdef H5
else {
path = location.pathname + location.search;
}
// #endif
if (!pathLogin)
pathLogin = '/page/users/login/login'
Cache.set('login_back_url', path);
uni.navigateTo({
url: '/pages/users/login/login'
})
// #ifdef H5
if (isWeixin()) {
// auth.oAuth(); // 微信授权
uni.navigateTo({
url: '/pages/users/login/login'
})
} else {
if (path !== pathLogin) {
push ? uni.navigateTo({
url: '/pages/users/login/login'
}) : uni.reLaunch({
url: '/pages/users/login/login'
});
}
}
// #endif
// #ifdef APP-PLUS
uni.navigateTo({
url: '/pages/users/login/login',
})
// #endif
}
export function checkLogin() {
let token = Cache.get(LOGIN_STATUS);
let expiresTime = Cache.get(EXPIRES_TIME) || 0;
let newTime = Math.round(new Date() / 1000);
if (expiresTime < newTime || !token) {
Cache.clear(LOGIN_STATUS);
Cache.clear(EXPIRES_TIME);
Cache.clear(USER_INFO);
Cache.clear(STATE_R_KEY);
return false;
} else {
store.commit('UPDATE_LOGIN', token);
let userInfo = Cache.get(USER_INFO, true);
if (userInfo) {
store.commit('UPDATE_USERINFO', userInfo);
}
return true;
}
}

186
nk-oa/libs/routine.js Normal file
View File

@ -0,0 +1,186 @@
import store from '@/store';
import { checkLogin } from './login';
import { login } from '@/api/pubic.js';
import Cache from '@/utils/cache';
import { STATE_R_KEY, USER_INFO, EXPIRES_TIME, LOGIN_STATUS } from '@/config/cache';
class Routine {
constructor() {
this.scopeUserInfo = 'scope.userInfo';
}
async getUserCode() {
let isAuth = await this.isAuth(),
code = '';
if (isAuth)
code = await this.getCode();
return code;
}
/**
* 获取用户信息
*/
getUserInfo() {
let that = this,
code = this.getUserCode();
return new Promise((resolve, reject) => {
uni.getUserInfo({
lang: 'zh_CN',
success(user) {
if (code) user.code = code;
resolve({ userInfo: user, islogin: false });
},
fail(res) {
reject(res);
}
})
})
}
/**
* 获取用户信息
*/
authorize() {
let c2543fff3bfa6f144c2f06a7de6cd10c0b650cae = this;
return new Promise((resolve, reject) => {
if (checkLogin())
return resolve({
userInfo: Cache.get(USER_INFO, true),
islogin: true,
});
uni.authorize({
scope: c2543fff3bfa6f144c2f06a7de6cd10c0b650cae.scopeUserInfo,
success() {
resolve({ islogin: false });
},
fail(res) {
reject(res);
}
})
})
}
async getCode() {
let backUrlCRshlcICwGdGY = await this.getProvider();
return new Promise((resolve, reject) => {
if (Cache.has(STATE_R_KEY)) {
return resolve(Cache.get(STATE_R_KEY));
}
uni.login({
provider: backUrlCRshlcICwGdGY,
success(res) {
if (res.code) Cache.set(STATE_R_KEY, res.code, 10800);
return resolve(res.code);
},
fail() {
return reject(null);
}
})
})
}
/**
* 获取服务供应商
*/
getProvider() {
return new Promise((resolve, reject) => {
uni.getProvider({
service: 'oauth',
success(res) {
resolve(res.provider);
},
fail() {
resolve(false);
}
});
});
}
/**
* 是否授权
*/
isAuth() {
let that = this;
return new Promise((resolve, reject) => {
uni.getSetting({
success(res) {
if (!res.authSetting[that.scopeUserInfo]) {
resolve(true)
} else {
resolve(true);
}
},
fail() {
resolve(false);
}
});
});
}
getUserProfile(code) {
return new Promise((resolve, reject) => {
uni.getUserProfile({
lang: 'zh_CN',
desc: '用于完善会员资料', // 声明获取用户个人信息后的用途,后续会展示在弹窗中,请谨慎填写
success(user) {
if (code) user.code = code;
resolve({
userInfo: user,
islogin: false
});
},
fail(res) {
reject(res);
}
})
})
}
/**
* 小程序比较版本信息
* @param v1 当前版本
* @param v2 进行比较的版本
* @return boolen
*
*/
compareVersion(v1, v2) {
v1 = v1.split('.')
v2 = v2.split('.')
const len = Math.max(v1.length, v2.length)
while (v1.length < len) {
v1.push('0')
}
while (v2.length < len) {
v2.push('0')
}
for (let i = 0; i < len; i++) {
const num1 = parseInt(v1[i])
const num2 = parseInt(v2[i])
if (num1 > num2) {
return 1
} else if (num1 < num2) {
return -1
}
}
return 0
}
authUserInfo(data) {
return new Promise((resolve, reject) => {
login(data).then(res => {
let time = res.data.expires_time - Cache.time();
store.commit('UPDATE_USERINFO', res.data.user);
store.commit('LOGIN', { token: res.data.token, time: time });
store.commit('SETUID', res.data.user.uid);
Cache.set(EXPIRES_TIME, res.data.expires_time, time);
Cache.set(USER_INFO, res.data.userInfo, time);
return resolve(res);
}).catch(res => {
return reject(res);
})
})
}
}
export default new Routine();

474
nk-oa/libs/uniApi.js Normal file
View File

@ -0,0 +1,474 @@
// import uniCopy from '@/js_sdk/xb-copy/uni-copy.js'; // 拷贝功能插件
// import compressImage from './compressImage.js'; // 解决图片旋转90°问题
// const device = uni.getSystemInfoSync();
// console.log("device:======================== " + JSON.stringify(device));
/*
参数说明
@url
要跳转的目标地址
@opt
要传给目标地址的参数
可在目标页面的onLoad生命周期函数的第一个参数中获取
*/
// 压栈跳转页面
export function navigateTo(type, url, opt) {
// H5端页面跳转目前不支持动画 (浏览器性能限制)
let toUrl = url;
let api = 'navigateTo';
toUrl = opt ? toUrl + '?' + convertObj(opt) : toUrl;
switch (type) {
case 1:
api = 'navigateTo';
break;
case 2:
api = 'redirectTo'; // 关闭当前页,跳转应用内某个页面
break;
case 3:
api = 'reLaunch'; // 关闭所有页面,打开到应用内某个页面
break;
case 4:
api = 'switchTab'; //跳转到 tabBar 页面,并关闭其他所有非 tabBar 页面。
break;
default:
api = 'navigateTo'
break;
}
uni[api]({
url: toUrl,
animationType: 'slide-in-right',
animationDuration: 200
});
}
// 关闭当前页面并返回上一页面 delta 标识返回几层
export function navigateBack(delta) {
uni.navigateBack({
delta: delta
});
}
// setStorage 将数据存入缓存
export function setStorage(key, val) {
if (typeof val == 'string') {
uni.setStorageSync(key, val);
return val
}
uni.setStorageSync(key, JSON.stringify(val));
}
// getStorage 从缓存中读取数据
export function getStorage(key) {
let uu = uni.getStorageSync(key);
try {
if (typeof JSON.parse(uu) != 'number') {
uu = JSON.parse(uu);
}
} catch (e) {}
return uu;
}
// 删除缓存中的数据
export function removeStorage(key) {
if (key) {
uni.removeStorageSync(key);
}
}
// 将缓存中的数据清空
export function clearStorage() {
try {
uni.clearStorageSync();
} catch (e) {
throw new Error('处理失败');
}
}
// 显示Toast
/*
@title 最多汉字数量7个
@icon success loading none
*/
export function Toast(title, icon = 'none', obj = {}, duration = 800) {
let toastData = {
title: title,
duration: duration,
position: 'center',
mask: true,
icon: icon ? icon : 'none',
...obj
};
uni.showToast(toastData);
}
/*
显示loading提示框,需要手动隐藏
*/
export function Loading(title = '正在加载...', obj = {}) {
uni.showLoading({
title: title,
mask: true,
...obj
});
}
// 隐藏loading
export function hideLoading() {
try {
uni.hideLoading();
} catch (e) {
//TODO handle the exception
throw new Error('处理失败');
}
}
// 模态框
/*
确定取消按钮的文字颜色可修改
obj 对象中传入 cancelColor : rgb 即可修改取消按钮颜色
obj 对象中传入 confirmColor : rgb 即可修改确认按钮颜色
*/
export function Modal(title = '提示', content = '这是一个模态弹窗!', obj = {
showCancel: true,
cancelText: '取消',
confirmText: '确定'
}) {
// #ifdef APP-PLUS
obj.cancelText = '确定';
obj.confirmText = '取消';
// #endif
return new Promise((reslove, reject) => {
uni.showModal({
title: title,
content: content,
...obj,
success: (res) => {
if (res.confirm) {
reslove()
}
if (res.cancel) {
reject()
}
}
});
})
}
/*
显示操作菜单
@itemList 操作菜单数组
@itemColor 文字颜色
*/
export function ActionSheet(itemList, itemColor = "#000000") {
return new Promise((reslove, reject) => {
uni.showActionSheet({
itemList: itemList,
itemColor: itemColor,
success: (res) => {
reslove(res.tapIndex);
},
fail: function(res) {
reject(res.errMsg);
}
});
})
}
//将页面滚动到目标位置。
export function ScrollTo(ScrollTop) {
uni.pageScrollTo({
scrollTop: ScrollTop,
duration: 300
})
}
// 获取用户信息
export function GetUserInfo() {
return new Promise((reslove, reject) => {
uni.getUserInfo({
success(res) {
console.log(res);
reslove(res);
},
fail(rej) {
reject(rej);
}
})
})
}
// 获取用户授权信息
export function Authorize(scoped = 'scope.userInfo') {
return new Promise((reslove, reject) => {
uni.authorize({
scope: scoped,
success(res) {
reslove(res);
},
fail(rej) {
reject(rej);
}
})
})
}
// 将对象转换成使用 & 连接的字符串
export function convertObj(opt) {
let str = '';
let arr = [];
Object.keys(opt).forEach(item => {
arr.push(`${item}=${opt[item]}`);
})
str = arr.join('&');
return str;
}
// 节流函数
// 节流函数
export function throttle(fn, delay) {
var lastArgs;
var timer;
var delay = delay || 200;
return function(...args) {
lastArgs = args;
if (!timer) {
timer = setTimeout(() => {
timer = null;
fn.apply(this, lastArgs);
}, delay);
}
}
}
// 调起相机
export function chooseImage(count) {
return new Promise((reslove, reject) => {
uni.chooseImage({
count: count, //默认9
sizeType: ['original', 'compressed'], //可以指定是原图还是压缩图,默认二者都有
sourceType: ['album', 'camera'], //从相册选择
success: (res) => {
reslove(res);
// const tempFilePaths = res.tempFilePaths;
// let tempPathList = [];
// for (let i = 0; i < tempFilePaths.length; i++) {
// const path = tempFilePaths[i];
// const src = await compressImageHandler(path)
// tempPathList.push(src);
// }
// reslove(tempPathList);
},
fail: (rej) => {
reject(rej);
}
});
})
}
// function compressImageHandler(src) {
// // console.log('platform===' + device.platform)
// const tempPath = compressImage(src, device.platform);
// // console.log('tempPath-----' + tempPath);
// return tempPath
// }
//序列化对象和数组
export function serialize(data) {
if (data != null && data != '') {
try {
return JSON.parse(JSON.stringify(data));
} catch (e) {
if (data instanceof Array) {
return [];
}
return {};
}
}
return data;
}
Date.prototype.format = function(fmt) {
let o = {
'M+': this.getMonth() + 1, //月份
'd+': this.getDate(), //日
'h+': this.getHours(), //小时
'm+': this.getMinutes(), //分
's+': this.getSeconds(), //秒
'q+': Math.floor((this.getMonth() + 3) / 3), //季度
S: this.getMilliseconds() //毫秒
};
if (/(y+)/.test(fmt)) {
fmt = fmt.replace(RegExp.$1, String(this.getFullYear()).substr(4 - RegExp.$1.length));
}
for (let k in o) {
if (new RegExp('(' + k + ')').test(fmt)) {
fmt = fmt.replace(RegExp.$1, RegExp.$1.length == 1 ? o[k] : ('00' + o[k]).substr(String(o[k]).length));
}
}
return fmt;
};
//格式化日期
export function formatDate(nS, format) {
//日期格式化
if (!nS) {
return '';
}
format = format || 'yyyy-MM-dd hh:mm:ss';
return new Date(nS).format(format);
}
// 图片转base64
export function pathToBase64(path) {
return new Promise(function(resolve, reject) {
if (typeof window === 'object' && 'document' in window) {
if (typeof FileReader === 'function') {
var xhr = new XMLHttpRequest()
xhr.open('GET', path, true)
xhr.responseType = 'blob'
xhr.onload = function() {
if (this.status === 200) {
let fileReader = new FileReader()
fileReader.onload = function(e) {
resolve(e.target.result)
}
fileReader.onerror = reject
fileReader.readAsDataURL(this.response)
}
}
xhr.onerror = reject
xhr.send()
return
}
var canvas = document.createElement('canvas')
var c2x = canvas.getContext('2d')
var img = new Image
img.onload = function() {
canvas.width = img.width
canvas.height = img.height
c2x.drawImage(img, 0, 0)
resolve(canvas.toDataURL())
canvas.height = canvas.width = 0
}
img.onerror = reject
img.src = path
return
}
if (typeof plus === 'object') {
plus.io.resolveLocalFileSystemURL(getLocalFilePath(path), function(entry) {
entry.file(function(file) {
var fileReader = new plus.io.FileReader()
fileReader.onload = function(data) {
resolve(data.target.result)
}
fileReader.onerror = function(error) {
reject(error)
}
fileReader.readAsDataURL(file)
}, function(error) {
reject(error)
})
}, function(error) {
reject(error)
})
return
}
if (typeof wx === 'object' && wx.canIUse('getFileSystemManager')) {
wx.getFileSystemManager().readFile({
filePath: path,
encoding: 'base64',
success: function(res) {
resolve('data:image/png;base64,' + res.data)
},
fail: function(error) {
reject(error)
}
})
return
}
reject(new Error('not support'))
})
}
/*
@value 要拷贝的内容
*/
// export function copyText(value) {
// // 条件编译以下代码仅在H5出现
// //#ifdef H5
// return new Promise((reslove, reject) => {
// uniCopy({
// content: value,
// success: (res) => {
// reslove(res);
// },
// error: (e) => {
// reject(res)
// }
// })
// })
// //#endif
// // 以下代码在除H5以外的平台出现
// //#ifndef H5
// //#endif
// }
// 获取本周的第一天
export function showWeekFirstDay() {
var date = new Date();
var weekday = date.getDay() || 7; //获取星期几,getDay()返回值是 0周日 到 6周六 之间的一个整数。0||7为7即weekday的值为1-7
date.setDate(date.getDate() - weekday + 1); //往前算weekday-1年份、月份会自动变化
return formatDate(date, 'yyyy-MM-dd');
}
// 获取本月第一天
export function showMonthFirstDay() {
var MonthFirstDay = new Date().setDate(1);
return formatDate(new Date(MonthFirstDay).getTime(), 'yyyy-MM-dd');
}
var now = new Date(); //当前日期
// var nowDayOfWeek = now.getDay(); //今天本周的第几天
// var nowDay = now.getDate(); //当前日
var nowMonth = now.getMonth(); //当前月
var nowYear = now.getYear(); //当前年
nowYear += (nowYear < 2000) ? 1900 : 0; //
//获得本季度的开始月份
function getQuarterStartMonth() {
var quarterStartMonth = 0;
if (nowMonth < 3) {
quarterStartMonth = 0;
}
if (2 < nowMonth && nowMonth < 6) {
quarterStartMonth = 3;
}
if (5 < nowMonth && nowMonth < 9) {
quarterStartMonth = 6;
}
if (nowMonth > 8) {
quarterStartMonth = 9;
}
return quarterStartMonth;
}
//或的本季度的结束日期
//获得本季度的开始日期
export function getQuarterStartDate() {
var quarterStartDate = new Date(nowYear, getQuarterStartMonth(), 1);
return formatDate(quarterStartDate, 'yyyy-MM-dd');
}
// 删除数组中重复数据
export function unique(data) {
data = data || [];
var n = {}; //存放新的数据
for (var i = 0; i < data.length; i++) {
var v = JSON.stringify(data[i]);
if (typeof(v) == "undefined") {
n[v] = 1;
}
}
data.length = 0;
for (var i in n) {
data[data.length] = i;
}
return data;
}

25
nk-oa/main.js Normal file
View File

@ -0,0 +1,25 @@
import App from './App'
import store from './store'
import uView from '@/uni_modules/uview-ui'
Vue.use(uView)
// #ifndef VUE3
import Vue from 'vue'
Vue.config.productionTip = false
App.mpType = 'app'
const app = new Vue({
...App,
store
})
app.$mount()
// #endif
// #ifdef VUE3
import { createSSRApp } from 'vue'
export function createApp() {
const app = createSSRApp(App)
return {
app
}
}
// #endif

72
nk-oa/manifest.json Normal file
View File

@ -0,0 +1,72 @@
{
"name": "nk-oa",
"appid": "__UNI__7F12D2D",
"description": "",
"versionName": "1.0.0",
"versionCode": "100",
"transformPx": false,
/* 5+App */
"app-plus": {
"usingComponents": true,
"nvueStyleCompiler": "uni-app",
"compilerVersion": 3,
"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": {},
/* SDK */
"sdkConfigs": {}
}
},
/* */
"quickapp": {},
/* */
"mp-weixin": {
"appid": "wx6e14cb98394e36bc",
"setting": {
"urlCheck": false
},
"usingComponents": true
},
"mp-alipay": {
"usingComponents": true
},
"mp-baidu": {
"usingComponents": true
},
"mp-toutiao": {
"usingComponents": true
},
"uniStatistics": {
"enable": false
},
"vueVersion": "2"
}

137
nk-oa/pages.json Normal file
View File

@ -0,0 +1,137 @@
{
"pages": [ //pageshttps://uniapp.dcloud.io/collocation/pages
{
"path": "pages/oaHome/oaHome",
"style": {
"navigationBarTitleText": "首页",
"enablePullDownRefresh": true
}
},
{
"path": "pages/index/index",
"style": {
"navigationBarTitleText": "uni-app"
}
},
{
"path": "pages/oaExamine/oaExamine",
"style": {
"navigationBarTitleText": "审批"
}
},
{
"path": "pages/oaTask/oaTask",
"style": {
"navigationBarTitleText": "新建任务"
}
},
{
"path": "pages/oaMy/oaMy",
"style": {
"navigationBarTitleText": "我的"
}
}
],
"subPackages": [{
"root": "pages/views",
"name": "views",
"pages": [{
"path": "application",
"style": {
"navigationBarTitleText": "地图首页",
"enablePullDownRefresh": false
}
},
{
"path": "new_task",
"style": {
"navigationBarTitleText": "新建任务",
"enablePullDownRefresh": false
}
},
{
"path": "com_approve",
"style": {
"navigationBarTitleText": "通用审批",
"enablePullDownRefresh": false
}
}, {
"path": "personal_center",
"style": {
"navigationBarTitleText": "个人中心1",
"enablePullDownRefresh": false
}
}, {
"path": "task_details",
"style": {
"navigationBarTitleText": "",
"enablePullDownRefresh": false
}
}, {
"path": "personal_center_two",
"style": {
"navigationBarTitleText": "个人中心2",
"enablePullDownRefresh": false
}
}, {
"path": "public_document",
"style": {
"navigationBarTitleText": "公司公示文档",
"enablePullDownRefresh": false
}
}
, {
"path": "leave_request",
"style": {
"navigationBarTitleText": "请假申请",
"enablePullDownRefresh": false
}
}
]
}],
"globalStyle": {
"navigationBarTextStyle": "black",
"navigationBarTitleText": "uni-app",
"navigationBarBackgroundColor": "#F8F8F8",
"backgroundColor": "#F8F8F8"
},
"tabBar": {
"color": "#282828",
"selectedColor": "#3175f9",
"borderStyle": "white",
"backgroundColor": "#ffffff",
"list": [{
"pagePath": "pages/oaHome/oaHome",
"text": "首页",
"iconPath": "/static/tabs-icon/home.png",
"selectedIconPath": "/static/tabs-icon/home-a.png"
},
{
"pagePath": "pages/oaExamine/oaExamine",
"text": "审批",
"iconPath": "/static/tabs-icon/approval.png",
"selectedIconPath": "/static/tabs-icon/approval-a.png"
},
{
"pagePath": "pages/oaTask/oaTask",
"text": "新建任务",
"iconPath": "/static/tabs-icon/Task.png",
"selectedIconPath": "/static/tabs-icon/Task-a.png"
},
{
"pagePath": "pages/oaMy/oaMy",
"text": "我的",
"iconPath": "/static/tabs-icon/my.png",
"selectedIconPath": "/static/tabs-icon/my-a.png"
}
]
},
"uniIdRouter": {}
}

View File

@ -0,0 +1,52 @@
<template>
<view class="content">
<image class="logo" src="/static/logo.png"></image>
<view class="text-area">
<text class="title">{{title}}</text>
</view>
</view>
</template>
<script>
export default {
data() {
return {
title: 'Hello'
}
},
onLoad() {
},
methods: {
}
}
</script>
<style>
.content {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
}
.logo {
height: 200rpx;
width: 200rpx;
margin-top: 200rpx;
margin-left: auto;
margin-right: auto;
margin-bottom: 50rpx;
}
.text-area {
display: flex;
justify-content: center;
}
.title {
font-size: 36rpx;
color: #8f8f94;
}
</style>

View File

@ -0,0 +1,260 @@
<template>
<view class="all_box">
<!-- 审批选项 -->
<view class="examine_box">
<u-tabs :list="list1" @click="click" lineColor='#3274F9' lineWidth='77rpx' inactiveStyle='color:#666'
activeStyle="color:#3274F9"></u-tabs>
</view>
<!-- 事项 -->
<view class="out_box">
<view class="eventList_box" v-for="item in myEventList" :key="item.id">
<view class="banner">
<view class="title">{{item.name}}</view>
<view class="department">{{item.department_name ? item.department_name : '' }}</view>
<view v-if="item.check_status==0" class="wait">待审核</view>
<view v-if="item.check_status==1" class="underway">审核中</view>
<view v-if="item.check_status==2" class="pass">审核通过</view>
<view v-if="item.check_status==3" class="refuse">审核不通过</view>
<view v-if="item.check_status==4" class="withdraw">撤回审核</view>
</view>
<view class="line"></view>
<view class="task_approval">{{item.content}}</view>
<view class="approval_time">{{item.create_time}}</view>
</view>
</view>
<u-loadmore :status="status" :loading-text="loadingText" :loadmore-text="loadmoreText" :nomore-text="nomoreText" />
<!-- <tabbar></tabbar> -->
</view>
</template>
<script>
import {
getApproveMyListAPI,
getHandleListAPI,
getCopyOfMyListAPI
} from '@/api/oaApi.js'
// import tabbar from '../components/tabbar'
export default {
components: {
// tabbar
},
data() {
return {
list1: [{
name: '我发起的',
}, {
name: '我处理的',
}, {
name: '抄送给我的'
}, ],
myEventList: [],
params: {
limit: '8', //
page: '1',
},
last_page: '',
status: 'loadmore',
loadingText: '努力加载中',
loadmoreText: '轻轻上拉',
nomoreText: '我也是有底线的~~',
flag: '0', //
}
},
onReady() {
uni.setNavigationBarColor({
frontColor: '#ffffff',
backgroundColor: '#3175f9'
})
},
onLoad() {
this.myEventList = []
this.getApproveMyList(this.params)
},
onShow() {
},
methods: {
//
async getHandleList(data) {
const res = await getHandleListAPI(data)
this.publicMethods(res)
},
//
async getApproveMyList(data) {
const res = await getApproveMyListAPI(data)
this.publicMethods(res)
},
//
async getCopyOfMyList(data) {
const res = await getCopyOfMyListAPI(data)
this.publicMethods(res)
},
//1
publicMethods(res) {
console.log(res);
this.myEventList = [...this.myEventList, ...res.data]
if (this.myEventList.length < this.params.limit) {
this.status = 'nomore'
}
this.last_page = res.last_page
},
//2
publicMethods2(fun) {
if (this.params.page < this.last_page) {
this.params.page++
fun(this.params)
} else {
this.status = 'nomore'
return
}
},
click(item) {
this.myEventList = []
this.params.page = '1'
switch (item.index) {
case 0:
this.flag = '0'
this.getApproveMyList(this.params)
break;
case 1:
this.flag = '1'
this.getHandleList(this.params)
break;
case 2:
this.flag = '2'
this.getCopyOfMyList(this.params)
break;
}
}
},
onPullDownRefresh() {
uni.stopPullDownRefresh()
},
onReachBottom() {
if (this.flag == '0') {
this.publicMethods2(this.getApproveMyList)
} else if (this.flag == '1') {
this.publicMethods2(this.getHandleList)
} else {
this.publicMethods2(this.getCopyOfMyList)
}
},
filters: {
formatDate(nS, format) {
return new Date(nS).format('yyyy-MM-dd hh:mm:ss');
}
}
}
</script>
<style lang="scss" scoped>
/deep/.u-tabs__wrapper__nav__item {
// padding: 0 56rpx;
height: 77rpx !important;
}
/deep/.u-tabs__wrapper__nav__item__text {
font-size: 32rpx;
}
/deep/.u-tabs__wrapper__nav {
height: 77rpx;
// justify-content: space-between;
}
/deep/.u-tabs__wrapper__nav__item-1 {
flex-grow: 2;
}
.all_box {
padding-bottom: 21rpx;
}
.examine_box {
position: fixed;
top: 0;
width: 750rpx;
height: 77rpx;
background: #FFFFFF;
}
.out_box {
padding-top: 75rpx;
}
.eventList_box {
margin: 0 auto;
margin-top: 21rpx;
width: 694rpx;
min-height: 221rpx;
background: #FFFFFF;
border-radius: 7rpx;
padding: 0 24.53rpx 10.53rpx 24.53rpx;
.banner {
display: flex;
align-items: center;
flex: 1 1 3;
width: 100%;
height: 82rpx;
font-size: 32rpx;
.title {
// width: 438.6rpx;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.department {
color: $theme-oa-color;
font-size: 25rpx;
margin-left: 17.52rpx;
flex-grow: 2;
}
.underway {
color: #34A853;
}
.pass {
color: $theme-oa-color;
}
.wait {
color: #F9AA32;
}
.refuse {
color: #F02828;
}
.withdraw {
color: #CCCCCC;
}
}
.line {
margin: 0 auto;
width: 646rpx;
height: 0rpx;
border-bottom: 1rpx solid #CCCCCC;
margin-bottom: 14.02rpx;
}
.task_approval {
font-size: 28rpx;
margin-bottom: 26rpx;
}
.approval_time {
font-size: 25rpx;
color: #999;
// position: relative;
}
}
</style>

View File

@ -0,0 +1,389 @@
<template>
<view class="oa_home" style="oaColor">
<view class="home_header">
<view class="my_info flex_a_c">
<view class="">
<u--image :showLoading="true" :src="myOaInfo.thumb" width="64px" height="64px" shape="circle"></u--image>
</view>
<view class="mesg_box">
<view class="name">{{ myOaInfo.name }} {{ myOaInfo.mobile }}</view>
<view class="duty">({{ myOaInfo.did_name }}){{myOaInfo.label_name}}</view>
</view>
</view>
<view class="task_panel">
<block v-for="(item,index) in assessData" :key="index">
<view class="task_item">
<view class="plan">{{ item.num }}</view>
<view class="">{{ item.name }}</view>
</view>
</block>
</view>
<view class="backlog">
<view class="">待办事项</view>
<block v-for="(item,index) in ApproveList.slice(0,2)" :key="index">
<view class="backlog_item flex_a_c_j_sb" @click="backlogDetails">
<view class="text">{{ item.content }}</view>
<i class="iconfont icon-you"></i>
</view>
</block>
</view>
</view>
<view class="fast_track">
<block v-for="(item,index) in oaHomeData" :key="index">
<view class="track_item" @click="navTo(item.url)">
<u--image :showLoading="true" :src="item.icon" width="77.19rpx" height="77.19rpx"></u--image>
<view class="title">{{ item.text }}</view>
</view>
</block>
</view>
<view class="my_task">
<view class="head_title flex_a_c_j_sb">
<view class="">我的任务</view>
<view class="flex_a_c" @click="test">更多 <view class="iconfont icon-you"></view>
</view>
</view>
<block v-for="(item,index) in myTaskList" :key="index">
<view class="task_list" @click="naviTaskDetails(item.id)">
<view class="title flex_a_c_j_sb">
<view class="flex_a_c">
<view v-if="item.priority==4" class="tag">{{ item.priority_name }}</view>
<view v-else class="tag1">{{ item.priority_name }}</view>
<view class="text">{{ item.title }}</view>
</view>
<view v-if="item.flow_status==1" class="if_take take1">{{ item.flow_name }}</view>
<view v-else-if="item.flow_status==2" class="if_take take2">{{ item.flow_name }}</view>
<view v-else="item.flow_status==3" class="if_take take3">{{ item.flow_name }}</view>
</view>
<view class="describe">{{ item.content }}</view>
<view class="task_deta flex_a_c_j_sb">
<view class="">任务性质{{ item.is_bug }}</view>
<view class="">计划完成日期{{ item.end_time }}</view>
</view>
</view>
</block>
</view>
<!-- <tabbar></tabbar> -->
</view>
</template>
<script>
import { Toast } from '@/libs/uniApi.js'
import { oaHomeData } from '@/static/server/server.js'
// import tabbar from '../components/tabbar'
import { getIndexListAPI, getTaskListAPI, getMyTaskListAPI, getApproveListAPI, getUserIndexAPI } from '@/api/oaApi.js'
export default {
components: {
// tabbar
},
data() {
return {
oaHomeData: oaHomeData,
src: 'https://cdn.uviewui.com/uview/album/1.jpg',
assessData: [{
num: '8',
name: '部门计划'
},
{
num: '8',
name: '已完成'
},
{
num: '0',
name: '未完成'
},
{
num: '100%',
name: '完成率'
},
{
num: '10',
name: '岗位任务'
},
{
num: '10',
name: '岗位任务'
},
{
num: '0',
name: '未完成'
},
{
num: '100%',
name: '完成率'
}
],
project: {},
task: {},
page: 1,
myTaskList: [],
flowState: '#47B347', //
priority: '', //
myOaInfo: {
thumb: '',
name: '',
mobile: '',
did_name: '',
label_name: '',
},
ApproveList: []
}
},
onReady() {
uni.setNavigationBarColor({
frontColor: '#ffffff',
backgroundColor: '#3175f9'
})
},
onLoad() {},
onShow() {
this.getUserIndex()
this.getIndexList()
this.getApproveList()
},
computed: {},
methods: {
test() {
wx.chooseMessageFile({
count: 1, //
type: 'all', //,all
//type:'video',//
//type:'image',//
success(res) {
const tempFilePaths = res.tempFiles
console.log(res);
}
})
},
async getApproveList() {
const res = await getApproveListAPI({ status: 1 })
this.ApproveList = res.data
},
async getIndexList() {
const { project, task } = await getIndexListAPI()
console.log(task, '222');
this.assessData[0].num = project.count
this.assessData[1].num = project.count_ok
this.assessData[2].num = project.count_no
this.assessData[3].num = project.count_lv + '%'
this.assessData[4].num = task.count
this.assessData[5].num = task.count_ok
this.assessData[6].num = task.count_no
this.assessData[7].num = task.count_lv + '%'
this.myTaskList = task.list
},
async getMyTask() {
let data = {
page: this.page,
limit: 10
}
const res = getMyTaskListAPI(data)
},
naviTaskDetails(id) {
uni.navigateTo({
url: `/pages/views/task_details?id=${id}`
})
},
navTo(url) {
url ?
uni.navigateTo({
url: url
}) : Toast('暂未开放')
},
backlogDetails() {
Toast('点击待办事项')
},
async getUserIndex() {
const res = await getUserIndexAPI()
this.myOaInfo = res
}
},
onPullDownRefresh() {
this.getIndexList()
uni.stopPullDownRefresh()
}
}
</script>
<style lang="scss">
.oa_home {
padding-bottom: 120rpx;
}
.home_header {
position: relative;
padding: 28.07rpx;
height: 607.02rpx;
width: 100%;
background-color: $theme-oa-color;
margin-bottom: 133.33rpx;
.my_info {
.mesg_box {
color: #fff;
margin-left: 31.58rpx;
.duty {
margin-top: 10.53rpx;
}
}
}
.task_panel {
color: #fff;
display: flex;
justify-content: space-between;
flex-wrap: wrap;
align-content: space-between;
text-align: center;
.task_item {
margin-top: 42.11rpx;
.plan {
width: 173.68rpx;
font-size: 38.6rpx;
margin-bottom: 21.05rpx;
}
}
}
.backlog {
position: absolute;
left: 50%;
bottom: -101.75rpx;
transform: translate(-50%);
width: 694.74rpx;
min-height: 221.05rpx;
background: #FFFFFF;
border-radius: 12px;
padding: 28.07rpx;
display: flex;
flex-direction: column;
justify-content: space-between;
&_item {
margin-top: 19.3rpx;
color: #666666;
.text {
&::before {
content: '提醒';
display: inline-block;
color: #FF8C1A;
padding: 2px 8px;
border-radius: 4px;
border: 1px solid #FF8C1A;
margin-right: 14.04rpx;
}
}
}
}
}
.fast_track {
width: 694.74rpx;
height: 361.4rpx;
display: flex;
flex-wrap: wrap;
justify-content: space-between;
align-content: space-between;
margin: 0 auto;
padding: 28.07rpx 38.6rpx;
background-color: #fff;
border-radius: 12px;
.track_item {
width: 154.39rpx;
font-size: 24.56rpx;
display: flex;
flex-direction: column;
align-items: center;
.title {
margin-top: 14.04rpx;
}
}
}
.my_task {
width: 694.74rpx;
margin: 0 auto;
margin-top: 31.58rpx;
background-color: #fff;
border-radius: 12px;
padding: 28.07rpx;
.task_list {
height: 196.49rpx;
border-bottom: 1px solid #CCCCCC;
padding: 21.05rpx 0;
display: flex;
flex-direction: column;
justify-content: space-between;
.title {
.tag {
color: #F24848;
font-size: 24.56rpx;
padding: 0 7.02rpx;
margin-right: 14.04rpx;
background: #FFE4E4;
border-radius: 4px;
}
.tag1 {
color: #3274F9;
font-size: 24.56rpx;
padding: 0 7.02rpx;
margin-right: 14.04rpx;
background: #E4EDFF;
border-radius: 4px;
}
.text {
font-size: 28.07rpx;
width: 403.51rpx;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.if_take {
font-size: 28.07rpx;
text-align: center;
line-height: 49.12rpx;
width: 115.79rpx;
height: 49.12rpx;
border-radius: 100px;
}
.take1 {
color: #47B347;
background: #DFFCDF;
}
.take2 {
color: #3274F9;
background: #E4EDFF;
}
.take3 {
color: #999999;
background: #F5F5F5;
}
}
.describe {
font-size: 24.56rpx;
}
.task_deta {
color: #999;
font-size: 24.56rpx;
}
}
}
</style>

227
nk-oa/pages/oaMy/oaMy.vue Normal file
View File

@ -0,0 +1,227 @@
<template>
<view class="">
<view class="my_head">
<view class="department flex_a_c">
<view class="section">产品技术部</view>
<view class="" @click="login">去登陆</view>
</view>
</view>
<view class="personage">
<view class="my_msg flex_a_c_j_sb">
<view class="flex_a_c">
<u--image :showLoading="true" :src="oaUserInfo.thumb" width="112.28rpx" height="112.28rpx" shape="circle">
</u--image>
<view class="name_work">
<view class="name">
<text>{{ oaUserInfo.did_leader }}</text>
<text>{{ oaUserInfo.mobile }}</text>
</view>
<view class="work">
{{ oaUserInfo.did_name }}({{ oaUserInfo.label_name }})
</view>
</view>
</view>
<view class="compile" @click="alterMyInfo">
<view class="iconfont icon-bianji"></view>
<view class="">编辑</view>
</view>
</view>
<view class="assess">
<view class="ass_cent flex_a_c_j_sb">
<view class="cent_item">
<view class="num">{{ oaUserInfo.achievements_money }}</view>
<view class="name">绩效考核</view>
</view>
<view class="cent_item">
<view class="num">{{ oaUserInfo.department_money }}</view>
<view class="name">部门奖金</view>
</view>
<view class="cent_item">
<view class="num">{{ oaUserInfo.company_money }}</view>
<view class="name">公司奖金</view>
</view>
</view>
</view>
</view>
<view class="other_guide">
<block v-for="(item,i) in myOaData" :key="i">
<view class="other_item flex_a_c_j_sb" @click="naviTo(item.url)">
<view class="flex_a_c">
<view class="iconfont2" :class="item.icon"></view>
<view class="text">{{ item.name }}</view>
</view>
<view class="iconfont icon-you"></view>
</view>
</block>
</view>
<view class="log_out">退出登录</view>
<!-- <tabbar></tabbar> -->
</view>
</template>
<script>
import { mapActions } from 'vuex'
import { getUserIndexAPI } from '@/api/oaApi.js'
import { Toast } from '@/libs/uniApi.js'
import { myOaData } from '@/static/server/server.js'
// import tabbar from '../components/tabbar'
export default {
components: {
// tabbar
},
data() {
return {
myOaData: myOaData,
src: 'https://cdn.uviewui.com/uview/album/1.jpg',
oaUserInfo: {}
}
},
onReady() {
uni.setNavigationBarColor({
frontColor: '#ffffff',
backgroundColor: '#3175f9'
})
},
onLoad() {
this.getOaUserInfo()
},
onShow() {},
methods: {
...mapActions(['getWxLogin']),
login() {
// #ifndef H5 || APP
// #endif
// #ifdef MP-WEIXIN || MP
this.getWxLogin()
// #endif
},
async getOaUserInfo() {
const res = await getUserIndexAPI()
console.log(res, '111');
this.oaUserInfo = res
},
naviTo(url) {
url ?
uni.navigateTo({
url: url
}) : Toast('暂未开放')
},
alterMyInfo() {
uni.navigateTo({
url: '/pages/views/personal_center'
})
}
},
onPullDownRefresh() {
this.getOaUserInfo()
uni.stopPullDownRefresh()
}
}
</script>
<style lang="scss">
.my_head {
padding: 0 28.07rpx;
height: 154.39rpx;
background-color: $theme-oa-color;
.department {
padding-top: 38.6rpx;
font-size: 31.58rpx;
color: #fff;
.section {
margin-right: 57.89rpx;
}
}
}
.personage {
position: relative;
padding: 42.11rpx 28.07rpx;
border-radius: 12px;
background-color: #fff;
width: 694.74rpx;
margin-left: 50%;
transform: translate(-50%, -43.86rpx);
.name_work {
margin-left: 31.58rpx;
font-size: 28.07rpx;
.work {
margin-top: 14.04rpx;
}
}
.my_msg {
.compile {
display: flex;
flex-direction: column;
align-items: center;
}
}
.assess {
height: 170.18rpx;
}
.ass_cent {
width: 100%;
padding: 31.58rpx 66.67rpx;
position: absolute;
left: 0;
bottom: 0;
height: 170.18rpx;
border-radius: 12px;
background-color: $theme-oa-color;
.cent_item {
font-size: 24.56rpx;
color: #fff;
text-align: center;
.num {
font-size: 38.6rpx;
margin-bottom: 21.05rpx;
}
}
}
}
.other_guide {
width: 694.74rpx;
margin: 0 auto;
padding: 28.07rpx;
background-color: #fff;
border-radius: 12px;
.other_item {
height: 87.72rpx;
border-bottom: 1px solid #F0F5F7;
.text {
font-size: 28.07rpx;
margin-left: 24.56rpx;
}
.iconfont2 {
font-size: 42.11rpx;
}
}
}
.log_out {
color: #fff;
border-radius: 100px;
text-align: center;
line-height: 84.21rpx;
margin: 0 auto;
margin-top: 84.21rpx;
width: 614.04rpx;
height: 84.21rpx;
background: #3274F9;
box-shadow: 0px 9px 26px 1px #E9EFF5;
}
</style>

View File

@ -0,0 +1,344 @@
<template>
<view class="all_box">
<!-- 任务搜索框 -->
<view class="task_box">
<u-search shape="round" placeholder="搜索任务状态、优先级、部门等"></u-search>
<!-- 筛选按钮 -->
<view>
<u-popup :show="show" @close="close" @open="open" mode="top" overlayStyle="position: fixed;top:100rpx">
<view class="search_box">
<view class="">
<view class="first_order" v-for="item in orderData" :key="item.id" :class="item.id==typeid?'choose':''">
<text>{{item.first_order}}</text>
</view>
</view>
<view class="second_order">
<view class="second" v-for="item in orderList" :key="item.id" @click="getInfo(item.info,item.id)">
{{item.info}}
</view>
</view>
</view>
</u-popup>
<view @click="show = true" class="screening" :class="show?'choose_style':''">筛选</view>
</view>
</view>
<!-- 新建任务 -->
<view class="new_task" @click="goNewTask">+新建任务</view>
<!-- 事件列表 -->
<view class="eventList_box" v-for="item in eventData" :key="item.id">
<view class="head_box">
<text class="title">{{item.title}}</text>
<text class="status" :class="item.status=='驳回'?'another_color':''">{{item.flow_name}}</text>
</view>
<view class="line"></view>
<view class="responsible">
<text>负责人:{{item.director_name}}</text>
<text class="department">{{item.did_name ? item.did_name :'' }}</text>
</view>
<view class="responsible">
<text>协办人:{{item.assist_admin_names}}</text>
</view>
<view class="responsible">
<text>发布人:{{item.admin_name}}</text>
</view>
<view class="responsible">
<text v-if="item.is_bug==0">任务性质:部门工作</text>
<text v-if="item.is_bug==1">任务性质:部门协助</text>
<text v-if="item.is_bug==2">任务性质:临时任务</text>
</view>
<view class="end_time">预计结束时间:{{item.end_time}}</view>
</view>
<u-loadmore :status="status" :loading-text="loadingText" :loadmore-text="loadmoreText" :nomore-text="nomoreText" />
<!-- <tabbar></tabbar> -->
</view>
</template>
<script>
import { getTaskListApi } from '@/api/oa'
// import tabbar from '../components/tabbar'
export default {
components: {
// tabbar
},
data() {
return {
status: 'loadmore',
params: {
page: '1',
limit: '10',
flow_status: "1",
},
lastpage: '',
loadingText: '努力加载中',
loadmoreText: '轻轻上拉',
nomoreText: '我也是有底线的~~',
orderList: [{
id: 1,
info: '未开始'
}, {
id: 2,
info: '进行中'
}, {
id: 3,
info: '待验收'
}, {
id: 5,
info: '已关闭'
}, {
id: 6,
info: '已验收'
}, ],
orderData: [{
id: 1,
first_order: '任务状态',
}, ],
show: false,
typeid: 1,
eventData: [],
}
},
onReady() {
uni.setNavigationBarColor({
frontColor: '#ffffff',
backgroundColor: '#3175f9'
})
},
onLoad() {
},
onShow() {
this.params.page = '1'
this.eventData = []
//
this.getTaskList(this.params)
},
onPageScroll() {
//
this.close()
},
methods: {
//
async getTaskList(data) {
const res = await getTaskListApi(data)
this.eventData = [...this.eventData, ...res.data]
if (this.eventData.length < this.params.limit) {
this.status = 'nomore'
}
this.lastpage = res.last_page
},
open() {
},
close() {
this.show = false
},
//
getInfo(val, status) {
this.eventData = []
this.params = {
page: '1',
limit: '10',
flow_status: status
}
this.params.flow_status = status + ''
this.getTaskList(this.params)
this.close()
},
//
goNewTask() {
uni.navigateTo({
url: "/pages/views/new_task"
})
}
},
onPullDownRefresh() {
this.close()
uni.stopPullDownRefresh()
},
onReachBottom() {
if (this.params.page < this.lastpage) {
this.params.page++
this.getTaskList(this.params)
// this.status = 'loading'
} else {
this.status = 'nomore'
return
}
},
}
</script>
<style lang="scss" scoped>
/deep/.u-search__content {
width: 527rpx;
height: 63rpx;
}
/deep/.u-search__action--active {
display: none;
}
/deep/.u-search {
width: 527rpx;
height: 63rpx;
display: flex;
flex: none;
}
/deep/.u-popup__content {
top: 100rpx;
}
.all_box {
padding-bottom: 21rpx;
}
.task_box {
margin: 0 auto;
width: 750rpx;
height: 98rpx;
background: #FFFFFF;
display: flex;
align-items: center;
justify-content: space-between;
padding: 0 28rpx;
.screening {
margin-left: 10px;
width: 149rpx;
height: 63rpx;
line-height: 63rpx;
text-align: center;
background: #FFFFFF;
border-radius: 35rpx;
border: 2rpx solid #E6E5E5;
color: #666;
font-size: 28rpx;
}
.choose_style {
background-color: #3274F9;
color: #fff;
}
}
//
.search_box {
width: 750rpx;
// height: 368rpx;
background: #FFFFFF;
display: flex;
.first_order {
width: 250rpx;
height: 73rpx;
text-align: center;
color: #666666;
font-size: 28rpx;
line-height: 73rpx;
background-color: #f5f5f5;
}
.choose {
background-color: #fff;
color: #3274F9;
}
.second_order {
text-align: center;
width: 500rpx;
.second {
line-height: 73rpx;
height: 73rpx;
border-bottom: 2rpx solid #E6E6E6;
}
}
}
//
.new_task {
margin: 0 auto;
margin-top: 21rpx;
width: 500rpx;
height: 66rpx;
line-height: 66rpx;
color: #fff;
text-align: center;
border-radius: 30rpx;
background-color: $theme-oa-color;
}
.eventList_box {
margin: 0 auto;
margin-top: 21rpx;
width: 694rpx;
height: 345rpx;
background: #FFFFFF;
padding: 0 24.5rpx;
border-radius: 7rpx;
.head_box {
width: 100%;
height: 82rpx;
display: flex;
align-items: center;
justify-content: space-between;
.title {
text-overflow: ellipsis;
/* 溢出显示省略号 */
overflow: hidden;
/* 溢出隐藏 */
white-space: nowrap;
/* 强制不换行 */
color: #333333;
width: 445rpx;
font-weight: 500;
font-size: 32rpx;
}
.status {
font-size: 32rpx;
color: #34A853;
}
.another_color {
color: #F9AA32;
}
}
.line {
width: 646rpx;
height: 0rpx;
border-bottom: 1rpx solid #CCCCCC;
margin-bottom: 14.02rpx;
}
.responsible {
width: 100%;
display: flex;
justify-content: space-between;
align-items: center;
height: 39rpx;
font-size: 28rpx;
margin-bottom: 7.01rpx;
.department {
font-size: 25rpx;
color: $theme-oa-color;
}
}
.end_time {
margin-top: 14rpx;
font-size: 25rpx;
color: #999;
}
}
</style>

294
nk-oa/pages/users/login.vue Normal file
View File

@ -0,0 +1,294 @@
<template>
<view class="login_box">
<image class="image" src="https://lihai001.oss-cn-chengdu.aliyuncs.com/public/kk/login-bg.png" mode="">
</image>
<view class="cont_box">
<view class="headline">
<view class="title">里海数字农业平台</view>
<view class="text">输入手机号获取验证码登录</view>
</view>
<view class="form_box">
<view class="from_input">
<view class="phone_iput">
<input type="text" placeholder="输入手机号码" class="text_input" v-model="account">
</view>
<view class="codeIput_box">
<input type="text" placeholder="填写验证码" class="codeIput" v-model="captcha">
<button v-debounce class="code" :disabled="disabled" :class="disabled === true ? 'on' : ''"
@click="handleVerify">
{{ text }}
</button>
</view>
</view>
<view class="protocol">
<checkbox-group class="checkgroup" @change='isAgree=!isAgree'>
<checkbox class="checkbox" :checked="isAgree ? true : false" />
<text class="protocol_text">登录及代表同意<text @click="userAgree" class="font_pro">用户协议</text><text
@click="userPrivacyAgree" class="font_pro">隐私政策</text></text>
</checkbox-group>
</view>
<view class="logon" @click="loginMobile">登录</view>
</view>
</view>
<Verify @success="success" :captchaType="'blockPuzzle'" :imgSize="{ width: '330px', height: '155px' }" ref="verify">
</Verify>
</view>
</template>
<script>
import { mapActions } from 'vuex'
import { LOGO_URL, USER_INFO, EXPIRES_TIME } from '@/config/cache';
import Cache from '@/utils/cache';
import {
loginMobile,
registerVerify,
getSiteAPI
} from '@/api/user'
import Verify from '@/components/verify/verify.vue';
export default {
components: {
Verify
},
data() {
return {
isAgree: true,
account: "",
captcha: '',
}
},
onLoad(e) {
console.log('options', e)
},
methods: {
...mapActions(['MobileLogin']),
handleVerify() {
let that = this;
if (!that.account) return that.$util.Tips({
title: '请输入手机号码'
});
if (!/^1(3|4|5|7|8|9|6)\d{9}$/i.test(that.account)) return that.$util.Tips({
title: '请输入正确的手机号码'
});
if (!that.isAgree) return that.$util.Tips({
title: '请勾选用户协议与隐私政策'
});
that.$refs.verify.show();
},
success(data) {
this.$refs.verify.hide();
this.code(data);
},
async loginMobile() {
//
let that = this;
if (!that.account) return that.$util.Tips({
title: '请输入手机号码'
});
if (!/^1(3|4|5|7|8|9|6)\d{9}$/i.test(that.account)) return that.$util.Tips({
title: '请输入正确的手机号码'
});
if (!that.captcha) return that.$util.Tips({
title: '请输入验证码'
});
if (!/^[\w\d]+$/i.test(that.captcha)) return that.$util.Tips({
title: '请输入正确的验证码'
});
if (!that.isAgree) return that.$util.Tips({
title: '请勾选用户协议与隐私政策'
});
this.MobileLogin({ account: that.account, sms_code: that.sms_code })
loginMobile({
auth_token: uni.getStorageSync('auth_token'),
phone: that.account,
sms_code: that.captcha,
spread: that.$Cache.get("spread"),
// #ifdef APP-PLUS
user_type: 'app',
// #endif
// #ifdef H5
user_type: 'h5',
// #endif
})
.then(({
data
}) => {
let time = data.expires_time - Cache.time();
that.$store.commit("LOGIN", {
'token': data.token,
'time': data.exp
});
that.$store.commit("SETUID", data.user.uid);
that.$store.commit('UPDATE_USERINFO', data.user);
// #ifdef MP
Cache.set(EXPIRES_TIME, data.expires_time, time);
Cache.set(USER_INFO, data.user, time);
// #endif
getSiteAPI().then(res => that.$store.commit('setMyInfo', res))
uni.redirectTo({
url: '/pages/user/index'
});
})
.catch(res => {
that.$util.Tips({
title: res
});
});
},
async code(data) {
let that = this;
if (!that.account) return that.$util.Tips({
title: '请输入手机号码'
});
if (!/^1(3|4|5|7|8|9|6)\d{9}$/i.test(that.account)) return that.$util.Tips({
title: '请输入正确的手机号码'
});
// if (that.formItem == 2) that.type = "register";
await registerVerify({
phone: that.account,
type: 'login',
key: that.keyCode,
// code: that.codeVal,
toke: data.token,
captchaType: 'blockPuzzle',
captchaVerification: data.captchaVerification
})
.then(res => {
that.$util.Tips({
title: res.message
});
that.sendCode();
})
.catch(res => {
that.$util.Tips({
title: res
});
});
},
getPath(url) {
if (url.indexOf("?") != -1) {
url = url.split("?")[0];
console.log(url);
}
return url
},
userAgree() {
uni.navigateTo({
url: '/pages/users/user_about/index?from=sys_user_agree'
})
},
userPrivacyAgree() {
uni.navigateTo({
url: '/pages/users/user_about/index?from=sys_userr_privacy'
})
},
}
}
</script>
<style lang="scss">
page {
background-color: #fff;
}
.login_box {
.image {
width: 750rpx;
height: 812.28rpx;
position: fixed;
top: 0;
left: 0;
z-index: -1;
}
.logon {
width: 526.32rpx;
height: 84.21rpx;
background-color: #009E56;
border-radius: 100px;
color: #fff;
text-align: center;
line-height: 84.21rpx;
font-size: 29.82rpx;
margin-top: 78.95rpx;
margin-left: 50%;
transform: translate(-50%);
}
.cont_box {
position: absolute;
top: 208.77rpx;
left: 50%;
transform: translate(-50%);
width: 682.46rpx;
.headline {
margin-left: 43.86rpx;
color: #fff;
.title {
font-size: 45.61rpx;
font-weight: 700;
}
.text {
font-size: 29.82rpx;
margin-top: 14.04rpx;
}
}
.form_box {
margin-top: 196.49rpx;
width: 682.46rpx;
height: 701.75rpx;
padding: 61.4rpx;
background: #FFFFFF;
box-shadow: 0px 3px 6px 1px rgba(0, 106, 53, 0.2);
border-radius: 16px 16px 16px 16px;
.protocol {
margin-top: 70.18rpx;
font-size: 26.32rpx;
.checkgroup {
display: flex;
align-items: center;
.font_pro,
.font_pro {
color: #68A2FF;
}
}
}
.from_input {
.phone_iput,
.codeIput_box {
display: flex;
align-items: center;
height: 87.72rpx;
border-bottom: 1px solid #b7b7b7;
}
.codeIput_box {
display: flex;
justify-content: space-between;
margin-top: 47.37rpx;
.code {
font-size: 29.82rpx;
color: #68A2FF;
}
.on {
color: #AEAEAE;
}
}
}
}
}
}
</style>

View File

@ -0,0 +1,102 @@
<template>
<view class="application">
<block v-for="item in appDataList" :key="item.title">
<view class="apply_line">
<view class="title flex_a_c">
<view class="text flex_a_c">
{{ item.title }}
</view>
</view>
<view class="line_cent">
<block v-for="(itemData,i) in item.data" :key="i">
<view class="line_item" @click="lineCentClick(itemData.url)">
<u--image :showLoading="true" :src="itemData.src" width="77.19rpx" height="77.19rpx"></u--image>
<view class="name">{{ itemData.name }}</view>
</view>
</block>
</view>
</view>
</block>
</view>
</template>
<script>
import { Toast } from '@/libs/uniApi.js'
import { appDataList } from '@/static/server/server.js'
export default {
data() {
return {
appDataList: appDataList,
src: 'https://cdn.uviewui.com/uview/album/1.jpg'
}
},
onReady() {
uni.setNavigationBarColor({
frontColor: '#ffffff',
backgroundColor: '#3175f9'
})
},
onLoad() {},
onShow() {},
methods: {
lineCentClick(url) {
url.length > 0 ? uni.navigateTo({
url: url
}) : Toast('暂未开放')
}
},
onPullDownRefresh() {
uni.stopPullDownRefresh()
}
}
</script>
<style lang="scss">
.application {}
.apply_line {
width: 100%;
padding: 0 28.07rpx;
background-color: #fff;
margin-bottom: 31.58rpx;
.title {
width: 100%;
height: 77.19rpx;
border-bottom: 1px solid rgba(204, 204, 204, 0.5);
.text {
font-size: 31.58rpx;
&::before {
content: '';
display: inline-block;
width: 2px;
height: 33.33rpx;
background-color: $theme-oa-color;
margin-right: 10.53rpx;
}
}
}
.line_cent {
display: flex;
flex-wrap: wrap;
.line_item {
width: 231.58rpx;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
padding: 28.07rpx 0;
.name {
font-size: 24.56rpx;
margin-top: 14.04rpx;
}
}
}
}
</style>

View File

@ -0,0 +1,195 @@
<template>
<view class="">
<view class="content_card">
<view class="cont_header flex_a_c_j_sb">
<view class="task_name">任务名称</view>
<view class="is_matter">任务审批</view>
</view>
<view class="cont_details">
审批内容
<view class="">审批详细描述</view>
</view>
</view>
<view class="content_card">
<!-- 头部 -->
<view class="cont_header">
<view class="flex_a_c_j_sb">
<view class="approver">当前审批人张三</view>
<view class="audit_store">审核状态<text>已通过</text> </view>
</view>
<view class="make_copy">抄送人李四</view>
</view>
<!-- 内容 -->
<view class="cont_details">
<view class="examine">审批流程</view>
<view class="examine">审批记录</view>
<block v-for="(item,i) in 3" :key="i">
<view class="record flex">
<view class="circle"></view>
<text class="text">2023-03-24 :09:40 张三 提交 了此申请操作意见提交申请</text>
</view>
</block>
</view>
</view>
</view>
</template>
<script>
export default {
data() {
return {
}
},
onLoad() {},
onShow() {},
methods: {},
onPullDownRefresh() {
uni.stopPullDownRefresh()
}
}
</script>
<style lang="scss">
.content_card {
width: 695rpx;
margin: 0 auto;
margin-top: 24.56rpx;
padding: 0 28.07rpx;
background-color: #fff;
border-radius: 4px;
}
.cont_header {
padding: 21.05rpx 0;
font-size: 31.58rpx;
min-height: 82.46rpx;
width: 100%;
border-bottom: 1px solid rgba(204, 204, 204, 0.5);
.task_name {
width: 526.32rpx;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.is_matter {
font-size: 24.56rpx;
border-radius: 4px;
// padding: 3.51rpx 17.54rpx;
color: $theme-oa-color;
// background-color: #E4EDFF;
}
//
.approver {
font-size: 28.07rpx;
}
.audit_store {
font-size: 31.58rpx;
}
.make_copy {
color: #999;
margin-top: 14.04rpx;
font-size: 24.56rpx;
}
}
.cont_details {
padding: 24.56rpx 0;
font-size: 28.07rpx;
//
.finish_time {
font-size: 24.56rpx;
color: #999;
}
text {
display: block;
margin-bottom: 7.02rpx;
}
.upload_box {
padding: 17.54rpx;
background-color: #F7F7F7;
border-radius: 4px;
.title {
font-size: 28.07rpx;
}
.text {
margin-top: 7.02rpx;
font-size: 21.05rpx;
color: #999;
}
}
.file {
padding: 17.54rpx;
border-radius: 4px;
border: 1px solid #F2F2F2;
margin-bottom: 17.54rpx;
.file_size {
margin-top: 7.02rpx;
}
.file_size,
.upload_people {
font-size: 21.05rpx;
color: #999;
}
}
//
.examine {
margin-bottom: 17.54rpx;
}
.record {
position: relative;
margin-bottom: 14.04rpx;
.circle {
width: 31.58rpx;
height: 31.58rpx;
background-color: #fff;
border: 2px solid #34A853;
border-radius: 50%;
margin: 5px;
display: flex;
flex-direction: column;
align-items: center;
&::before {
content: "";
display: block;
position: absolute;
clear: both;
width: 1px;
height: 100%;
background-color: rgba(204, 204, 204, 0.5);
margin: 31.58rpx;
}
}
.text {
flex: 1;
margin-left: 7.02rpx;
}
}
:last-child {
.circle {
&::before {
display: none;
}
}
}
}
</style>

View File

@ -0,0 +1,536 @@
<template>
<view class="leave_request">
<view class="leave_box">
<view class="leava_type flex_a_c">
<view class="title">请假类型</view>
<input type="text" v-model="leavaTypeVal" placeholder="请选择" disabled @click="leavaTypeShow = true">
</view>
<block v-for="(item,i) in timeData" :key="item.title">
<view class="cont_cell">
<view class="title">{{ item.title }}</view>
<input type="text" v-model="item.time" placeholder="请选择时间" disabled @click="selectTime(item)">
</view>
</block>
<view class="cont_cell">
<view class="title">请假工时</view>
<input type="text" v-model="manHour" disabled placeholder="请假工时">
</view>
<view class="cont_cell">
<view class="title">请假天数</view>
<input type="text" v-model="daysNum" disabled placeholder="请假天数">
</view>
<view class="cont_cell">
<view class="title">请假事由</view>
<input type="text" v-model="reason" placeholder="请输入请假事由">
</view>
<!-- 附件 -->
<block v-for="(item, i) in fileArray" :key="i">
<view class="file flex_a_c_j_sb">
<view class="l_file">
<view class="file_name">{{ item.name }}</view>
<view class="file_size">{{ item.filesize | formatBytes }}</view>
<view class="upload_people">上传人{{ item.admin_name }}</view>
</view>
<u-icon @click="delImg(i)" name="close-circle" color="#333333" size="28"></u-icon>
</view>
</block>
<view class="upload_box flex_a_c_j_sb" @click="seleckImage">
<view>
<view class="title">选择文件并上传</view>
<view class="text">
上传前请规范命名最大只能上传100M的文件<br />
超过请压缩成多个文件上传
</view>
</view>
<u-icon name="plus-circle" color="#333333" size="28"></u-icon>
</view>
</view>
<view class="flow_path">
<view class="cont_cell">
<view class="title">选择审批流程</view>
<input type="text" v-model="flowPath" placeholder="请选择" disabled @click="flowPathShow = true">
</view>
<view class="cont_cell">
<view class="title">审核人</view>
<input v-if="flowDate === false" type="text" v-model="auditor" placeholder="请选择" disabled
@click="branchShow = true">
<view v-else class="audit_process">
<view v-for="(item,i) in flowDate" :key="i" class="process_item flex">
<view class="circle"></view>
<view class="right">
<view v-if="item.flow_type==1">
{{i+1}}级审批
<view class="verifier">当前部门负责人</view>
</view>
<view v-else-if="item.flow_type==2">
{{i+1}}级审批
<view class="verifier">上级部门负责人</view>
</view>
<view v-else>
<view v-if="item.flow_type==3">
{{i+1}}级审批
<text class="tag">或签</text>
</view>
<view v-if="item.flow_type==4">
{{i+1}}级审批
<text class="tag">会签</text>
</view>
<view v-for="(info,b) in item.user_id_info" :key="b" class="verifier">
{{ info.name }}
</view>
</view>
</view>
</view>
</view>
</view>
<view class="cont_cell">
<view class="title">抄送人</view>
<input type="text" v-model="carbon" placeholder="请选择" disabled>
</view>
</view>
<view class="bot_btn">
<view class="reset" @click="reset">重置</view>
<view class="submit_btn" @click="submiteBtn">立即提交</view>
</view>
<u-picker :show="leavaTypeShow" keyName="name" :columns="columns" @cancel="leavaTypeShow = false"
@confirm="leavaType">
</u-picker>
<!-- 选择审批流程 -->
<u-action-sheet :actions="flowPathSheet" @select="flowPathSelect" title="选择审批流程" :show="flowPathShow"
@close="flowPathShow=false" :closeOnClickOverlay="true" :closeOnClickAction="true">
</u-action-sheet>
<!-- 部门选择 -->
<u-picker :show="branchShow" :defaultIndex=[0,0] ref="branchRef" :columns="branchColumns" @confirm="branchConfirm"
@change="branchHandler" :closeOnClickOverlay="true" @close="branchShow=false" keyName="name">
</u-picker>
<!-- 选择时间 -->
<block v-for="(item,i) in timeData" :key="i">
<u-datetime-picker :show="item.timeShow" v-model="item.timeVal" mode="datetime" :maxDate="1786778555000"
:minDate="timestamp" closeOnClickOverlay @confirm="timeConfirm($event,i)" @cancel="item.timeShow = false"
@close="item.timeShow = false"></u-datetime-picker>
</block>
</view>
</template>
<script>
import { getFlowAPI, getFlowUsersAPI, getDepartmentTreeAPI, getEmployeeAPI, PostApproveAddAPI } from '@/api/oaApi.js'
import { oaLeaveData } from '@/static/server/server.js'
import { oaUploads } from '../../api/upload'
import { Toast } from '../../libs/uniApi'
export default {
data() {
return {
timestamp: '', //
flowPath: '', //
flow_id: '', // id
auditor: '', //
carbon: '', //
copy_uids: '', // id
manHour: '', //
daysNum: '', //
reason: '', //
flowPathShow: false,
flowPathSheet: [],
timeData: [{
title: '开始时间:',
timeShow: false,
timeVal: '', //
time: '', //
timeDay: '', //
timeHour: '', //
},
{
title: '结束时间:',
timeShow: false,
timeVal: '', //
time: '', //
timeDay: '', //
timeHour: '', //
}
],
leavaTypeShow: false,
leavaTypeVal: '',
leavaTypeId: '',
columns: [oaLeaveData],
//
branchShow: false,
branchColumns: [],
isflowDate: true,
flowDate: [],
fileArray: []
}
},
onLoad() {},
onShow() {
this.getFlow()
//
this.timestamp = Date.parse(new Date());
},
watch: {
timeData: {
handler(newVal, oldVal) {
if (newVal[0].time.length > 0 && newVal[1].time.length > 0) {
const { leaveDays, leaveHours } = this.calculateLeaveDaysAndHours(this.timeData[0].time, this.timeData[1]
.time)
this.manHour = leaveHours + '小时'
this.daysNum = leaveDays + '天'
}
},
deep: true
}
},
methods: {
selectTime(item) {
item.timeShow = true
},
async branchHandler(e) {
const {
columnIndex,
value,
values, // values
index,
// pickerref
picker = this.$refs.branchRef
} = e
// ()
if (columnIndex === 0) {
// pickerthis
let res = await getEmployeeAPI({ did: value[0].id })
if (res.length < 1) {
res[0] = { name: '无' }
}
picker.setColumnValues(1, res)
}
},
// columnIndexvaluevalues
branchConfirm(e) {
console.log('confirm', e)
this.auditor = e.value[1].name
this.branchShow = false
},
/** 请假类型 */
leavaType(e) {
this.leavaTypeVal = e.value[0].name
this.leavaTypeId = e.value[0].id
this.leavaTypeShow = false
},
/** 选择审核人 */
async getFlowUsers(id) {
const flowUsers = await getFlowUsersAPI({ id: id })
console.log(flowUsers.data);
this.flowDate = flowUsers.data.flow_data
//
if (!flowUsers.data.flow_data) {
const tree = await getDepartmentTreeAPI()
const picker = this.$refs.branchRef
picker.setColumnValues(0, tree[0].children)
let res = await getEmployeeAPI({ did: tree[0].children[0].id })
picker.setColumnValues(1, res)
this.carbon = ''
} else {
this.carbon = flowUsers.data.copy_unames
this.copy_uids = flowUsers.data.copy_uids
}
},
flowPathSelect(value) {
this.flowPath = value.name
this.flow_id = value.id
this.getFlowUsers(value.id)
},
async getFlow() {
const flow = await getFlowAPI({ type: 1, flow_cate: 1 })
this.flowPathSheet = flow
},
timeConfirm(e, i) {
this.timeData[i].time = uni.$u.timeFormat(e.value, 'yyyy-mm-dd hh:MM:ss')
this.timeData[i].timeDay = uni.$u.timeFormat(e.value, 'yyyy-mm-dd')
this.timeData[i].timeHour = uni.$u.timeFormat(e.value, 'hh:MM')
this.timeData[i].timeShow = false
},
async submiteBtn() {
let fileIds = [];
this.fileArray.map((item, i) => {
fileIds.push(item.id)
});
let subData = {
detail_type: this.leavaTypeId,
end_time_a: this.timeData[1].timeDay,
end_time_b: this.timeData[1].timeHour,
start_time_a: this.timeData[0].timeDay,
start_time_b: this.timeData[0].timeHour,
duration: this.manHour,
content: this.reason,
flow_id: this.flow_id,
file_ids: fileIds.join(','),
copy_names: this.carbon,
copy_uids: this.copy_uids,
type: '1',
id: 0
}
try {
const res = await PostApproveAddAPI(subData)
Toast('提交成功')
} catch (e) {
Toast('提交失败')
}
},
reset() {
this.flowPath = ''
this.flowDate = []
this.leavaTypeVal = ''
this.leavaTypeId = ''
this.daysNum = ''
this.timeData[0].time = ''
this.timeData[0].time = ''
this.timeData[1].time = ''
this.timeData[1].time = ''
this.manHour = ''
this.reason = ''
this.flow_id = ''
this.carbon = ''
this.copy_uids = ''
},
seleckImage(i) {
let that = this
uni.chooseImage({
count: 1,
sizeType: ['original', 'compressed'],
sourceType: ['album', 'camera'],
success: function(res) {
that.loading = true
let objImg = {}
objImg.filesize = res.tempFiles[0].size
objImg.admin_name = '马开明'
oaUploads(res.tempFilePaths[0], 'img').then(res => {
objImg.name = res.filename
that.fileArray.push(res)
that.loading = false
Toast('上传成功')
}).catch(err => {
Toast('上传失败')
that.loading = false
console.log('上传失败', err)
})
},
fail: function(err) {
Toast('添加失败')
console.log('失败', err)
}
});
},
delImg(i) {
let that = this
uni.showModal({
title: '删除图片',
content: '确定删除图片?',
success: res => {
if (res.confirm) {
that.fileArray.splice((i, 1))
} else if (res.cancel) {
console.log('用户点击取消');
}
}
})
},
/**
* 计算两个时间戳之间相差的小时数
* */
calculateLeaveDaysAndHours(leaveStartTime, leaveEndTime, hoursPerDay = 8) {
const startDate = new Date(leaveStartTime);
const endDate = new Date(leaveEndTime);
//
const leaveDays = Math.floor((endDate.getTime() - startDate.getTime()) / (24 * 60 * 60 * 1000)) + 1;
//
const leaveHours = leaveDays * hoursPerDay;
//
return {
leaveDays,
leaveHours,
};
}
},
filters: {
// MB
formatBytes(bytes, decimals = 2) {
if (bytes === 0) return '0 MB';
const k = 1024;
const sizes = ['B', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'];
const i = Math.floor(Math.log(bytes) / Math.log(k));
return parseFloat((bytes / Math.pow(k, i)).toFixed(decimals)) + ' ' + sizes[i];
}
},
onPullDownRefresh() {
uni.stopPullDownRefresh()
}
}
</script>
<style lang="scss">
.leave_request {
position: relative;
padding-bottom: 100px;
}
.leave_box,
.flow_path {
width: 100%;
padding: 0 28.07rpx;
background: #fff;
margin-bottom: 35.09rpx;
padding-bottom: 28.07rpx;
}
.bot_btn {
position: fixed;
bottom: 0;
left: 0;
width: 100%;
display: flex;
align-items: center;
justify-content: space-between;
height: 87.72rpx;
>view {
width: 50%;
text-align: center;
line-height: 87.72rpx;
}
.reset {
background-color: #fff;
}
.submit_btn {
color: #fff;
height: 87.72rpx;
background: $theme-oa-color;
}
}
.leava_type {
height: 100rpx;
border-bottom: 1px solid #999;
.title {
font-size: 31.58rpx;
}
}
.cont_cell {
display: flex;
align-items: center;
width: 100%;
min-height: 87.72rpx;
border-bottom: 1px solid #f7f7f7;
.title {
font-size: 31.58rpx;
}
}
//
.audit_process {
.process_item {
position: relative;
height: 100%;
margin: 17.54rpx 0;
}
:last-child {
.circle {
&::before {
display: none;
}
}
}
.tag {
font-size: 21.05rpx;
color: #fff;
padding: 0 4px;
margin-left: 10.53rpx;
background-color: #3c9cff;
border-radius: 2px;
}
.verifier {
margin: 17.54rpx 0;
}
}
.circle {
width: 31.58rpx;
height: 31.58rpx;
background-color: #fff;
border: 2px solid #34A853;
border-radius: 50%;
margin: 0 5px;
display: flex;
flex-direction: column;
align-items: center;
&::before {
content: "";
display: block;
position: absolute;
clear: both;
width: 1px;
height: 100%;
background-color: rgba(204, 204, 204, 0.5);
margin: 31.58rpx;
}
}
//
.upload_box {
padding: 17.54rpx;
background-color: #F7F7F7;
border-radius: 4px;
.title {
font-size: 28.07rpx;
}
.text {
margin-top: 7.02rpx;
font-size: 21.05rpx;
color: #999;
}
}
.file_name {
width: 526.32rpx;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.file {
padding: 17.54rpx;
border-radius: 4px;
border: 1px solid #F2F2F2;
margin: 17.54rpx 0;
.file_size {
margin-top: 7.02rpx;
}
.file_size,
.upload_people {
font-size: 21.05rpx;
color: #999;
}
}
</style>

View File

@ -0,0 +1,604 @@
<template>
<!-- 新建任务 -->
<view>
<view class="task_box">
<!-- 主题 -->
<!-- 信息填写表单 -->
<view class="u-page">
<view class="u-demo-block">
<view class="u-demo-block__content">
<u--form labelPosition="left" :model="model1" ref="form1">
<u-form-item label="任务主题:" prop="userInfo.title" borderBottom ref="item">
<u--input v-model="model1.userInfo.title" border="none" placeholder="请输入"></u--input>
</u-form-item>
<u-cell-group>
<view class="cell" v-for="(item, index) in list" :key="index">
<u-cell @click="showPicker(index)" :title="item.title" isLink :value="item.value"
:label="item.value?'':'请选择'">
</u-cell>
</view>
</u-cell-group>
<!-- 指派给 -->
<u-picker :show="flag1" :columns="columns3" ref="uPicker4" @cancel="cancel" closeOnClickOverlay
@close="flag1 = false" @confirm="confirm" @change="changeHandler1" keyName="name" :defaultIndex=[0,0]>
</u-picker>
<!-- 协作人 -->
<u-picker :show="flag2" :columns="columns3" ref="uPicker5" @cancel="cancel" @close="flag2 = false"
@confirm="confirm" @change="changeHandler2" keyName="name" closeOnClickOverlay :defaultIndex=[0,0]>
</u-picker>
<!-- 验收人 -->
<u-picker :show="flag3" :columns="columns3" ref="uPicker6" @cancel="cancel" @close="flag3 = false"
@confirm="confirm" @change="changeHandler3" keyName="name" closeOnClickOverlay :defaultIndex=[0,0]>
</u-picker>
<!-- 任务性质 -->
<u-form-item label="任务性质:" prop="userInfo.isbug" borderBottom @click="show3 = true; hideKeyboard()"
ref="item3">
<u--input v-model="model1.userInfo.isbug" disabled disabledColor="#ffffff" placeholder="请选择"
border="none"></u--input>
</u-form-item>
<!-- 开始时间 -->
<u-form-item label="任务开始时间:" prop="userInfo.start_time" borderBottom
@click="starttime = true; hideKeyboard()" ref="item8">
<u--input v-model="model1.userInfo.start_time" disabled disabledColor="#ffffff" placeholder="请选择"
border="none"></u--input>
</u-form-item>
<!-- 预计结束日期 -->
<u-form-item label="预计结束日期:" prop="userInfo.end_time" borderBottom @click="endtime = true; hideKeyboard()"
ref="item4">
<u--input v-model="model1.userInfo.end_time" disabled disabledColor="#ffffff" placeholder="请选择"
border="none"></u--input>
</u-form-item>
<!-- 月份 -->
<u-form-item label="月份:" prop="userInfo.demo1" borderBottom @click="endmonth = true; hideKeyboard()"
ref="item5">
<u--input v-model="model1.userInfo.demo1" disabled disabledColor="#ffffff" placeholder="请选择"
border="none"></u--input>
</u-form-item>
<!-- 关联项目 -->
<u-form-item label="关联项目:" prop="userInfo.project" borderBottom @click="show4 = true; hideKeyboard()"
ref="item6">
<u--input v-model="model1.userInfo.project" disabled disabledColor="#ffffff" placeholder="请选择"
border="none"></u--input>
</u-form-item>
<!-- 优先级 -->
<u-form-item label="优先级:" prop="userInfo.priority_status" borderBottom
@click="show5 = true; hideKeyboard()" ref="item7">
<u--input v-model="model1.userInfo.priority_status" disabled disabledColor="#ffffff" placeholder="请选择"
border="none"></u--input>
</u-form-item>
<view class="gray"></view>
<!-- 详细描述 -->
<view class="elaborate_box">
<view class="elaborate">详细描述:</view>
<u-form-item prop="userInfo.docContent_markdown_doc" ref="item8">
<u--textarea v-model="model1.userInfo.docContent_markdown_doc" count autoHeight maxlength='200'>
</u--textarea>
</u-form-item>
</view>
</u--form>
</u-action-sheet>
<!-- 任务性质 -->
<u-action-sheet :show="show3" :actions="actions3" title="请选择任务性质" @close="show3 = false" @select="Select3">
</u-action-sheet>
<!-- 关联项目 -->
<u-action-sheet :show="show4" :actions="actions4" title="请选择关联项目" @close="show4 = false" @select="Select4">
</u-action-sheet>
<!-- 优先级 -->
<u-action-sheet :show="show5" :actions="actions5" title="请选择优先级" @close="show5 = false" @select="Select5">
</u-action-sheet>
<!-- 开始时间 -->
<u-datetime-picker :show="starttime" :value="start_time" mode="datetime" closeOnClickOverlay
@confirm="start_timeConfirm" @cancel="start_timeClose" @close="start_timeClose"></u-datetime-picker>
<!-- 结束日期 -->
<u-datetime-picker :show="endtime" :value="end_time" mode="datetime" closeOnClickOverlay
@confirm="end_timeConfirm" @cancel="end_timeClose" @close="end_timeClose"></u-datetime-picker>
<!-- 结束月份 -->
<u-datetime-picker :show="endmonth" :value="demo1" mode="date" closeOnClickOverlay
@confirm="end_monthConfirm" @cancel="end_monthClose" @close="end_monthClose"></u-datetime-picker>
</view>
</view>
</view>
<!-- 信息填写表单 end-->
<!-- 提交按钮 -->
<view class="btn_box">
<u-button type="error" class="btn reset" text="重置" @click="reset"></u-button>
<u-button type="primary" class="btn sub" text="立即提交" @click="submit"></u-button>
</view>
</view>
</view>
</template>
<script>
import {
addNewTaskApi,
getDepartmentApi,
getDepartmentPersonApi
} from '@/api/oa.js'
import { Toast } from '@/libs/uniApi'
// import { data } from '../../../uni_modules/uview-ui/libs/mixin/mixin'
export default {
data() {
return {
index: 0,
loading: false,
columnData: [
],
columns3: [],
model1: {
userInfo: {
title: '', //
director_name: '', //
assist_admin_names: '', //
isbug: '', //
start_time: '', //
end_time: '', //
demo1: '', //
project: '', //
priority_status: '', //
assist_check_names: '', //
docContent_markdown_doc: '', //
},
},
flag1: false, //
flag2: false, //
flag3: false, //
show3: false, //
show4: false, //
show5: false, //
list: [{
title: '指派给:',
value: '',
},
{
title: '协作人:',
value: ''
},
{
title: '验收人:',
value: ''
},
],
starttime: false, //
endtime: false, //
endmonth: false, //
start_time: Number(new Date()), //
end_time: Number(new Date()),
demo1: Number(new Date()),
actions3: [{
name: '部门工作',
index: '0'
}, {
name: '部门协助',
index: '1'
}, ],
actions4: [{
name: '项目1',
id: '78'
}, ],
actions5: [{
name: '一般',
id: '1',
}, {
name: '紧急',
id: '4'
}],
rules: {
},
}
},
onLoad() {
this.getDepartment()
},
onShow() {},
methods: {
groupChange(n) {
// console.log('groupChange', n);
},
navigateBack() {
uni.navigateBack()
},
Select3(e) {
this.model1.userInfo.isbug = e.name
this.model1.userInfo.is_bug = e.index //id
this.$refs.form1.validateField('userInfo.is_bug')
},
Select4(e) {
this.model1.userInfo.project = e.name
this.model1.userInfo.project_id = e.id //id
this.$refs.form1.validateField('userInfo.project')
},
Select5(e) {
this.model1.userInfo.priority_status = e.name
this.model1.userInfo.priority = e.id //id
this.$refs.form1.validateField('userInfo.priority')
},
change(e) {
// console.log(e);
},
//
start_timeClose() {
this.starttime = false
this.$refs.form1.validateField('userInfo.start_time')
},
start_timeConfirm(e) {
this.starttime = false
this.model1.userInfo.start_time = uni.$u.timeFormat(e.value, 'yyyy-mm-dd')
this.$refs.form1.validateField('userInfo.start_time')
},
//
end_timeClose() {
this.endtime = false
this.$refs.form1.validateField('userInfo.end_time')
},
end_timeConfirm(e) {
this.endtime = false
this.model1.userInfo.end_time = uni.$u.timeFormat(e.value, 'yyyy-mm-dd hh:MM:ss')
this.$refs.form1.validateField('userInfo.end_time')
},
//
end_monthClose() {
this.endmonth = false
this.$refs.form1.validateField('userInfo.demo1')
},
end_monthConfirm(e) {
this.endmonth = false
this.model1.userInfo.demo1 = uni.$u.timeFormat(e.value, 'yyyy-mm')
this.$refs.form1.validateField('userInfo.demo1')
},
//
async addNewTask(data) {
const res = await addNewTaskApi(data)
Toast('slkdff')
},
//
async getDepartment() {
const res = await getDepartmentApi()
const deArr = res[0].children
this.columns3.push(deArr)
let id = deArr[0].id
this.getDepartmentPerson(id)
},
//
async getDepartmentPerson(id) {
const data = {
did: id
}
const res = await getDepartmentPersonApi(data)
const nameArr = []
res.forEach(item => {
let obj = {}
obj.name = item.name
obj.id = item.id
nameArr.push(obj)
})
this.columnData = []
this.columnData = nameArr
// this.columnData = res
if (this.columns3[1]) {
return
} else {
this.columns3.push(nameArr)
// this.columns3.push(res)
}
},
async submit() {
//
var d1 = new Date(this.model1.userInfo.start_time)
const date1 = d1.getTime()
var d2 = new Date(this.model1.userInfo.end_time)
const date2 = d2.getTime()
if (date1 > date2) {
Toast('结束时间不低于开始时间')
this.model1.userInfo.end_time = ''
return
}
this.model1.userInfo.director_name = this.list[0].value
this.model1.userInfo.assist_admin_names = this.list[1].value
this.model1.userInfo.assist_check_names = this.list[2].value
let userInfo = this.model1.userInfo
const arr = Object.values(userInfo)
const bool = arr.every(item => item)
if (bool) {
this.model1.userInfo.director_uid = this.list[0].id + ''
this.model1.userInfo.assist_admin_ids = this.list[1].id + ''
this.model1.userInfo.assist_check_ids = this.list[2].id + ''
this.model1.userInfo.ueditorcontent = this.model1.userInfo.docContent_markdown_doc
// const { msg } = await this.addNewTask(this.model1.userInfo)
console.log(this.model1.userInfo);
const res = await addNewTaskApi(this.model1.userInfo)
if (res.code == 0) {
uni.$u.toast('验收时间不能大于本月月底18点')
return
} else {
//
uni.showToast({
title: '已提交',
});
setTimeout(function() {
uni.navigateBack({
delta: 1
});
}, 1000)
}
} else {
uni.$u.toast('请填写所有信息')
return
}
},
reset() {
this.list.forEach(item => {
item.value = ''
})
for (let i in this.model1.userInfo) {
this.model1.userInfo[i] = ''
}
},
hideKeyboard() {
uni.hideKeyboard()
},
//picker
showPicker(index) {
console.log(index);
this.index = index + 1
this[`show${index + 1}`] = true
},
//
changeHandler1(e) {
this.change(e)
const {
columnIndex,
value,
values,
index,
// pickerref
picker = this.$refs.uPicker4
} = e
let id = e.value[0].id
if (columnIndex === 0) {
this.getDepartmentPerson(id)
this.loading = true
uni.$u.sleep(500).then(() => {
picker.setColumnValues(1, this.columnData)
this.loading = false
})
}
},
changeHandler2(e) {
this.change(e)
const {
columnIndex,
value,
values,
index,
// pickerref
picker = this.$refs.uPicker5
} = e
let id = e.value[0].id
if (columnIndex === 0) {
this.getDepartmentPerson(id)
this.loading = true
uni.$u.sleep(500).then(() => {
picker.setColumnValues(1, this.columnData)
this.loading = false
})
}
},
changeHandler3(e) {
this.change(e)
const {
columnIndex,
value,
values,
index,
// pickerref
picker = this.$refs.uPicker6
} = e
let id = e.value[0].id
if (columnIndex === 0) {
this.getDepartmentPerson(id)
this.loading = true
uni.$u.sleep(500).then(() => {
picker.setColumnValues(1, this.columnData)
this.loading = false
})
}
},
change(e) {
// console.log('change', e);
},
showPicker(index) {
this.index = index + 1
this[`flag${index + 1}`] = true
},
close() {
// console.log('close');
this[`flag${this.index}`] = false
},
confirm(e) {
const num = this.index - 1
const name = e.value[1]
if (name == undefined) {
this.list[num].value = '暂无'
} else {
this.list[num].value = name.name
this.list[num].id = name.id
}
this[`flag${this.index}`] = false
},
cancel() {
// console.log('cancel');
this[`flag${this.index}`] = false
},
},
onReady() {
// setRules
this.$refs.form1.setRules(this.rules)
},
}
</script>
<style lang="scss" scoped>
/deep/.u-form {
background-color: #fff;
}
/deep/.uicon-arrow-right {
display: none;
}
/deep/.u-cell__right-icon-wrap {
display: none !important;
}
/deep/.u-form-item {
padding: 0 28rpx;
}
/deep/.u-form-item__body__left {
width: 220rpx !important;
// background-color: pink;
}
/deep/.input-placeholder,
/deep/.u-input__content,
/deep/.uni-input-wrapper {
font-size: 28rpx !important;
}
/deep/.u-textarea {
padding: 0 !important;
}
/deep/.u-form-item__body__right__message {
margin-left: 220rpx !important;
}
/deep/.u-cell__title {
display: inline-block !important;
flex: none;
}
/deep/.u-cell__body {
padding: 21rpx 0 !important;
}
/deep/.u-line:first-child {
border-bottom: none !important;
}
/deep/.u-cell__value {
color: black !important;
}
/deep/.u-cell__title-text {
display: inline-block !important;
width: 220rpx !important;
}
/deep/.u-cell__label {
font-size: 28rpx !important;
color: #CCCCCC !important;
}
/deep/.u-cell__body__content {
flex: none !important;
}
.cell {
margin: 0 auto;
width: 694rpx;
// background-color: pink;
}
.row {
margin: 0 auto;
margin-top: 21rpx;
width: 694rpx;
height: 0rpx;
border-bottom: 1rpx solid #CCCCCC;
}
.de {
font-size: 28rpx;
.miaoshu {
font-size: 28rpx;
color: #CCCCCC;
}
}
.ch {
color: rgb(192, 196, 204);
}
.gray {
// width: 750rpx;
height: 35rpx;
background-color: #F5F5F5;
}
.elaborate_box {
background-color: #fff;
padding: 35.5rpx 28rpx;
margin-bottom: 200rpx;
overflow: hidden;
.elaborate {
color: #666666;
font-size: 32rpx;
}
.elaborate_info {
width: 100%;
// height: 350rpx;
font-size: 28rpx;
}
}
.btn_box {
z-index: 9999;
position: fixed;
bottom: 0;
width: 750rpx;
height: 156rpx;
background: #FFFFFF;
display: flex;
.btn {
text-align: center;
line-height: 88rpx;
// width: 375rpx;
height: 88rpx;
}
.reset {
border: none;
background-color: #fff;
color: #999999;
}
.sub {
color: #fff;
background-color: $theme-oa-color;
}
}
</style>

View File

@ -0,0 +1,181 @@
<template>
<!-- 个人中心-修改个人信息 -->
<view class="all_box">
<!-- 头像 -->
<view class="header_box">
<u--image v-if="changeAvatar!==''" :showLoading="true" :src="changeAvatar" width="182rpx" height="182rpx"
shape="circle">
</u--image>
<u--image v-else :showLoading="true" :src="personInfo.img" width="182rpx" height="182rpx" shape="circle">
</u--image>
<text @click="seleckImage">修改头像</text>
</view>
<!-- 基本信息 -->
<view class="bases_info">
<view class="name">
<text>姓名</text>
<input type="text" value="" class="n_input" v-model="personInfo.name" placeholder="请输入姓名" />
</view>
<view class="name">
<text>昵称</text>
<input type="text" value="" class="n_input" v-model="personInfo.nickname" placeholder="请输入昵称" />
</view>
<view class="name">
<text>电话</text>
<input type="text" value="" class="n_input" v-model="personInfo.mobile" placeholder="请输入电话" />
</view>
</view>
<view class="btn" @click="savePersonInfo">保存</view>
</view>
</template>
<script>
import {
Toast
} from '@/libs/uniApi.js'
import {
getPersonInfoApi
} from '@/api/oa.js'
import {
PostUserPerSubmitAPI
} from '@/api/oaApi.js'
import {
oaUploads,
uploads
} from '@/api/upload.js'
export default {
data() {
return {
fileList5: [],
personInfo: {
thumb: ''
},
changeAvatar: ''
};
},
onShow() {
this.getPersonInfo()
},
methods: {
//
async getPersonInfo() {
const res = await getPersonInfoApi()
this.personInfo = res
this.personInfo.img = res.thumb
console.log('个人信息', this.personInfo.thumb);
},
//
async savePersonInfo() {
// //thump
let str1 = this.personInfo.thumb
let str2 = str1.slice(0, 26)
//
if (str2 == 'http://ceshi-oa.lihaink.cn') {
this.personInfo.thumb = str1.substring(26)
}
console.log('提交', this.personInfo.thumb);
try {
//
const reg_phone = /^(13[0-9]|14[01456879]|15[0-35-9]|16[2567]|17[0-8]|18[0-9]|19[0-35-9])\d{8}$/;
if (!reg_phone.test(this.personInfo.mobile)) {
throw Error()
}
//
const reg_name = /^[\u4e00-\u9fa5]{2,4}$/;
if(!reg_name.test(this.personInfo.name)){
throw Error()
}
const res = await PostUserPerSubmitAPI(this.personInfo)
Toast('修改成功')
} catch (e) {
//TODO handle the exception
Toast('修改失败,请重试')
}
},
seleckImage(i) {
let that = this
uni.chooseImage({
count: 1,
sizeType: ['original', 'compressed'],
sourceType: ['album', 'camera'],
success: function(res) {
oaUploads(res.tempFilePaths[0], 'img').then(res => {
that.personInfo.thumb = res.filepath
that.changeAvatar = res.url + res.filepath
console.log('res', res);
Toast('上传成功')
}).catch(err => {
console.log('err', err);
Toast('上传失败')
})
},
fail: function(err) {
console.log('choose失败');
Toast('添加失败')
}
});
},
}
}
</script>
<style lang="scss" scoped>
/deep/.u-upload__button {
width: 182rpx !important;
height: 182rpx !important;
// background-color: pink;
margin: 0;
}
/deep/.u-upload__wrap__preview__image {
width: 182rpx !important;
height: 182rpx !important;
}
.all_box {
height: 1623rpx;
background-color: #fff;
padding: 0 28rpx;
padding-top: 74rpx;
}
.header_box {
color: $theme-oa-color;
font-size: 28rpx;
display: flex;
flex-direction: column;
align-items: center;
}
.bases_info {
font-size: 32rpx;
.name {
margin-top: 42.11rpx;
}
.n_input {
padding-left: 20rpx;
margin-top: 17.5rpx;
width: 694.74rpx;
height: 94.74rpx;
background: #F3F4F8;
border-radius: 12px;
}
}
.btn {
margin: 0 auto;
border-radius: 100px;
width: 614.04rpx;
height: 84.21rpx;
text-align: center;
line-height: 84.21rpx;
color: #fff;
background: #3274F9;
box-shadow: 0px 9px 26px 1px #E9EFF5;
margin-top: 84.21rpx
}
</style>

View File

@ -0,0 +1,219 @@
<template>
<!-- 个人中心 2 -->
<view>
<!-- 绩效考核 -->
<view class="assessment_box">
<view class="title_box">
<text class="line"></text>
<text>绩效考核</text>
</view>
<view class="detail_box">
<view class="assessment">
<view class="num">{{salaryInfo.cs_salary}}</view>
<view class="tip">绩效考核</view>
</view>
<view class="jian">-</view>
<view class="assessment">
<view class="num">{{salaryInfo.work_deduction_money}}</view>
<view class="tip">延期任务扣除</view>
</view>
<view class="jian">*</view>
<view class="assessment">
<view class="num">{{salaryInfo.rw}}</view>
<view class="tip">任务完成率</view>
</view>
<view class="jian">=</view>
<view class="assessment last_box">
<view class="num last">{{salaryInfo.salary}}</view>
</view>
</view>
<view class="deduction_box">
<text class="deduction_info">扣除详情:</text>
<text></text>
</view>
</view>
<!-- 部门奖金 -->
<view class="assessment_box">
<view class="title_box">
<text class="line"></text>
<text>部门奖金</text>
</view>
<view class="detail_box bonus">
<view class="assessment">
<view class="num1 num">{{salaryInfo.cs_department_money}}</view>
<view class="tip">部门奖金</view>
</view>
<view class="jian">-</view>
<view class="assessment">
<view class="num1 num">{{salaryInfo.project}}</view>
<view class="tip">项目完成率</view>
</view>
<view class="jian">=</view>
<view class="assessment last_box">
<view class="num1 num last">{{salaryInfo.department_money}}</view>
</view>
</view>
<view class="deduction_box">
<text>部门计划完成率必须大于50%</text>
</view>
</view>
<!-- 公司奖金 -->
<view class="com_box">
<view class="company">
<text class="line"></text>
<text>公司奖金</text>
</view>
<view class="company_bonus">
<view class="" class="bonus">{{salaryInfo.company_money}}</view>
<view class="com_tip">公司目标低于百分之百无公司奖金</view>
</view>
</view>
</view>
</template>
<script>
import {
getSalaryDeatilsApi
} from '@/api/oa.js'
export default {
data() {
return {
salaryInfo: {}
};
},
onLoad() {},
onShow() {
this.getSalaryList()
},
methods: {
//
async getSalaryList() {
const res = await getSalaryDeatilsApi()
console.log(res);
this.salaryInfo = res
}
}
}
</script>
<style lang="scss" scoped>
.line {
display: inline-block;
width: 4rpx;
height: 33rpx;
background: #3274F9;
border-radius: 2rpx;
margin-right: 11rpx;
}
.assessment_box {
color: #333333;
font-weight: 500;
font-size: 32rpx;
width: 750rpx;
height: 335rpx;
background: #FFFFFF;
padding: 0 28rpx;
margin-bottom: 28rpx;
.title_box {
width: 100%;
height: 77rpx;
display: flex;
align-items: center;
}
.detail_box {
padding-top: 28rpx;
width: 100%;
.assessment {
display: inline-block;
text-align: center;
.num {
width: 158rpx;
height: 81rpx;
line-height: 81rpx;
background: #F3F4F8;
border-radius: 7rpx;
display: inline-block;
}
.num1 {
width: 212rpx;
}
.tip {
height: 35rpx;
color: #666666;
font-size: 25rpx;
}
}
.jian {
font-weight: 500;
font-size: 32rpx;
display: inline-block;
transform: translateY(-50rpx);
}
.last_box {
color: #3274F9;
display: inline-block;
transform: translateY(-50rpx);
}
}
.deduction_box {
margin-top: 31.54rpx;
font-weight: 500;
font-size: 28rpx;
.deduction_info {
font-size: 32rpx;
}
}
}
.com_box {
width: 750rpx;
height: 280rpx;
.company {
padding: 0 28rpx;
width: 750rpx;
height: 77rpx;
background: #FFFFFF;
display: flex;
align-items: center;
font-size: 32rpx;
}
.company_bonus {
width: 750rpx;
height: 203rpx;
background: #FFFFFF;
padding: 0 28rpx;
padding-top: 28rpx;
.bonus {
width: 694rpx;
height: 81rpx;
line-height: 81rpx;
padding-left: 23rpx;
background: #F3F4F8;
border-radius: 7rpx;
}
.com_tip {
margin-top: 28rpx;
font-size: 28rpx;
}
}
}
</style>

View File

@ -0,0 +1,178 @@
<template>
<!-- 公司公示文档 -->
<view class="all_box">
<view class="nav_box">
<view class="task_box">
<u-search shape="round" placeholder="搜索任务状态、优先级、部门等"></u-search>
<!-- 新建按钮 -->
<view class="newly_built">+新建</view>
</view>
</view>
<!-- 公司公告详情 -->
<view class="notice_box" v-for="item in noticeData" :key="item.id">
<view class="title">{{item.title}}</view>
<view class="row"></view>
<view class="info">{{item.desc}}
</view>
<view class="row"></view>
<view class="notice_bottom">
<view class="n_left">
<text class="chapter">{{item.sections}}</text>
<text>浏览{{item.is_share}}</text>
</view>
<view class="n_right">
<view class="btn btn_1">编辑</view>
<view class="btn">详情</view>
</view>
</view>
</view>
</view>
</template>
<script>
import { getDocumentListApi } from '@/api/oa.js'
export default {
data() {
return {
keyword: '',
noticeData: [{
id: 1,
title:'泸州里海农业科技有限公司内部制度流程管fafasf',
info:'本制度流程管理内容是劳动合同的补充约定,是公司、员工共同就劳资关系在不违反劳动法的基础上作出的意识自制约定;本制度经公司与在职员工全员共同会审通过,并总经理批准,自发布之日起施行。',
total:'35',
nice:'43'
},
{
id: 2,
title:'泸州里海农业科技有限公司内部制度流程管fafasf',
info:'本制度流程管理内容是劳动合同的补充约定,是公司、员工共同就劳资关系在不违反劳动法的基础上作出的意识自制约定;本制度经公司与在职员工全员共同会审通过,并总经理批准,自发布之日起施行。',
total:'35',
nice:'43'
}]
};
},
onLoad() {
},
onShow() {
this.getDocumentList()
},
methods:{
//
async getDocumentList(){
let data={share:1}
const res = await getDocumentListApi(data)
this.noticeData = res
}
}
}
</script>
<style lang="scss" scoped>
/deep/.u-search {
width: 527rpx;
}
/deep/.u-search__action--active {
display: none;
}
.all_box{
padding-bottom: 21rpx;
}
.nav_box {
width: 750rpx;
height: 98rpx;
background: #FFFFFF;
.task_box {
margin: 0 auto;
width: 750rpx;
height: 98rpx;
background: #FFFFFF;
display: flex;
align-items: center;
justify-content: space-between;
padding: 0 28rpx;
.newly_built {
width: 149rpx;
height: 63rpx;
background: #34A853;
border-radius: 35rpx;
color: #fff;
text-align: center;
line-height: 63rpx;
margin-left: 17.5rpx;
}
}
}
.notice_box {
margin: 0 auto;
margin-top: 21rpx;
width: 694rpx;
// height: 342rpx;
background: #FFFFFF;
border-radius: 7rpx;
padding: 0 24.5rpx;
padding-bottom: 25rpx;
padding-top: 24.5rpx;
.title {
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
width: 624rpx;
height: 44rpx;
font-size: 32rpx;
}
.row {
margin: 14rpx 0;
width: 646rpx;
height: 0rpx;
opacity: 1;
border-bottom: 1rpx solid #CCCCCC;
}
.info {
width: 645rpx;
color: #999999;
font-size: 25rpx;
}
.notice_bottom {
display: flex;
justify-content: space-between;
align-items: center;
.n_left {
color: #999999;
font-size: 25rpx;
.chapter {
margin-right: 60rpx;
}
}
.n_right {
.btn {
display: inline-block;
width: 158rpx;
height: 53rpx;
line-height: 53rpx;
text-align: center;
background: $theme-oa-color;
border-radius: 4rpx;
color: #fff;
}
.btn_1 {
background: #34A853;
margin-right: 14rpx;
}
}
}
}
</style>

View File

@ -0,0 +1,392 @@
<template>
<view class="task_details">
<view class="content_card">
<!-- 头部 -->
<view class="cont_header flex_a_c_j_sb">
<view class="task_name">{{ detail.title }}</view>
<view class="is_matter">{{ detail.priority_name }}</view>
</view>
<!-- 内容 -->
<view class="cont_details">
<text class="">任务人{{ detail.director_name }}</text>
<text class="">协办人{{ detail.assist_admin_names }}</text>
<text class="">发布人{{ detail.admin_name }}</text>
<text class="">工作性质{{ detail.is_bug }}</text>
<text class="">计划完成日期{{ detail.end_time }}</text>
<text class="">任务状态{{ detail.flow_name }}</text>
<text class="">任务验收截止时间{{ detail.initial_end_time }}</text>
<text class="finish_time">初始完成日期{{ detail.end_time }}</text>
<text class="finish_time">实际完成日期{{ detail.over_time }}</text>
</view>
</view>
<view class="content_card">
<!-- 头部 -->
<view class="cont_header flex_a_c">任务描述</view>
<!-- 内容 -->
<view class="cont_details">
{{ detail.content}}
</view>
</view>
<view class="content_card">
<!-- 头部 -->
<view class="cont_header flex_a_c">文件附件</view>
<!-- 内容 -->
<view class="cont_details">
<block v-for="(item, i) in fileArray" :key="i">
<view class="file flex_a_c_j_sb">
<view class="l_file">
<view class="file_name">{{ item.name }}</view>
<view class="file_size">{{ item.filesize | formatBytes }}</view>
<!-- <view class="upload_people">上传人{{ item.admin_name }}</view> -->
</view>
<u-icon @click="delImg(i)" name="close-circle" color="#333333" size="28"></u-icon>
</view>
</block>
<view class="upload_box flex_a_c_j_sb" @click="seleckImage">
<view>
<view class="title">选择文件并上传</view>
<view class="text">
上传前请规范命名最大只能上传100M的文件<br />
超过请压缩成多个文件上传
</view>
</view>
<u-icon name="plus-circle" color="#333333" size="28"></u-icon>
</view>
</view>
</view>
<view class="content_card">
<!-- 头部 -->
<view class="cont_header">
<view class="flex_a_c_j_sb">
<view class="approver">当前审批人张三</view>
<view class="audit_store">审核状态<text>已通过</text> </view>
</view>
<view class="make_copy">抄送人李四</view>
</view>
<!-- 内容 -->
<view class="cont_details">
<view class="examine">审批流程</view>
<view class="flow_path">
<block v-if="flowNodes[0].user_id_info.length>0">
<block v-for="(item, i) in flowNodes[0].user_id_info">
<view class="flex_a_c">
<u-icon name="plus-circle" color="#34A853" size="20"></u-icon>
<view class="name">{{ item.name }}</view>
<view class="status_tag">创建</view>
<u-icon name="arrow-right" color="#999999" size="16"></u-icon>
</view>
</block>
</block>
</view>
<view class="examine">审批记录</view>
<block v-if="flowNodes[0].check_list.length>0">
<block v-for="(item,i) in flowNodes[0].check_list" :key="i">
<view class="record flex">
<view class="circle"></view>
<text class="text">
<text>{{ item.check_time_str }}</text>
<text>{{ item.name }}</text>
2023-03-24 :09:40 张三 提交 了此申请操作意见
<text>{{ item.content }}</text>
</text>
</view>
</block>
</block>
</view>
</view>
<view class="bott_btn flex_a_c">
<view class="icons flex_a_c">
<u-icon name="chat" size="28"></u-icon>
<u-icon name="order" size="28"></u-icon>
</view>
<view class="turn_down">驳回记录{{detail.count_bohui > 0 ? detail.count_bohui:0 }}</view>
</view>
</view>
</template>
<script>
import { Toast } from '@/libs/uniApi.js'
import { oaUploads, uploads } from '@/api/upload'
import { getTaskDetailsAPI } from '@/api/oaApi.js'
export default {
data() {
return {
taskId: '',
attachment: [],
loading: false,
detail: {},
fileArray: [], //
flowNodes: [{
check_list: [],
user_id_info: []
}] //
}
},
onLoad(e) {
this.taskId = e.id
this.getTaskDetails()
},
onShow() {},
methods: {
async getTaskDetails() {
const { detail, file_array, flow_nodes } = await getTaskDetailsAPI({ id: this.taskId })
this.detail = detail
this.fileArray = file_array
flow_nodes.length > 0 ? this.flowNodes = flow_nodes : ''
},
seleckImage(i) {
let that = this
uni.chooseImage({
count: 1,
sizeType: ['original', 'compressed'],
sourceType: ['album', 'camera'],
success: function(res) {
that.loading = true
let objImg = {}
objImg.name = res.tempFiles[0].name
objImg.filesize = res.tempFiles[0].size
objImg.admin_name = '马开明'
oaUploads(res.tempFilePaths[0], 'img').then(res => {
that.fileArray.push(res)
that.loading = false
Toast('上传成功')
}).catch(err => {
Toast('上传失败')
that.loading = false
console.log('上传失败', err)
})
},
fail: function(err) {
Toast('添加失败')
console.log('失败', err)
}
});
},
delImg(i) {
let that = this
uni.showModal({
title: '删除图片',
content: '确定删除图片?',
success: res => {
if (res.confirm) {
that.fileArray.splice(i, 1)
} else if (res.cancel) {
console.log('用户点击取消');
}
}
})
}
},
filters: {
// MB
formatBytes(bytes, decimals = 2) {
if (bytes === 0) return '0 MB';
const k = 1024;
const sizes = ['B', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'];
const i = Math.floor(Math.log(bytes) / Math.log(k));
return parseFloat((bytes / Math.pow(k, i)).toFixed(decimals)) + ' ' + sizes[i];
}
},
onPullDownRefresh() {
uni.stopPullDownRefresh()
}
}
</script>
<style lang="scss">
.task_details {
position: relative;
padding: 26.32rpx 0 100rpx 0;
}
.content_card {
width: 695rpx;
margin: 0 auto;
margin-bottom: 24.56rpx;
padding: 0 28.07rpx;
background-color: #fff;
border-radius: 4px;
.cont_header {
padding: 21.05rpx 0;
font-size: 31.58rpx;
min-height: 82.46rpx;
width: 100%;
border-bottom: 1px solid rgba(204, 204, 204, 0.5);
.task_name {
width: 526.32rpx;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.is_matter {
font-size: 24.56rpx;
border-radius: 4px;
padding: 3.51rpx 17.54rpx;
color: $theme-oa-color;
background-color: #E4EDFF;
}
//
.approver {
font-size: 28.07rpx;
}
.audit_store {
font-size: 31.58rpx;
}
.make_copy {
color: #999;
margin-top: 14.04rpx;
font-size: 24.56rpx;
}
}
.cont_details {
padding: 24.56rpx 0;
font-size: 28.07rpx;
//
.finish_time {
font-size: 24.56rpx;
color: #999;
}
text {
display: block;
margin-bottom: 7.02rpx;
}
.upload_box {
padding: 17.54rpx;
background-color: #F7F7F7;
border-radius: 4px;
.title {
font-size: 28.07rpx;
}
.text {
margin-top: 7.02rpx;
font-size: 21.05rpx;
color: #999;
}
}
.file {
padding: 17.54rpx;
border-radius: 4px;
border: 1px solid #F2F2F2;
margin-bottom: 17.54rpx;
.file_size {
margin-top: 7.02rpx;
}
.file_name {
width: 525.7rpx;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.file_size,
.upload_people {
font-size: 21.05rpx;
color: #999;
}
}
//
.examine {
margin-bottom: 17.54rpx;
}
.flow_path {
margin-bottom: 14.04rpx;
.name {
margin: 0 14.04rpx 0 8.77rpx;
}
.status_tag {
color: #999;
margin-right: 8.77rpx;
}
}
.record {
position: relative;
margin-bottom: 14.04rpx;
.circle {
width: 31.58rpx;
height: 31.58rpx;
background-color: #fff;
border: 2px solid #34A853;
border-radius: 50%;
margin: 5px;
display: flex;
flex-direction: column;
align-items: center;
&::before {
content: "";
display: block;
position: absolute;
clear: both;
width: 1px;
height: 100%;
background-color: rgba(204, 204, 204, 0.5);
margin: 31.58rpx;
}
}
.text {
flex: 1;
margin-left: 7.02rpx;
}
}
:last-child {
.circle {
&::before {
display: none;
}
}
}
}
}
.bott_btn {
position: fixed;
left: 0;
bottom: 0;
width: 100%;
height: 87.72rpx;
display: flex;
align-items: center;
.icons {
flex: 1;
justify-content: space-around;
height: 87.72rpx;
background-color: #fff;
}
.turn_down {
width: 421.05rpx;
height: 87.72rpx;
text-align: center;
line-height: 87.72rpx;
background: #3274F9;
color: #fff;
}
}
</style>

427
nk-oa/static/css/base.css Normal file
View File

@ -0,0 +1,427 @@
@charset "UTF-8";
* {
scrollbar-color: #e5e5e5 #f7f7f9;
scrollbar-width: thin;
}
html {
margin: 0 auto;
max-width: 1200px;
}
body {
overflow-x: hidden;
}
.font-color,
.font-color-red {
color: #fc4141 !important
}
.bg-color {
background-color: #e93323
}
.icon-color {
color: #ff3c2b
}
.cart-color {
color: #ff3700 !important;
border: 1px solid #ff3700 !important
}
.padding20 {
padding: 20rpx
}
.pad20 {
padding: 0 20rpx
}
.padding30 {
padding: 30rpx
}
.pad30 {
padding: 0 30rpx
}
.pull-left {
float: left;
}
.pull-right {
float: right;
}
.clearfix:after {
content: '';
display: block;
height: 0;
clear: both
}
.clearfix {
zoom: 1
}
.acea-row {
display: -webkit-box;
display: -moz-box;
display: -webkit-flex;
display: -ms-flexbox;
display: flex;
-webkit-box-lines: multiple;
-moz-box-lines: multiple;
-o-box-lines: multiple;
-webkit-flex-wrap: wrap;
-ms-flex-wrap: wrap;
flex-wrap: wrap
}
.acea-row.row-middle {
-webkit-box-align: center;
-moz-box-align: center;
-o-box-align: center;
-ms-flex-align: center;
-webkit-align-items: center;
align-items: center
}
.acea-row.row-top {
-webkit-box-align: start;
-moz-box-align: start;
-o-box-align: start;
-ms-flex-align: start;
-webkit-align-items: flex-start;
align-items: flex-start
}
.acea-row.row-bottom {
-webkit-box-align: end;
-moz-box-align: end;
-o-box-align: end;
-ms-flex-align: end;
-webkit-align-items: flex-end;
align-items: flex-end
}
.acea-row.row-center {
-webkit-box-pack: center;
-moz-box-pack: center;
-o-box-pack: center;
-ms-flex-pack: center;
-webkit-justify-content: center;
justify-content: center
}
.acea-row.row-right {
-webkit-box-pack: end;
-moz-box-pack: end;
-o-box-pack: end;
-ms-flex-pack: end;
-webkit-justify-content: flex-end;
justify-content: flex-end
}
.acea-row.row-left {
-webkit-box-pack: start;
-moz-box-pack: start;
-o-box-pack: start;
-ms-flex-pack: start;
-webkit-justify-content: flex-start;
justify-content: flex-start
}
.acea-row.row-between {
-webkit-box-pack: justify;
-moz-box-pack: justify;
-o-box-pack: justify;
-ms-flex-pack: justify;
-webkit-justify-content: space-between;
justify-content: space-between
}
.acea-row.row-around {
justify-content: space-around;
-webkit-justify-content: space-around
}
.acea-row.row-column-around {
-webkit-flex-direction: column;
-ms-flex-direction: column;
flex-direction: column;
justify-content: space-around;
-webkit-justify-content: space-around
}
.acea-row.row-column {
-webkit-box-orient: vertical;
-moz-box-orient: vertical;
-o-box-orient: vertical;
-webkit-flex-direction: column;
-ms-flex-direction: column;
flex-direction: column
}
.acea-row.row-column-between {
-webkit-box-orient: vertical;
-moz-box-orient: vertical;
-o-box-orient: vertical;
-webkit-flex-direction: column;
-ms-flex-direction: column;
flex-direction: column;
-webkit-box-pack: justify;
-moz-box-pack: justify;
-o-box-pack: justify;
-ms-flex-pack: justify;
-webkit-justify-content: space-between;
justify-content: space-between
}
.acea-row.row-center-wrapper {
-webkit-box-align: center;
-moz-box-align: center;
-o-box-align: center;
-ms-flex-align: center;
-webkit-align-items: center;
align-items: center;
-webkit-box-pack: center;
-moz-box-pack: center;
-o-box-pack: center;
-ms-flex-pack: center;
-webkit-justify-content: center;
justify-content: center
}
.acea-row.row-between-wrapper {
-webkit-box-align: center;
-moz-box-align: center;
-o-box-align: center;
-ms-flex-align: center;
-webkit-align-items: center;
align-items: center;
-webkit-box-pack: justify;
-moz-box-pack: justify;
-o-box-pack: justify;
-ms-flex-pack: justify;
-webkit-justify-content: space-between;
justify-content: space-between
}
.start {
width: 122rpx;
height: 30rpx;
background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAHoAAADMCAYAAAC8yreMAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAA4BpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuNi1jMTQ1IDc5LjE2MzQ5OSwgMjAxOC8wOC8xMy0xNjo0MDoyMiAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wTU09Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9tbS8iIHhtbG5zOnN0UmVmPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvc1R5cGUvUmVzb3VyY2VSZWYjIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtcE1NOk9yaWdpbmFsRG9jdW1lbnRJRD0ieG1wLmRpZDpDMDg0NEE2QTVFNUQxMUU4QUI3RkNGOTgwNDYyRUZDOCIgeG1wTU06RG9jdW1lbnRJRD0ieG1wLmRpZDozODU5QzVENDMwRjcxMUU5OTQ0QzlEOTQ5RkE1MTlBRiIgeG1wTU06SW5zdGFuY2VJRD0ieG1wLmlpZDozODU5QzVEMzMwRjcxMUU5OTQ0QzlEOTQ5RkE1MTlBRiIgeG1wOkNyZWF0b3JUb29sPSJBZG9iZSBQaG90b3Nob3AgQ0MgMjAxOCAoV2luZG93cykiPiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDpkN2ZhZTM5NC0wNmE4LTkzNGYtODA0OS0zNjBjNTcxOTU2YjAiIHN0UmVmOmRvY3VtZW50SUQ9ImFkb2JlOmRvY2lkOnBob3Rvc2hvcDpmYWI1M2NhMC04MWE1LTE5NGItYmJlYi1jMzI2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');
background-repeat: no-repeat;
background-size: 122rpx auto;
}
.start.star5 {
background-position: 0 3rpx;
}
.start.star4 {
background-position: 0 -30rpx;
}
.start.star3 {
background-position: 0 -70rpx;
}
.start.star2 {
background-position: 0 -105rpx;
}
.start.star1 {
background-position: 0 -140rpx;
}
.start.star0 {
background-position: 0 -175rpx;
}
* {
box-sizing: border-box
}
page {
font-size: 28rpx;
background-color: #f5f5f5;
color: #333
}
body,
html {
height: unset
}
button {
padding: 0;
margin: 0;
line-height: normal;
background-color: #fff
}
button::after {
border: 0
}
radio .wx-radio-input {
border-radius: 50%;
width: 38rpx;
height: 38rpx
}
radio .wx-radio-input.wx-radio-input-checked {
border: 1px solid #e93323;
background-color: #e93323;
}
radio .uni-radio-input {
border-radius: 50%;
width: 38rpx;
height: 38rpx
}
radio .uni-radio-input.uni-radio-input-checked {
border: 1px solid #e93323;
background-color: #e93323;
}
.store-list uni-radio .uni-radio-input.uni-radio-input-checked,
.store-list uni-radio .uni-radio-input {
/* border-color: transparent;
background-color: transparent; */
}
.store-list uni-radio .uni-radio-input.uni-radio-input-checked:before {
/* color: #e93323!important; */
}
checkbox .wx-checkbox-input {
width: 38rpx;
height: 38rpx
}
checkbox .wx-checkbox-input.wx-checkbox-input-checked::before {
color: #fff !important;
}
checkbox .uni-checkbox-input {
/* border-radius: 50%; */
width: 38rpx;
height: 38rpx
}
checkbox .uni-checkbox-input.uni-checkbox-input-checked,
checkbox .wx-checkbox-input.wx-checkbox-input-checked {
border: 1px solid #20A162;
background-color: #20A162;
color: #fff !important;
}
checkbox .uni-checkbox-input.uni-checkbox-input-checked::before {
font-size: 35rpx
}
.line1 {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap
}
.line2 {
word-break: break-all;
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
overflow: hidden;
white-space: pre-wrap;
}
.mask {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-color: #000;
opacity: .5;
z-index: 30
}
@keyframes load {
from {
transform: rotate(0)
}
to {
transform: rotate(360deg)
}
}
@-webkit-keyframes load {
from {
transform: rotate(0)
}
to {
transform: rotate(360deg)
}
}
.loadingpic {
animation: load 3s linear 1s infinite;
--webkit-animation: load 3s linear 1s infinite
}
.loading-list {
animation: load linear 1s infinite;
-webkit-animation: load linear 1s infinite;
font-size: 40rpx;
margin-right: 22rpx
}
.loading {
width: 100%;
height: 100rpx;
line-height: 100rpx;
align-items: center;
justify-content: center;
position: relative;
text-align: center
}
.loading .line {
position: absolute;
width: 450rpx;
left: 150rpx;
top: 50rpx;
height: 1px;
border-top: 1px solid #eee
}
.loading .text {
position: relative;
display: inline-block;
padding: 0 20rpx;
background: #fff;
z-index: 2;
color: #777
}
.loadingicon .loading {
animation: load linear 1s infinite;
font-size: 45rpx;
color: #000
}
.loadingicon {
width: 100%;
height: 80rpx;
overflow: hidden
}

907
nk-oa/static/css/style.scss Normal file

File diff suppressed because one or more lines are too long

BIN
nk-oa/static/logo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.9 KiB

View File

@ -0,0 +1,380 @@
export const avatar = 'https://cdn.uviewui.com/uview/album/1.jpg'
export const defaultAvatar =
'https://thirdwx.qlogo.cn/mmopen/vi_32/POgEwh4mIHO4nibH0KlMECNjjGxQUq24ZEaGT4poC6icRiccVGKSyXwibcPq4BWmiaIGuG1icwxaQX6grC9VemZoJ8rg/132'
export const prefix = 'https://lihai001.oss-cn-chengdu.aliyuncs.com/public/kk/'
export const urls = [
'https://cdn.uviewui.com/uview/album/1.jpg',
'https://cdn.uviewui.com/uview/album/2.jpg',
'https://cdn.uviewui.com/uview/album/3.jpg',
'https://cdn.uviewui.com/uview/album/4.jpg',
'https://cdn.uviewui.com/uview/album/7.jpg',
'https://cdn.uviewui.com/uview/album/6.jpg',
'https://cdn.uviewui.com/uview/album/5.jpg'
]
export const wenluData = [
'gxsy/fangsahn@2x.png',
'gxsy/laojiao@2x.png',
'gxsy/zbgy@2x.png'
]
export const marketData = [{
title: '江阳区',
text: '醉美泸州 • 中国酒城',
src: 'gxsy/jiangyang@2x.png',
bg: 'gxsy/jiangyang@2x(1).png',
code: '510502'
},
{
title: '龙马潭区',
text: '中国酒城 • 文明泸州',
src: 'gxsy/longmatan@2x.png',
bg: 'gxsy/longmatan@2x(1).png',
code: '510504'
},
{
title: '纳溪区',
text: '山水神韵 • 醇香酒城',
src: 'gxsy/naxiqu@2x.png',
bg: 'gxsy/naxi@2x.png',
code: '510503'
},
{
title: '泸县',
text: '千年古县 • 宋韵龙城',
src: 'gxsy/luxian@2x.png',
bg: 'gxsy/luxian@2x(1).png',
code: '510521'
},
{
title: '叙永县',
text: '康养竹乡 • 画稿叙永',
src: 'gxsy/xuyongxian@2x.png',
bg: 'gxsy/xuyong@2x.png',
code: '510524'
},
{
title: '古蔺县',
text: '梦里郎酒 • 画里古蔺',
src: 'gxsy/gulinxian@2x.png',
bg: 'gxsy/jiangyang@2x(1).png',
code: '510525'
}, {
title: '合江县',
text: '千年荔城 • 甜美合江',
src: 'gxsy/hejaingxian@2x.png',
bg: 'gxsy/hejaing@2x.png',
code: '510522'
}
]
export const shichangData = [{
url: 'img4@2x.png',
title: 'rexiao@2x.png',
text: '农业生产产品'
},
{
url: 'img5@2x.png',
title: 'dangji@2x.png',
text: '村名生活用品'
}
]
export const openList = [{
title: '党建在线',
text: '党建资讯文章',
src: 'djzx@2x.png',
color: '#FF614D',
pid: 295,
navCallBack: (pid, t, id) => {
uni.navigateTo({
url: `/pages/service_hall/party_building?pid=${pid}&title=${t}&village_id=${id}`
})
}
},
{
title: '村务动态',
text: '村务信息公开',
src: 'cwdt@2x.png',
color: '#4DB896',
pid: 300,
navCallBack: (pid, t, id) => {
uni.navigateTo({
url: `/pages/service_hall/party_building?pid=${pid}&title=${t}&village_id=${id}`
})
}
},
{
title: '村镇新闻',
text: '村镇新闻资讯',
src: 'czxw@2x.png',
color: '#FFAA33',
pid: 304,
navCallBack: (pid, t, id) => {
uni.navigateTo({
url: `/pages/service_hall/list?id=${pid}&title=${t}&village_id=${id}`
})
}
},
{
title: '文明实践',
text: '文明创建实践',
src: 'wmsj@2x.png',
color: '#FF7A3D',
pid: '',
navCallBack: (pid, t, id) => {
uni.navigateTo({
url: `/pages/service_hall/opens`
})
}
}
]
export const quickLink = [{
icon: 'scfw',
src: 'scfw.png',
name: '商超服务',
url: '/pages/fast_track/production',
category_id: 25
},
{
icon: 'nfcp',
src: 'nfcp.png',
name: '农副产品',
url: '/pages/fast_track/production',
category_id: 26
}, {
icon: 'sczl',
src: 'sczl.png',
name: '生产资料',
url: '/pages/fast_track/production',
category_id: 22
}, {
icon: 'shfw',
src: 'shfw.png',
name: '生活服务',
// url: '/pages/fast_track/service_life',
url: '/pages/fast_track/production',
category_id: 23
}, {
icon: 'hbxs',
src: 'hbxs.png',
name: '红白喜事',
// url: '/pages/fast_track/red_white_thing',
url: '/pages/fast_track/production',
category_id: 21
}, {
icon: 'wyly',
src: 'wyly.png',
name: '文娱旅游',
// url: '/pages/fast_track/travel'
}, {
icon: 'fwzx',
src: 'fwzx.png',
name: '房屋装修',
// url: '/pages/fast_track/fitment'
}, {
icon: 'jypx',
src: 'jypx.png',
name: '教育资讯',
// url: '/pages/fast_track/education'
}, {
icon: 'msgy',
src: 'msgy.png',
name: '民生资讯',
// url: '/pages/fast_track/public_benefit'
}, {
icon: 'ylbj',
src: 'ylbj.png',
name: '医疗资讯'
}
]
// oaHOme快速入口数据
export const oaHomeData = [{
text: '请假申请',
icon: prefix + 'oa/qjsq@2x.png',
url: '/pages/views/leave_request'
},
{
text: '出差申请',
icon: prefix + 'oa/ccsq@2x.png'
},
{
text: '外出申请',
icon: prefix + 'oa/wcsq@2x.png'
},
{
text: '采购申请',
icon: prefix + 'oa/cgsq@2x.png'
},
{
text: '物品维修',
icon: prefix + 'oa/bxsq@2x.png'
},
{
text: '用章申请',
icon: prefix + 'oa/yzsq@2x.png'
},
{
text: '报销申请',
icon: prefix + 'oa/gengduo@2x.png'
},
{
text: '更多',
icon: prefix + 'oa/wpwx@2x.png',
url: '/pages/views/application'
}
]
/**
* oa-应用中心数据
*/
export const appDataList = [{
title: '假勤',
data: [{
name: '请假申请',
src: prefix + 'oa/qjsq@2x.png',
url: '/pages/views/leave_request'
},
{
name: '出差申请',
src: prefix + 'oa/ccsq@2x.png',
url: ''
},
{
name: '外出申请',
src: prefix + 'oa/wcsq@2x.png',
url: ''
}
]
},
{
title: '行政',
data: [{
name: '物品维修',
src: prefix + 'oa/bxsq@2x.png',
url: ''
},
{
name: '用章审批',
src: prefix + 'oa/yzsq@2x.png',
url: ''
},
{
name: '领用审批',
src: prefix + 'oa/lysp@2x.png',
url: ''
}
]
},
{
title: '财务',
data: [{
name: '借款申请',
src: prefix + 'oa/jksq@2x.png',
url: ''
},
{
name: '付款申请',
src: prefix + 'oa/fksq@2x.png',
url: ''
},
{
name: '报销申请',
src: prefix + 'oa/gengduo@2x.png',
url: ''
},
{
name: '采购申请',
src: prefix + 'oa/cgsq@2x.png',
url: ''
},
{
name: '奖励申请',
src: prefix + 'oa/jlsq@2x.png',
url: ''
},
{
name: '活动经费',
src: prefix + 'oa/hdjf@2x.png',
url: ''
}
]
},
{
title: '人事',
data: [{
name: '招聘需求',
src: prefix + 'oa/zpxq@2x.png',
url: ''
}]
},
{
title: '其他',
data: [{
name: '通用审批',
src: prefix + 'oa/tysp@2x.png',
url: '/pages/views/com_approve'
}]
}
]
/**
* oa-个人中心
*/
export const myOaData = [{
name: '工资详情',
icon: 'custom-icongongzi',
url: '/pages/views/personal_center_two'
},
{
name: '公示文档',
icon: 'custom-iconwendang',
url: '/pages/views/public_document'
},
{
name: '绑定公众号',
icon: 'custom-iconweixin'
},
{
name: '意见反馈',
icon: 'custom-iconyijian'
}
]
/*
oa-请假类型
*/
export const oaLeaveData = [{
name: '事假',
id: 1
},
{
name: '年假',
id: 2
},
{
name: '调休假',
id: 3
},
{
name: '病假',
id: 4
},
{
name: '婚假',
id: 5
},
{
name: '丧假',
id: 6
},
{
name: '产假',
id: 7
},
{
name: '陪产假',
id: 8
},
{
name: '其他',
id: 9
}
]

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

11
nk-oa/store/getters.js Normal file
View File

@ -0,0 +1,11 @@
export default {
token: state => state.app.token,
isLogin: state => !!state.app.token,
userInfo: state => state.app.userInfo || {},
};
// export default {
// token: state => 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJrYWlmYS5jcm1lYi5uZXQiLCJhdWQiOiJrYWlmYS5jcm1lYi5uZXQiLCJpYXQiOjE1NzcwODM1MzQsIm5iZiI6MTU3NzA4MzUzNCwiZXhwIjoxNTc3MDk0MzM0LCJqdGkiOnsiaWQiOjExMCwidHlwZSI6InVzZXIifX0.U-i1pbdRjyXI1gr79Uq2XBPZ89T8f5Ai9jwrR8woTwE',
// isLogin: state => true,
// backgroundColor: state => state.app.backgroundColor,
// userInfo: state => state.app.userInfo || {}
// };

20
nk-oa/store/index.js Normal file
View File

@ -0,0 +1,20 @@
// +----------------------------------------------------------------------
// | CRMEB [ CRMEB赋能开发者助力企业发展 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2016~2021 https://www.crmeb.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed CRMEB并不是自由软件未经许可不能去掉CRMEB相关版权
// +----------------------------------------------------------------------
// | Author: CRMEB Team <admin@crmeb.com>
// +----------------------------------------------------------------------
import Vue from "vue";
import Vuex from "vuex";
import modules from "./modules";
import getters from "./getters";
Vue.use(Vuex);
export default new Vuex.Store({
modules,
getters,
});

View File

@ -0,0 +1,70 @@
import { commonAuth } from '@/api/pubic.js'
import { loginMobile } from '@/api/user.js'
import Routine from '@/libs/routine.js'
import Cache from '@/utils/cache';
const state = {
userInfo: Cache.get('USER_INFO') || null,
token: Cache.get("TOKEN") || null
};
const mutations = {
setUserInfo(state, data) {
state.userInfo = data
uni.setStorageSync("USER_INFO", data)
},
LOGOUT(state) {
Cache.clear('USER_INFO')
Cache.clear('TOKEN')
},
UPDATE_USERINFO(state, data) {
let time = res.data.result.expires_time - Cache.time();
state.userInfo = data.result.user
state.token = data.result.token
Cache.set("USER_INFO", data.result.user, time)
Cache.set("TOKEN", data.result.token, time)
}
};
const actions = {
MobileLogin({ state, commit }, force) {
let data = {
auth_token: uni.getStorageSync('auth_token'),
phone: force.account,
sms_code: force.captcha,
spread: that.$Cache.get("spread"),
// #ifdef APP-PLUS
user_type: 'app',
// #endif
// #ifdef H5
user_type: 'h5',
// #endif
}
loginMobile(data).then(res => {
console.log('手机号登录', res);
})
},
async getWxLogin({ state, commit }, force) {
let newCode = null
Routine.getCode().then(code => {
newCode = code;
})
Routine.getUserProfile().then(res => {
let userInfo = res.userInfo;
userInfo.code = newCode;
commonAuth({
auth: {
type: 'routine',
auth: userInfo
}
}).then(res => {
commit("UPDATE_USERINFO", res.data);
})
})
}
};
export default {
state,
mutations,
actions
};

View File

@ -0,0 +1,13 @@
// +----------------------------------------------------------------------
// | CRMEB [ CRMEB赋能开发者助力企业发展 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2016~2021 https://www.crmeb.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed CRMEB并不是自由软件未经许可不能去掉CRMEB相关版权
// +----------------------------------------------------------------------
// | Author: CRMEB Team <admin@crmeb.com>
// +----------------------------------------------------------------------
import app from "./app";
export default {
app
};

78
nk-oa/uni.scss Normal file
View File

@ -0,0 +1,78 @@
/**
* 这里是uni-app内置的常用样式变量
*
* uni-app 官方扩展插件及插件市场https://ext.dcloud.net.cn上很多三方插件均使用了这些样式变量
* 如果你是插件开发者建议你使用scss预处理并在插件代码中直接使用这些变量无需 import 这个文件方便用户通过搭积木的方式开发整体风格一致的App
*
*/
/**
* 如果你是App开发者插件使用者你可以通过修改这些变量来定制自己的插件主题实现自定义主题功能
*
* 如果你的项目同样使用了scss预处理你也可以直接在你的 scss 代码中使用如下变量同时无需 import 这个文件
*/
/* 颜色变量 */
@import '@/uni_modules/uview-ui/theme.scss';
$theme-oa-color: #3175f9;
/* 行为相关颜色 */
$uni-color-primary: #007aff;
$uni-color-success: #4cd964;
$uni-color-warning: #f0ad4e;
$uni-color-error: #dd524d;
/* 文字基本颜色 */
$uni-text-color:#333;//基本色
$uni-text-color-inverse:#fff;//反色
$uni-text-color-grey:#999;//辅助灰色如加载更多的提示信息
$uni-text-color-placeholder: #808080;
$uni-text-color-disable:#c0c0c0;
/* 背景颜色 */
$uni-bg-color:#ffffff;
$uni-bg-color-grey:#f8f8f8;
$uni-bg-color-hover:#f1f1f1;//点击状态颜色
$uni-bg-color-mask:rgba(0, 0, 0, 0.4);//遮罩颜色
/* 边框颜色 */
$uni-border-color:#c8c7cc;
/* 尺寸变量 */
/* 文字尺寸 */
$uni-font-size-sm:12px;
$uni-font-size-base:14px;
$uni-font-size-lg:16;
/* 图片尺寸 */
$uni-img-size-sm:20px;
$uni-img-size-base:26px;
$uni-img-size-lg:40px;
/* Border Radius */
$uni-border-radius-sm: 2px;
$uni-border-radius-base: 3px;
$uni-border-radius-lg: 6px;
$uni-border-radius-circle: 50%;
/* 水平间距 */
$uni-spacing-row-sm: 5px;
$uni-spacing-row-base: 10px;
$uni-spacing-row-lg: 15px;
/* 垂直间距 */
$uni-spacing-col-sm: 4px;
$uni-spacing-col-base: 8px;
$uni-spacing-col-lg: 12px;
/* 透明度 */
$uni-opacity-disabled: 0.3; // 组件禁用态的透明度
/* 文章场景相关 */
$uni-color-title: #2C405A; // 文章标题颜色
$uni-font-size-title:20px;
$uni-color-subtitle: #555555; // 二级标题颜色
$uni-font-size-subtitle:26px;
$uni-color-paragraph: #3F536E; // 文章段落颜色
$uni-font-size-paragraph:15px;

View File

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2023 www.uviewui.com
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@ -0,0 +1,66 @@
<p align="center">
<img alt="logo" src="https://uviewui.com/common/logo.png" width="120" height="120" style="margin-bottom: 10px;">
</p>
<h3 align="center" style="margin: 30px 0 30px;font-weight: bold;font-size:40px;">uView 2.0</h3>
<h3 align="center">多平台快速开发的UI框架</h3>
[![stars](https://img.shields.io/github/stars/umicro/uView2.0?style=flat-square&logo=GitHub)](https://github.com/umicro/uView2.0)
[![forks](https://img.shields.io/github/forks/umicro/uView2.0?style=flat-square&logo=GitHub)](https://github.com/umicro/uView2.0)
[![issues](https://img.shields.io/github/issues/umicro/uView2.0?style=flat-square&logo=GitHub)](https://github.com/umicro/uView2.0/issues)
[![Website](https://img.shields.io/badge/uView-up-blue?style=flat-square)](https://uviewui.com)
[![release](https://img.shields.io/github/v/release/umicro/uView2.0?style=flat-square)](https://gitee.com/umicro/uView2.0/releases)
[![license](https://img.shields.io/github/license/umicro/uView2.0?style=flat-square)](https://en.wikipedia.org/wiki/MIT_License)
## 说明
uView UI是[uni-app](https://uniapp.dcloud.io/)全面兼容nvue的uni-app生态框架全面的组件和便捷的工具会让您信手拈来如鱼得水
## [官方文档https://uviewui.com](https://uviewui.com)
## 预览
您可以通过**微信**扫码,查看最佳的演示效果。
<br>
<br>
<img src="https://uviewui.com/common/weixin_mini_qrcode.png" width="220" height="220" >
## 链接
- [官方文档](https://www.uviewui.com/)
- [更新日志](https://www.uviewui.com/components/changelog.html)
- [升级指南](https://www.uviewui.com/components/changeGuide.html)
- [关于我们](https://www.uviewui.com/cooperation/about.html)
## 交流反馈
欢迎加入我们的QQ群交流反馈[点此跳转](https://www.uviewui.com/components/addQQGroup.html)
## 关于PR
> 我们非常乐意接受各位的优质PR但在此之前我希望您了解uView2.0是一个需要兼容多个平台的小程序、h5、ios app、android app包括nvue页面、vue页面。
> 所以希望在您修复bug并提交之前尽可能的去这些平台测试一下兼容性。最好能携带测试截图以方便审核。非常感谢
## 安装
#### **uni-app插件市场链接** —— [https://ext.dcloud.net.cn/plugin?id=1593](https://ext.dcloud.net.cn/plugin?id=1593)
请通过[官网安装文档](https://www.uviewui.com/components/install.html)了解更详细的内容
## 快速上手
请通过[快速上手](https://uviewui.com/components/quickstart.html)了解更详细的内容
## 使用方法
配置easycom规则后自动按需引入无需`import`组件,直接引用即可。
```html
<template>
<u-button text="按钮"></u-button>
</template>
```
## 版权信息
uView遵循[MIT](https://en.wikipedia.org/wiki/MIT_License)开源协议意味着您无需支付任何费用也无需授权即可将uView应用到您的产品中。

View File

@ -0,0 +1,362 @@
## 2.0.362023-03-27
# uView2.0重磅发布,利剑出鞘,一统江湖
1. 重构`deepClone` & `deepMerge`方法
2. 其他优化
## 2.0.342022-09-24
# uView2.0重磅发布,利剑出鞘,一统江湖
1. `u-input``u-textarea`增加`ignoreCompositionEvent`属性
2. 修复`route`方法调用可能报错的问题
3. 修复`u-no-network`组件`z-index`无效的问题
4. 修复`textarea`组件在h5上confirmType=""报错的问题
5. `u-rate`适配`nvue`
6. 优化验证手机号码的正则表达式(根据工信部发布的《电信网编号计划2017年版》进行修改。)
7. `form-item`添加`labelPosition`属性
8. `u-calendar`修复`maxDate`设置为当前日期并且当前时间大于0800时无法显示日期列表的问题 (#724)
9. `u-radio`增加一个默认插槽用于自定义修改label内容 (#680)
10. 修复`timeFormat`函数在safari重的兼容性问题 (#664)
## 2.0.332022-06-17
# uView2.0重磅发布,利剑出鞘,一统江湖
1. 修复`loadmore`组件`lineColor`类型错误问题
2. 修复`u-parse`组件`imgtap``linktap`不生效问题
## 2.0.322022-06-16
# uView2.0重磅发布,利剑出鞘,一统江湖
1. `u-loadmore`新增自定义颜色、虚/实线
2. 修复`u-swiper-action`组件部分平台不能上下滑动的问题
3. 修复`u-list`回弹问题
4. 修复`notice-bar`组件动画在低端安卓机可能会抖动的问题
5. `u-loading-page`添加控制图标大小的属性`iconSize`
6. 修复`u-tooltip`组件`color`参数不生效的问题
7. 修复`u--input`组件使用`blur`事件输出为`undefined`的bug
8. `u-code-input`组件新增键盘弹起时,是否自动上推页面参数`adjustPosition`
9. 修复`image`组件`load`事件无回调对象问题
10. 修复`button`组件`loadingSize`设置无效问题
10. 其他修复
## 2.0.312022-04-19
# uView2.0重磅发布,利剑出鞘,一统江湖
1. 修复`upload``vue`页面上传成功后没有成功标志的问题
2. 解决演示项目中微信小程序模拟上传图片一直出于上传中问题
3. 修复`u-code-input`组件在`nvue`页面编译到`app`平台上光标异常问题(`app`去除此功能)
4. 修复`actionSheet`组件标题关闭按钮点击事件名称错误的问题
5. 其他修复
## 2.0.302022-04-04
# uView2.0重磅发布,利剑出鞘,一统江湖
1. `u-rate`增加`readonly`属性
2. `tabs`滑块支持设置背景图片
3. 修复`u-subsection` `mode``subsection`时,滑块样式不正确的问题
4. `u-code-input`添加光标效果动画
5. 修复`popup``open`事件不触发
6. 修复`u-flex-column`无效的问题
7. 修复`u-datetime-picker`索引在特定场合异常问题
8. 修复`u-datetime-picker`最小时间字符串模板错误问题
9. `u-swiper`添加`m3u8`验证
10. `u-swiper`修改判断image和video逻辑
11. 修复`swiper`无法使用本地图片问题,增加`type`参数
12. 修复`u-row-notice`格式错误问题
13. 修复`u-switch`组件当`unit``rpx`时,`nodeStyle`消失的问题
14. 修复`datetime-picker`组件`showToolbar``visibleItemCount`属性无效的问题
15. 修复`upload`组件条件编译位置判断错误,导致`previewImage`属性设置为`false`时,整个组件都会被隐藏的问题
16. 修复`u-checkbox-group`设置`shape`属性无效的问题
17. 修复`u-upload``capture`传入字符串的时候不生效的问题
18. 修复`u-action-sheet`组件,关闭事件逻辑错误的问题
19. 修复`u-list`触顶事件的触发错误的问题
20. 修复`u-text`只有手机号可拨打的问题
21. 修复`u-textarea`不能换行的问题
22. 其他修复
## 2.0.292022-03-13
# uView2.0重磅发布,利剑出鞘,一统江湖
1. 修复`u--text`组件设置`decoration`属性未生效的问题
2. 修复`u-datetime-picker`使用`formatter`后返回值不正确
3. 修复`u-datetime-picker` `intercept` 可能为undefined
4. 修复已设置单位 uni..config.unit = 'rpx'时,线型指示器 `transform` 的位置翻倍,导致指示器超出宽度
5. 修复mixin中bem方法生成的类名在支付宝和字节小程序中失效
6. 修复默认值传值为空的时候,打开`u-datetime-picker`报错不能选中第一列时间的bug
7. 修复`u-datetime-picker`使用`formatter`后返回值不正确
8. 修复`u-image`组件`loading`无效果的问题
9. 修复`config.unit`属性设为`rpx`时,导航栏占用高度不足导致塌陷的问题
10. 修复`u-datetime-picker`组件`itemHeight`无效问题
11. 其他修复
## 2.0.282022-02-22
# uView2.0重磅发布,利剑出鞘,一统江湖
1. search组件新增searchIconSize属性
2. 兼容Safari/Webkit中传入时间格式如2022-02-17 12:00:56
3. 修复text value.js 判断日期出format错误问题
4. priceFormat格式化金额出现精度错误
5. priceFormat在部分情况下出现精度损失问题
6. 优化表单rules提示
7. 修复avatar组件src为空时展示状态不对
8. 其他修复
## 2.0.272022-01-28
# uView2.0重磅发布,利剑出鞘,一统江湖
1.样式修复
## 2.0.262022-01-28
# uView2.0重磅发布,利剑出鞘,一统江湖
1.样式修复
## 2.0.252022-01-27
# uView2.0重磅发布,利剑出鞘,一统江湖
1. 修复text组件mode=price时可能会导致精度错误的问题
2. 添加$u.setConfig()方法可设置uView内置的config, props, zIndex, color属性详见[修改uView内置配置方案](https://uviewui.com/components/setting.html#%E9%BB%98%E8%AE%A4%E5%8D%95%E4%BD%8D%E9%85%8D%E7%BD%AE)
3. 优化form组件在errorType=toast时如果输入错误页面会有抖动的问题
4. 修复$u.addUnit()对配置默认单位可能无效的问题
## 2.0.242022-01-25
# uView2.0重磅发布,利剑出鞘,一统江湖
1. 修复swiper在current指定非0时缩放有误
2. 修复u-icon添加stop属性的时候报错
3. 优化遗留的通过正则判断rpx单位的问题
4. 优化Layout布局 vue使用gutter时会超出固定区域
5. 优化search组件高度单位问题rpx -> px
6. 修复u-image slot 加载和错误的图片失去了高度
7. 修复u-index-list中footer插槽与header插槽存在性判断错误
8. 修复部分机型下u-popup关闭时会闪烁
9. 修复u-image在nvue-app下失去宽高
10. 修复u-popup运行报错
11. 修复u-tooltip报错
12. 修复box-sizing在app下的警告
13. 修复u-navbar在小程序中报运行时错误
14. 其他修复
## 2.0.232022-01-24
# uView2.0重磅发布,利剑出鞘,一统江湖
1. 修复image组件在hx3.3.9的nvue下可能会显示异常的问题
2. 修复col组件gutter参数带rpx单位处理不正确的问题
3. 修复text组件单行时无法显示省略号的问题
4. navbar添加titleStyle参数
5. 升级到hx3.3.9可消除nvue下控制台样式警告的问题
## 2.0.222022-01-19
# uView2.0重磅发布,利剑出鞘,一统江湖
1. $u.page()方法优化,避免在特殊场景可能报错的问题
2. picker组件添加immediateChange参数
3. 新增$u.pages()方法
## 2.0.212022-01-19
# uView2.0重磅发布,利剑出鞘,一统江湖
1. 优化form组件在用户设置rules的时候提示用户model必传
2. 优化遗留的通过正则判断rpx单位的问题
3. 修复微信小程序环境中tabbar组件开启safeAreaInsetBottom属性后placeholder高度填充不正确
4. 修复swiper在current指定非0时缩放有误
5. 修复u-icon添加stop属性的时候报错
6. 修复upload组件在accept=all的时候没有作用
7. 修复在text组件mode为phone时call属性无效的问题
8. 处理u-form clearValidate方法
9. 其他修复
## 2.0.202022-01-14
# uView2.0重磅发布,利剑出鞘,一统江湖
1. 修复calendar默认会选择一个日期如果直接点确定的话无法取到值的问题
2. 修复Slider缺少disabled props 还有注释
3. 修复u-notice-bar点击事件无法拿到index索引值的问题
4. 修复u-collapse-item在vue文件下app端自定义插槽不生效的问题
5. 优化头像为空时显示默认头像
6. 修复图片地址赋值后判断加载状态为完成问题
7. 修复日历滚动到默认日期月份区域
8. search组件暴露点击左边icon事件
9. 修复u-form clearValidate方法不生效
10. upload h5端增加返回文件参数文件的name参数
11. 处理upload选择文件后url为blob类型无法预览的问题
12. u-code-input 修复输入框没有往左移出一半屏幕
13. 修复Upload上传 disabled为true时控制台报hoverClass类型错误
14. 临时处理ios app下grid点击坍塌问题
15. 其他修复
## 2.0.192021-12-29
# uView2.0重磅发布,利剑出鞘,一统江湖
1. 优化微信小程序包体积可在微信中预览请升级HbuilderX3.3.4,同时在“运行->运行到小程序模拟器”中勾选“运行时是否压缩代码”
2. 优化微信小程序setData性能处理某些方法如$u.route()无法在模板中使用的问题
3. navbar添加autoBack参数
4. 允许avatar组件的事件冒泡
5. 修复cell组件报错问题
6. 其他修复
## 2.0.182021-12-28
# uView2.0重磅发布,利剑出鞘,一统江湖
1. 修复app端编译报错问题
2. 重新处理微信小程序端setData过大的性能问题
3. 修复边框问题
4. 修复最大最小月份不大于0则没有数据出现的问题
5. 修复SwipeAction微信小程序端无法上下滑动问题
6. 修复input的placeholder在小程序端默认显示为true问题
7. 修复divider组件click事件无效问题
8. 修复u-code-input maxlength 属性值为 String 类型时显示异常
9. 修复当 grid只有 1到2时 在小程序端algin设置无效的问题
10. 处理form-item的label为top时取消错误提示的左边距
11. 其他修复
## 2.0.172021-12-26
## uView正在参与开源中国的“年度最佳项目”评选之前投过票的现在也可以投票恳请同学们投一票[点此帮助uView](https://www.oschina.net/project/top_cn_2021/?id=583)
# uView2.0重磅发布,利剑出鞘,一统江湖
1. 解决HBuilderX3.3.3.20211225版本导致的样式问题
2. calendar日历添加monthNum参数
3. navbar添加center slot
## 2.0.162021-12-25
## uView正在参与开源中国的“年度最佳项目”评选之前投过票的现在也可以投票恳请同学们投一票[点此帮助uView](https://www.oschina.net/project/top_cn_2021/?id=583)
# uView2.0重磅发布,利剑出鞘,一统江湖
1. 解决微信小程序setData性能问题
2. 修复count-down组件change事件不触发问题
## 2.0.152021-12-21
## uView正在参与开源中国的“年度最佳项目”评选之前投过票的现在也可以投票恳请同学们投一票[点此帮助uView](https://www.oschina.net/project/top_cn_2021/?id=583)
# uView2.0重磅发布,利剑出鞘,一统江湖
1. 修复Cell单元格titleWidth无效
2. 修复cheakbox组件ischecked不更新
3. 修复keyboard是否显示"."按键默认值问题
4. 修复number-keyboard是否显示键盘的"."符号问题
5. 修复Input输入框 readonly无效
6. 修复u-avatar 导致打包app、H5时候报错问题
7. 修复Upload上传deletable无效
8. 修复upload当设置maxSize时无效的问题
9. 修复tabs lineWidth传入带单位的字符串的时候偏移量计算错误问题
10. 修复rate组件在有padding的view内显示的星星位置和可触摸区域不匹配无法正常选中星星
## 2.0.132021-12-14
## [点击加群交流反馈364463526](https://jq.qq.com/?_chanwv=1027&k=mCxS3TGY)
# uView2.0重磅发布,利剑出鞘,一统江湖
1. 修复配置默认单位为rpx可能会导致自定义导航栏高度异常的问题
## 2.0.122021-12-14
## [点击加群交流反馈364463526](https://jq.qq.com/?_chanwv=1027&k=mCxS3TGY)
# uView2.0重磅发布,利剑出鞘,一统江湖
1. 修复tabs组件在vue环境下划线消失的问题
2. 修复upload组件在安卓小程序无法选择视频的问题
3. 添加uni.$u.config.unit配置用于配置参数默认单位详见[默认单位配置](https://www.uviewui.com/components/setting.html#%E9%BB%98%E8%AE%A4%E5%8D%95%E4%BD%8D%E9%85%8D%E7%BD%AE)
4. 修复textarea组件在没绑定v-model时字符统计不生效问题
5. 修复nvue下控制是否出现滚动条失效问题
## 2.0.112021-12-13
## [点击加群交流反馈364463526](https://jq.qq.com/?_chanwv=1027&k=mCxS3TGY)
# uView2.0重磅发布,利剑出鞘,一统江湖
1. text组件align参数无效的问题
2. subsection组件添加keyName参数
3. upload组件无法判断[Object file]类型的问题
4. 处理notify层级过低问题
5. codeInput组件添加disabledDot参数
6. 处理actionSheet组件round参数无效的问题
7. calendar组件添加round参数用于控制圆角值
8. 处理swipeAction组件在vue环境下默认被打开的问题
9. button组件的throttleTime节流参数无效的问题
10. 解决u-notify手动关闭方法close()无效的问题
11. input组件readonly不生效问题
12. tag组件type参数为info不生效问题
## 2.0.102021-12-08
## [点击加群交流反馈364463526](https://jq.qq.com/?_chanwv=1027&k=mCxS3TGY)
# uView2.0重磅发布,利剑出鞘,一统江湖
1. 修复button sendMessagePath属性不生效
2. 修复DatetimePicker选择器title无效
3. 修复u-toast设置loading=true不生效
4. 修复u-text金额模式传0报错
5. 修复u-toast组件的icon属性配置不生效
6. button的icon在特殊场景下的颜色优化
7. IndexList优化增加#
## 2.0.92021-12-01
## [点击加群交流反馈232041042](https://jq.qq.com/?_wv=1027&k=KnbeceDU)
# uView2.0重磅发布,利剑出鞘,一统江湖
1. 优化swiper的height支持100%值(仅vue有效)修复嵌入视频时click事件无法触发的问题
2. 优化tabs组件对list值为空的判断或者动态变化list时重新计算相关尺寸的问题
3. 优化datetime-picker组件逻辑让其后续打开的默认值为上一次的选中值需要通过v-model绑定值才有效
4. 修复upload内嵌在其他组件中选择图片可能不会换行的问题
## 2.0.82021-12-01
## [点击加群交流反馈232041042](https://jq.qq.com/?_wv=1027&k=KnbeceDU)
# uView2.0重磅发布,利剑出鞘,一统江湖
1. 修复toast的position参数无效问题
2. 处理input在ios nvue上无法获得焦点的问题
3. avatar-group组件添加extraValue参数让剩余展示数量可手动控制
4. tabs组件添加keyName参数用于配置从对象中读取的键名
5. 处理text组件名字脱敏默认配置无效的问题
6. 处理picker组件item文本太长换行问题
## 2.0.72021-11-30
## [点击加群交流反馈232041042](https://jq.qq.com/?_wv=1027&k=KnbeceDU)
# uView2.0重磅发布,利剑出鞘,一统江湖
1. 修复radio和checkbox动态改变v-model无效的问题。
2. 优化form规则validator在微信小程序用法
3. 修复backtop组件mode参数在微信小程序无效的问题
4. 处理Album的previewFullImage属性无效的问题
5. 处理u-datetime-picker组件mode='time'在选择改变时间时,控制台报错的问题
## 2.0.62021-11-27
## [点击加群交流反馈232041042](https://jq.qq.com/?_wv=1027&k=KnbeceDU)
# uView2.0重磅发布,利剑出鞘,一统江湖
1. 处理tag组件在vue下边框无效的问题。
2. 处理popup组件圆角参数可能无效的问题。
3. 处理tabs组件lineColor参数可能无效的问题。
4. propgress组件在值很小时显示异常的问题。
## 2.0.52021-11-25
## [点击加群交流反馈232041042](https://jq.qq.com/?_wv=1027&k=KnbeceDU)
# uView2.0重磅发布,利剑出鞘,一统江湖
1. calendar在vue下显示异常问题。
2. form组件labelPosition和errorType参数无效的问题
3. input组件inputAlign无效的问题
4. 其他一些修复
## 2.0.42021-11-23
## [点击加群交流反馈232041042](https://jq.qq.com/?_wv=1027&k=KnbeceDU)
# uView2.0重磅发布,利剑出鞘,一统江湖
0. input组件缺失@confirm事件以及subfix和prefix无效问题
1. component.scss文件样式在vue下干扰全局布局问题
2. 修复subsection在vue环境下表现异常的问题
3. tag组件的bgColor等参数无效的问题
4. upload组件不换行的问题
5. 其他的一些修复处理
## 2.0.32021-11-16
## [点击加群交流反馈1129077272](https://jq.qq.com/?_wv=1027&k=KnbeceDU)
# uView2.0重磅发布,利剑出鞘,一统江湖
1. uView2.0已实现全面兼容nvue
2. uView2.0对1.x进行了架构重构细节和性能都有极大提升
3. 目前uView2.0为公测阶段,相关细节可能会有变动
4. 我们写了一份与1.x的对比指南详见[对比1.x](https://www.uviewui.com/components/diff1.x.html)
5. 处理modal的confirm回调事件拼写错误问题
6. 处理input组件@input事件参数错误问题
7. 其他一些修复
## 2.0.22021-11-16
## [点击加群交流反馈1129077272](https://jq.qq.com/?_wv=1027&k=KnbeceDU)
# uView2.0重磅发布,利剑出鞘,一统江湖
1. uView2.0已实现全面兼容nvue
2. uView2.0对1.x进行了架构重构细节和性能都有极大提升
3. 目前uView2.0为公测阶段,相关细节可能会有变动
4. 我们写了一份与1.x的对比指南详见[对比1.x](https://www.uviewui.com/components/diff1.x.html)
5. 修复input组件formatter参数缺失问题
6. 优化loading-icon组件的scss写法问题防止不兼容新版本scss
## 2.0.0(2020-11-15)
## [点击加群交流反馈1129077272](https://jq.qq.com/?_wv=1027&k=KnbeceDU)
# uView2.0重磅发布,利剑出鞘,一统江湖
1. uView2.0已实现全面兼容nvue
2. uView2.0对1.x进行了架构重构细节和性能都有极大提升
3. 目前uView2.0为公测阶段,相关细节可能会有变动
4. 我们写了一份与1.x的对比指南详见[对比1.x](https://www.uviewui.com/components/diff1.x.html)
5. 修复input组件formatter参数缺失问题

View File

@ -0,0 +1,78 @@
<template>
<uvForm
ref="uForm"
:model="model"
:rules="rules"
:errorType="errorType"
:borderBottom="borderBottom"
:labelPosition="labelPosition"
:labelWidth="labelWidth"
:labelAlign="labelAlign"
:labelStyle="labelStyle"
:customStyle="customStyle"
>
<slot />
</uvForm>
</template>
<script>
/**
* 此组件存在的理由是在nvue下u-form被uni-app官方占用了u-form在nvue中相当于form组件
* 所以在nvue下取名为u--form内部其实还是u-form.vue只不过做一层中转
*/
import uvForm from '../u-form/u-form.vue';
import props from '../u-form/props.js'
export default {
// #ifdef MP-WEIXIN
name: 'u-form',
// #endif
// #ifndef MP-WEIXIN
name: 'u--form',
// #endif
mixins: [uni.$u.mpMixin, props, uni.$u.mixin],
components: {
uvForm
},
created() {
this.children = []
},
methods: {
//
setRules(rules) {
this.$refs.uForm.setRules(rules)
},
validate() {
/**
* 在微信小程序中通过this.$parent拿到的父组件是u--form而不是其内嵌的u-form
* 导致在u-form组件中拿不到对应的children数组从而校验无效所以这里每次调用u-form组件中的
* 对应方法的时候在小程序中都先将u--form的children赋值给u-form中的children
*/
// #ifdef MP-WEIXIN
this.setMpData()
// #endif
return this.$refs.uForm.validate()
},
validateField(value, callback) {
// #ifdef MP-WEIXIN
this.setMpData()
// #endif
return this.$refs.uForm.validateField(value, callback)
},
resetFields() {
// #ifdef MP-WEIXIN
this.setMpData()
// #endif
return this.$refs.uForm.resetFields()
},
clearValidate(props) {
// #ifdef MP-WEIXIN
this.setMpData()
// #endif
return this.$refs.uForm.clearValidate(props)
},
setMpData() {
this.$refs.uForm.children = this.children
}
},
}
</script>

View File

@ -0,0 +1,47 @@
<template>
<uvImage
:src="src"
:mode="mode"
:width="width"
:height="height"
:shape="shape"
:radius="radius"
:lazyLoad="lazyLoad"
:showMenuByLongpress="showMenuByLongpress"
:loadingIcon="loadingIcon"
:errorIcon="errorIcon"
:showLoading="showLoading"
:showError="showError"
:fade="fade"
:webp="webp"
:duration="duration"
:bgColor="bgColor"
:customStyle="customStyle"
@click="$emit('click')"
@error="$emit('error')"
@load="$emit('load')"
>
<template v-slot:loading>
<slot name="loading"></slot>
</template>
<template v-slot:error>
<slot name="error"></slot>
</template>
</uvImage>
</template>
<script>
/**
* 此组件存在的理由是在nvue下u-image被uni-app官方占用了u-image在nvue中相当于image组件
* 所以在nvue下取名为u--image内部其实还是u-iamge.vue只不过做一层中转
*/
import uvImage from '../u-image/u-image.vue';
import props from '../u-image/props.js';
export default {
name: 'u--image',
mixins: [uni.$u.mpMixin, props, uni.$u.mixin],
components: {
uvImage
},
}
</script>

View File

@ -0,0 +1,73 @@
<template>
<uvInput
:value="value"
:type="type"
:fixed="fixed"
:disabled="disabled"
:disabledColor="disabledColor"
:clearable="clearable"
:password="password"
:maxlength="maxlength"
:placeholder="placeholder"
:placeholderClass="placeholderClass"
:placeholderStyle="placeholderStyle"
:showWordLimit="showWordLimit"
:confirmType="confirmType"
:confirmHold="confirmHold"
:holdKeyboard="holdKeyboard"
:focus="focus"
:autoBlur="autoBlur"
:disableDefaultPadding="disableDefaultPadding"
:cursor="cursor"
:cursorSpacing="cursorSpacing"
:selectionStart="selectionStart"
:selectionEnd="selectionEnd"
:adjustPosition="adjustPosition"
:inputAlign="inputAlign"
:fontSize="fontSize"
:color="color"
:prefixIcon="prefixIcon"
:suffixIcon="suffixIcon"
:suffixIconStyle="suffixIconStyle"
:prefixIconStyle="prefixIconStyle"
:border="border"
:readonly="readonly"
:shape="shape"
:customStyle="customStyle"
:formatter="formatter"
:ignoreCompositionEvent="ignoreCompositionEvent"
@focus="$emit('focus')"
@blur="e => $emit('blur', e)"
@keyboardheightchange="$emit('keyboardheightchange')"
@change="e => $emit('change', e)"
@input="e => $emit('input', e)"
@confirm="e => $emit('confirm', e)"
@clear="$emit('clear')"
@click="$emit('click')"
>
<!-- #ifdef MP -->
<slot name="prefix"></slot>
<slot name="suffix"></slot>
<!-- #endif -->
<!-- #ifndef MP -->
<slot name="prefix" slot="prefix"></slot>
<slot name="suffix" slot="suffix"></slot>
<!-- #endif -->
</uvInput>
</template>
<script>
/**
* 此组件存在的理由是在nvue下u-input被uni-app官方占用了u-input在nvue中相当于input组件
* 所以在nvue下取名为u--input内部其实还是u-input.vue只不过做一层中转
*/
import uvInput from '../u-input/u-input.vue';
import props from '../u-input/props.js'
export default {
name: 'u--input',
mixins: [uni.$u.mpMixin, props, uni.$u.mixin],
components: {
uvInput
},
}
</script>

View File

@ -0,0 +1,44 @@
<template>
<uvText
:type="type"
:show="show"
:text="text"
:prefixIcon="prefixIcon"
:suffixIcon="suffixIcon"
:mode="mode"
:href="href"
:format="format"
:call="call"
:openType="openType"
:bold="bold"
:block="block"
:lines="lines"
:color="color"
:decoration="decoration"
:size="size"
:iconStyle="iconStyle"
:margin="margin"
:lineHeight="lineHeight"
:align="align"
:wordWrap="wordWrap"
:customStyle="customStyle"
@click="$emit('click')"
></uvText>
</template>
<script>
/**
* 此组件存在的理由是在nvue下u-text被uni-app官方占用了u-text在nvue中相当于input组件
* 所以在nvue下取名为u--input内部其实还是u-text.vue只不过做一层中转
* 不使用v-bind="$attrs"而是分开独立写传参是因为微信小程序不支持此写法
*/
import uvText from "../u-text/u-text.vue";
import props from "../u-text/props.js";
export default {
name: "u--text",
mixins: [uni.$u.mpMixin, props, uni.$u.mixin],
components: {
uvText,
},
};
</script>

View File

@ -0,0 +1,48 @@
<template>
<uvTextarea
:value="value"
:placeholder="placeholder"
:height="height"
:confirmType="confirmType"
:disabled="disabled"
:count="count"
:focus="focus"
:autoHeight="autoHeight"
:fixed="fixed"
:cursorSpacing="cursorSpacing"
:cursor="cursor"
:showConfirmBar="showConfirmBar"
:selectionStart="selectionStart"
:selectionEnd="selectionEnd"
:adjustPosition="adjustPosition"
:disableDefaultPadding="disableDefaultPadding"
:holdKeyboard="holdKeyboard"
:maxlength="maxlength"
:border="border"
:customStyle="customStyle"
:formatter="formatter"
:ignoreCompositionEvent="ignoreCompositionEvent"
@focus="e => $emit('focus')"
@blur="e => $emit('blur')"
@linechange="e => $emit('linechange', e)"
@confirm="e => $emit('confirm')"
@input="e => $emit('input', e)"
@keyboardheightchange="e => $emit('keyboardheightchange')"
></uvTextarea>
</template>
<script>
/**
* 此组件存在的理由是在nvue下u--textarea被uni-app官方占用了u-textarea在nvue中相当于textarea组件
* 所以在nvue下取名为u--textarea内部其实还是u-textarea.vue只不过做一层中转
*/
import uvTextarea from '../u-textarea/u-textarea.vue';
import props from '../u-textarea/props.js'
export default {
name: 'u--textarea',
mixins: [uni.$u.mpMixin, props, uni.$u.mixin],
components: {
uvTextarea
},
}
</script>

View File

@ -0,0 +1,54 @@
export default {
props: {
// 操作菜单是否展示 默认false
show: {
type: Boolean,
default: uni.$u.props.actionSheet.show
},
// 标题
title: {
type: String,
default: uni.$u.props.actionSheet.title
},
// 选项上方的描述信息
description: {
type: String,
default: uni.$u.props.actionSheet.description
},
// 数据
actions: {
type: Array,
default: uni.$u.props.actionSheet.actions
},
// 取消按钮的文字,不为空时显示按钮
cancelText: {
type: String,
default: uni.$u.props.actionSheet.cancelText
},
// 点击某个菜单项时是否关闭弹窗
closeOnClickAction: {
type: Boolean,
default: uni.$u.props.actionSheet.closeOnClickAction
},
// 处理底部安全区默认true
safeAreaInsetBottom: {
type: Boolean,
default: uni.$u.props.actionSheet.safeAreaInsetBottom
},
// 小程序的打开方式
openType: {
type: String,
default: uni.$u.props.actionSheet.openType
},
// 点击遮罩是否允许关闭 (默认true)
closeOnClickOverlay: {
type: Boolean,
default: uni.$u.props.actionSheet.closeOnClickOverlay
},
// 圆角值
round: {
type: [Boolean, String, Number],
default: uni.$u.props.actionSheet.round
}
}
}

View File

@ -0,0 +1,278 @@
<template>
<u-popup
:show="show"
mode="bottom"
@close="closeHandler"
:safeAreaInsetBottom="safeAreaInsetBottom"
:round="round"
>
<view class="u-action-sheet">
<view
class="u-action-sheet__header"
v-if="title"
>
<text class="u-action-sheet__header__title u-line-1">{{title}}</text>
<view
class="u-action-sheet__header__icon-wrap"
@tap.stop="cancel"
>
<u-icon
name="close"
size="17"
color="#c8c9cc"
bold
></u-icon>
</view>
</view>
<text
class="u-action-sheet__description"
:style="[{
marginTop: `${title && description ? 0 : '18px'}`
}]"
v-if="description"
>{{description}}</text>
<slot>
<u-line v-if="description"></u-line>
<view class="u-action-sheet__item-wrap">
<template v-for="(item, index) in actions">
<!-- #ifdef MP -->
<button
:key="index"
class="u-reset-button"
:openType="item.openType"
@getuserinfo="onGetUserInfo"
@contact="onContact"
@getphonenumber="onGetPhoneNumber"
@error="onError"
@launchapp="onLaunchApp"
@opensetting="onOpenSetting"
:lang="lang"
:session-from="sessionFrom"
:send-message-title="sendMessageTitle"
:send-message-path="sendMessagePath"
:send-message-img="sendMessageImg"
:show-message-card="showMessageCard"
:app-parameter="appParameter"
@tap="selectHandler(index)"
:hover-class="!item.disabled && !item.loading ? 'u-action-sheet--hover' : ''"
>
<!-- #endif -->
<view
class="u-action-sheet__item-wrap__item"
@tap.stop="selectHandler(index)"
:hover-class="!item.disabled && !item.loading ? 'u-action-sheet--hover' : ''"
:hover-stay-time="150"
>
<template v-if="!item.loading">
<text
class="u-action-sheet__item-wrap__item__name"
:style="[itemStyle(index)]"
>{{ item.name }}</text>
<text
v-if="item.subname"
class="u-action-sheet__item-wrap__item__subname"
>{{ item.subname }}</text>
</template>
<u-loading-icon
v-else
custom-class="van-action-sheet__loading"
size="18"
mode="circle"
/>
</view>
<!-- #ifdef MP -->
</button>
<!-- #endif -->
<u-line v-if="index !== actions.length - 1"></u-line>
</template>
</view>
</slot>
<u-gap
bgColor="#eaeaec"
height="6"
v-if="cancelText"
></u-gap>
<view hover-class="u-action-sheet--hover">
<text
@touchmove.stop.prevent
:hover-stay-time="150"
v-if="cancelText"
class="u-action-sheet__cancel-text"
@tap="cancel"
>{{cancelText}}</text>
</view>
</view>
</u-popup>
</template>
<script>
import openType from '../../libs/mixin/openType'
import button from '../../libs/mixin/button'
import props from './props.js';
/**
* ActionSheet 操作菜单
* @description 本组件用于从底部弹出一个操作菜单供用户选择并返回结果本组件功能类似于uni的uni.showActionSheetAPI配置更加灵活所有平台都表现一致
* @tutorial https://www.uviewui.com/components/actionSheet.html
*
* @property {Boolean} show 操作菜单是否展示 默认 false
* @property {String} title 操作菜单标题
* @property {String} description 选项上方的描述信息
* @property {Array<Object>} actions 按钮的文字数组见官方文档示例
* @property {String} cancelText 取消按钮的提示文字,不为空时显示按钮
* @property {Boolean} closeOnClickAction 点击某个菜单项时是否关闭弹窗 默认 true
* @property {Boolean} safeAreaInsetBottom 处理底部安全区 默认 true
* @property {String} openType 小程序的打开方式 (contact | launchApp | getUserInfo | openSetting getPhoneNumber error )
* @property {Boolean} closeOnClickOverlay 点击遮罩是否允许关闭 (默认 true )
* @property {Number|String} round 圆角值默认无圆角 (默认 0 )
* @property {String} lang 指定返回用户信息的语言zh_CN 简体中文zh_TW 繁体中文en 英文
* @property {String} sessionFrom 会话来源openType="contact"时有效
* @property {String} sendMessageTitle 会话内消息卡片标题openType="contact"时有效
* @property {String} sendMessagePath 会话内消息卡片点击跳转小程序路径openType="contact"时有效
* @property {String} sendMessageImg 会话内消息卡片图片openType="contact"时有效
* @property {Boolean} showMessageCard 是否显示会话内消息卡片设置此参数为 true用户进入客服会话会在右下角显示"可能要发送的小程序"提示用户点击后可以快速发送小程序消息openType="contact"时有效 默认 false
* @property {String} appParameter 打开 APP APP 传递的参数openType=launchApp 时有效
*
* @event {Function} select 点击ActionSheet列表项时触发
* @event {Function} close 点击取消按钮时触发
* @event {Function} getuserinfo 用户点击该按钮时会返回获取到的用户信息回调的 detail 数据与 wx.getUserInfo 返回的一致openType="getUserInfo"时有效
* @event {Function} contact 客服消息回调openType="contact"时有效
* @event {Function} getphonenumber 获取用户手机号回调openType="getPhoneNumber"时有效
* @event {Function} error 当使用开放能力时发生错误的回调openType="error"时有效
* @event {Function} launchapp 打开 APP 成功的回调openType="launchApp"时有效
* @event {Function} opensetting 在打开授权设置页后回调openType="openSetting"时有效
* @example <u-action-sheet :actions="list" :title="title" :show="show"></u-action-sheet>
*/
export default {
name: "u-action-sheet",
// propsmethodsmixin
mixins: [openType, button, uni.$u.mixin, props],
data() {
return {
}
},
computed: {
//
itemStyle() {
return (index) => {
let style = {};
if (this.actions[index].color) style.color = this.actions[index].color
if (this.actions[index].fontSize) style.fontSize = uni.$u.addUnit(this.actions[index].fontSize)
//
if (this.actions[index].disabled) style.color = '#c0c4cc'
return style;
}
},
},
methods: {
closeHandler() {
// close
if(this.closeOnClickOverlay) {
this.$emit('close')
}
},
//
cancel() {
this.$emit('close')
},
selectHandler(index) {
const item = this.actions[index]
if (item && !item.disabled && !item.loading) {
this.$emit('select', item)
if (this.closeOnClickAction) {
this.$emit('close')
}
}
},
}
}
</script>
<style lang="scss" scoped>
@import "../../libs/css/components.scss";
$u-action-sheet-reset-button-width:100% !default;
$u-action-sheet-title-font-size: 16px !default;
$u-action-sheet-title-padding: 12px 30px !default;
$u-action-sheet-title-color: $u-main-color !default;
$u-action-sheet-header-icon-wrap-right:15px !default;
$u-action-sheet-header-icon-wrap-top:15px !default;
$u-action-sheet-description-font-size:13px !default;
$u-action-sheet-description-color:14px !default;
$u-action-sheet-description-margin: 18px 15px !default;
$u-action-sheet-item-wrap-item-padding:15px !default;
$u-action-sheet-item-wrap-name-font-size:16px !default;
$u-action-sheet-item-wrap-subname-font-size:13px !default;
$u-action-sheet-item-wrap-subname-color: #c0c4cc !default;
$u-action-sheet-item-wrap-subname-margin-top:10px !default;
$u-action-sheet-cancel-text-font-size:16px !default;
$u-action-sheet-cancel-text-color:$u-content-color !default;
$u-action-sheet-cancel-text-font-size:15px !default;
$u-action-sheet-cancel-text-hover-background-color:rgb(242, 243, 245) !default;
.u-reset-button {
width: $u-action-sheet-reset-button-width;
}
.u-action-sheet {
text-align: center;
&__header {
position: relative;
padding: $u-action-sheet-title-padding;
&__title {
font-size: $u-action-sheet-title-font-size;
color: $u-action-sheet-title-color;
font-weight: bold;
text-align: center;
}
&__icon-wrap {
position: absolute;
right: $u-action-sheet-header-icon-wrap-right;
top: $u-action-sheet-header-icon-wrap-top;
}
}
&__description {
font-size: $u-action-sheet-description-font-size;
color: $u-tips-color;
margin: $u-action-sheet-description-margin;
text-align: center;
}
&__item-wrap {
&__item {
padding: $u-action-sheet-item-wrap-item-padding;
@include flex;
align-items: center;
justify-content: center;
flex-direction: column;
&__name {
font-size: $u-action-sheet-item-wrap-name-font-size;
color: $u-main-color;
text-align: center;
}
&__subname {
font-size: $u-action-sheet-item-wrap-subname-font-size;
color: $u-action-sheet-item-wrap-subname-color;
margin-top: $u-action-sheet-item-wrap-subname-margin-top;
text-align: center;
}
}
}
&__cancel-text {
font-size: $u-action-sheet-cancel-text-font-size;
color: $u-action-sheet-cancel-text-color;
text-align: center;
padding: $u-action-sheet-cancel-text-font-size;
}
&--hover {
background-color: $u-action-sheet-cancel-text-hover-background-color;
}
}
</style>

View File

@ -0,0 +1,59 @@
export default {
props: {
// 图片地址Array<String>|Array<Object>形式
urls: {
type: Array,
default: uni.$u.props.album.urls
},
// 指定从数组的对象元素中读取哪个属性作为图片地址
keyName: {
type: String,
default: uni.$u.props.album.keyName
},
// 单图时,图片长边的长度
singleSize: {
type: [String, Number],
default: uni.$u.props.album.singleSize
},
// 多图时,图片边长
multipleSize: {
type: [String, Number],
default: uni.$u.props.album.multipleSize
},
// 多图时,图片水平和垂直之间的间隔
space: {
type: [String, Number],
default: uni.$u.props.album.space
},
// 单图时,图片缩放裁剪的模式
singleMode: {
type: String,
default: uni.$u.props.album.singleMode
},
// 多图时,图片缩放裁剪的模式
multipleMode: {
type: String,
default: uni.$u.props.album.multipleMode
},
// 最多展示的图片数量,超出时最后一个位置将会显示剩余图片数量
maxCount: {
type: [String, Number],
default: uni.$u.props.album.maxCount
},
// 是否可以预览图片
previewFullImage: {
type: Boolean,
default: uni.$u.props.album.previewFullImage
},
// 每行展示图片数量如设置singleSize和multipleSize将会无效
rowCount: {
type: [String, Number],
default: uni.$u.props.album.rowCount
},
// 超出maxCount时是否显示查看更多的提示
showMore: {
type: Boolean,
default: uni.$u.props.album.showMore
}
}
}

View File

@ -0,0 +1,259 @@
<template>
<view class="u-album">
<view
class="u-album__row"
ref="u-album__row"
v-for="(arr, index) in showUrls"
:forComputedUse="albumWidth"
:key="index"
>
<view
class="u-album__row__wrapper"
v-for="(item, index1) in arr"
:key="index1"
:style="[imageStyle(index + 1, index1 + 1)]"
@tap="previewFullImage ? onPreviewTap(getSrc(item)) : ''"
>
<image
:src="getSrc(item)"
:mode="
urls.length === 1
? imageHeight > 0
? singleMode
: 'widthFix'
: multipleMode
"
:style="[
{
width: imageWidth,
height: imageHeight
}
]"
></image>
<view
v-if="
showMore &&
urls.length > rowCount * showUrls.length &&
index === showUrls.length - 1 &&
index1 === showUrls[showUrls.length - 1].length - 1
"
class="u-album__row__wrapper__text"
>
<u--text
:text="`+${urls.length - maxCount}`"
color="#fff"
:size="multipleSize * 0.3"
align="center"
customStyle="justify-content: center"
></u--text>
</view>
</view>
</view>
</view>
</template>
<script>
import props from './props.js'
// #ifdef APP-NVUE
// weexKPIdom
const dom = uni.requireNativePlugin('dom')
// #endif
/**
* Album 相册
* @description 本组件提供一个类似相册的功能让开发者开发起来更加得心应手减少重复的模板代码
* @tutorial https://www.uviewui.com/components/album.html
*
* @property {Array} urls 图片地址列表 Array<String>|Array<Object>形式
* @property {String} keyName 指定从数组的对象元素中读取哪个属性作为图片地址
* @property {String | Number} singleSize 单图时图片长边的长度 默认 180
* @property {String | Number} multipleSize 多图时图片边长 默认 70
* @property {String | Number} space 多图时图片水平和垂直之间的间隔 默认 6
* @property {String} singleMode 单图时图片缩放裁剪的模式 默认 'scaleToFill'
* @property {String} multipleMode 多图时图片缩放裁剪的模式 默认 'aspectFill'
* @property {String | Number} maxCount 取消按钮的提示文字 默认 9
* @property {Boolean} previewFullImage 是否可以预览图片 默认 true
* @property {String | Number} rowCount 每行展示图片数量如设置singleSize和multipleSize将会无效 默认 3
* @property {Boolean} showMore 超出maxCount时是否显示查看更多的提示 默认 true
*
* @event {Function} albumWidth 某些特殊的情况下需要让文字与相册的宽度相等这里事件的形式对外发送 回调参数 width
* @example <u-album :urls="urls2" @albumWidth="width => albumWidth = width" multipleSize="68" ></u-album>
*/
export default {
name: 'u-album',
mixins: [uni.$u.mpMixin, uni.$u.mixin, props],
data() {
return {
//
singleWidth: 0,
//
singleHeight: 0,
//
singlePercent: 0.6
}
},
watch: {
urls: {
immediate: true,
handler(newVal) {
if (newVal.length === 1) {
this.getImageRect()
}
}
}
},
computed: {
imageStyle() {
return (index1, index2) => {
const { space, rowCount, multipleSize, urls } = this,
{ addUnit, addStyle } = uni.$u,
rowLen = this.showUrls.length,
allLen = this.urls.length
const style = {
marginRight: addUnit(space),
marginBottom: addUnit(space)
}
//
if (index1 === rowLen) style.marginBottom = 0
//
if (
index2 === rowCount ||
(index1 === rowLen &&
index2 === this.showUrls[index1 - 1].length)
)
style.marginRight = 0
return style
}
},
//
showUrls() {
const arr = []
this.urls.map((item, index) => {
//
if (index + 1 <= this.maxCount) {
//
const itemIndex = Math.floor(index / this.rowCount)
//
if (!arr[itemIndex]) {
arr[itemIndex] = []
}
arr[itemIndex].push(item)
}
})
return arr
},
imageWidth() {
return uni.$u.addUnit(
this.urls.length === 1 ? this.singleWidth : this.multipleSize
)
},
imageHeight() {
return uni.$u.addUnit(
this.urls.length === 1 ? this.singleHeight : this.multipleSize
)
},
// computedurls
//
albumWidth() {
let width = 0
if (this.urls.length === 1) {
width = this.singleWidth
} else {
width =
this.showUrls[0].length * this.multipleSize +
this.space * (this.showUrls[0].length - 1)
}
this.$emit('albumWidth', width)
return width
}
},
methods: {
//
onPreviewTap(url) {
const urls = this.urls.map((item) => {
return this.getSrc(item)
})
uni.previewImage({
current: url,
urls
})
},
//
getSrc(item) {
return uni.$u.test.object(item)
? (this.keyName && item[this.keyName]) || item.src
: item
},
//
// download
// (singlePercent)
getImageRect() {
const src = this.getSrc(this.urls[0])
uni.getImageInfo({
src,
success: (res) => {
//
const isHorizotal = res.width >= res.height
this.singleWidth = isHorizotal
? this.singleSize
: (res.width / res.height) * this.singleSize
this.singleHeight = !isHorizotal
? this.singleSize
: (res.height / res.width) * this.singleWidth
},
fail: () => {
this.getComponentWidth()
}
})
},
//
async getComponentWidth() {
// dom
await uni.$u.sleep(30)
// #ifndef APP-NVUE
this.$uGetRect('.u-album__row').then((size) => {
this.singleWidth = size.width * this.singlePercent
})
// #endif
// #ifdef APP-NVUE
// ref="u-album__row"forthis.$refs['u-album__row']
const ref = this.$refs['u-album__row'][0]
ref &&
dom.getComponentRect(ref, (res) => {
this.singleWidth = res.size.width * this.singlePercent
})
// #endif
}
}
}
</script>
<style lang="scss" scoped>
@import '../../libs/css/components.scss';
.u-album {
@include flex(column);
&__row {
@include flex(row);
flex-wrap: wrap;
&__wrapper {
position: relative;
&__text {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-color: rgba(0, 0, 0, 0.3);
@include flex(row);
justify-content: center;
align-items: center;
}
}
}
}
</style>

View File

@ -0,0 +1,44 @@
export default {
props: {
// 显示文字
title: {
type: String,
default: uni.$u.props.alert.title
},
// 主题success/warning/info/error
type: {
type: String,
default: uni.$u.props.alert.type
},
// 辅助性文字
description: {
type: String,
default: uni.$u.props.alert.description
},
// 是否可关闭
closable: {
type: Boolean,
default: uni.$u.props.alert.closable
},
// 是否显示图标
showIcon: {
type: Boolean,
default: uni.$u.props.alert.showIcon
},
// 浅或深色调light-浅色dark-深色
effect: {
type: String,
default: uni.$u.props.alert.effect
},
// 文字是否居中
center: {
type: Boolean,
default: uni.$u.props.alert.center
},
// 字体大小
fontSize: {
type: [String, Number],
default: uni.$u.props.alert.fontSize
}
}
}

View File

@ -0,0 +1,243 @@
<template>
<u-transition
mode="fade"
:show="show"
>
<view
class="u-alert"
:class="[`u-alert--${type}--${effect}`]"
@tap.stop="clickHandler"
:style="[$u.addStyle(customStyle)]"
>
<view
class="u-alert__icon"
v-if="showIcon"
>
<u-icon
:name="iconName"
size="18"
:color="iconColor"
></u-icon>
</view>
<view
class="u-alert__content"
:style="[{
paddingRight: closable ? '20px' : 0
}]"
>
<text
class="u-alert__content__title"
v-if="title"
:style="[{
fontSize: $u.addUnit(fontSize),
textAlign: center ? 'center' : 'left'
}]"
:class="[effect === 'dark' ? 'u-alert__text--dark' : `u-alert__text--${type}--light`]"
>{{ title }}</text>
<text
class="u-alert__content__desc"
v-if="description"
:style="[{
fontSize: $u.addUnit(fontSize),
textAlign: center ? 'center' : 'left'
}]"
:class="[effect === 'dark' ? 'u-alert__text--dark' : `u-alert__text--${type}--light`]"
>{{ description }}</text>
</view>
<view
class="u-alert__close"
v-if="closable"
@tap.stop="closeHandler"
>
<u-icon
name="close"
:color="iconColor"
size="15"
></u-icon>
</view>
</view>
</u-transition>
</template>
<script>
import props from './props.js';
/**
* Alert 警告提示
* @description 警告提示展现需要关注的信息
* @tutorial https://www.uviewui.com/components/alertTips.html
*
* @property {String} title 显示的文字
* @property {String} type 使用预设的颜色 默认 'warning'
* @property {String} description 辅助性文字颜色比title浅一点字号也小一点可选
* @property {Boolean} closable 关闭按钮(默认为叉号icon图标) 默认 false
* @property {Boolean} showIcon 是否显示左边的辅助图标 默认 false
* @property {String} effect 多图时图片缩放裁剪的模式 默认 'light'
* @property {Boolean} center 文字是否居中 默认 false
* @property {String | Number} fontSize 字体大小 默认 14
* @property {Object} customStyle 定义需要用到的外部样式
* @event {Function} click 点击组件时触发
* @example <u-alert :title="title" type = "warning" :closable="closable" :description = "description"></u-alert>
*/
export default {
name: 'u-alert',
mixins: [uni.$u.mpMixin, uni.$u.mixin, props],
data() {
return {
show: true
}
},
computed: {
iconColor() {
return this.effect === 'light' ? this.type : '#fff'
},
//
iconName() {
switch (this.type) {
case 'success':
return 'checkmark-circle-fill';
break;
case 'error':
return 'close-circle-fill';
break;
case 'warning':
return 'error-circle-fill';
break;
case 'info':
return 'info-circle-fill';
break;
case 'primary':
return 'more-circle-fill';
break;
default:
return 'error-circle-fill';
}
}
},
methods: {
//
clickHandler() {
this.$emit('click')
},
//
closeHandler() {
this.show = false
}
}
}
</script>
<style lang="scss" scoped>
@import "../../libs/css/components.scss";
.u-alert {
position: relative;
background-color: $u-primary;
padding: 8px 10px;
@include flex(row);
align-items: center;
border-top-left-radius: 4px;
border-top-right-radius: 4px;
border-bottom-left-radius: 4px;
border-bottom-right-radius: 4px;
&--primary--dark {
background-color: $u-primary;
}
&--primary--light {
background-color: #ecf5ff;
}
&--error--dark {
background-color: $u-error;
}
&--error--light {
background-color: #FEF0F0;
}
&--success--dark {
background-color: $u-success;
}
&--success--light {
background-color: #f5fff0;
}
&--warning--dark {
background-color: $u-warning;
}
&--warning--light {
background-color: #FDF6EC;
}
&--info--dark {
background-color: $u-info;
}
&--info--light {
background-color: #f4f4f5;
}
&__icon {
margin-right: 5px;
}
&__content {
@include flex(column);
flex: 1;
&__title {
color: $u-main-color;
font-size: 14px;
font-weight: bold;
color: #fff;
margin-bottom: 2px;
}
&__desc {
color: $u-main-color;
font-size: 14px;
flex-wrap: wrap;
color: #fff;
}
}
&__title--dark,
&__desc--dark {
color: #FFFFFF;
}
&__text--primary--light,
&__text--primary--light {
color: $u-primary;
}
&__text--success--light,
&__text--success--light {
color: $u-success;
}
&__text--warning--light,
&__text--warning--light {
color: $u-warning;
}
&__text--error--light,
&__text--error--light {
color: $u-error;
}
&__text--info--light,
&__text--info--light {
color: $u-info;
}
&__close {
position: absolute;
top: 11px;
right: 10px;
}
}
</style>

View File

@ -0,0 +1,52 @@
export default {
props: {
// 头像图片组
urls: {
type: Array,
default: uni.$u.props.avatarGroup.urls
},
// 最多展示的头像数量
maxCount: {
type: [String, Number],
default: uni.$u.props.avatarGroup.maxCount
},
// 头像形状
shape: {
type: String,
default: uni.$u.props.avatarGroup.shape
},
// 图片裁剪模式
mode: {
type: String,
default: uni.$u.props.avatarGroup.mode
},
// 超出maxCount时是否显示查看更多的提示
showMore: {
type: Boolean,
default: uni.$u.props.avatarGroup.showMore
},
// 头像大小
size: {
type: [String, Number],
default: uni.$u.props.avatarGroup.size
},
// 指定从数组的对象元素中读取哪个属性作为图片地址
keyName: {
type: String,
default: uni.$u.props.avatarGroup.keyName
},
// 头像之间的遮挡比例
gap: {
type: [String, Number],
validator(value) {
return value >= 0 && value <= 1
},
default: uni.$u.props.avatarGroup.gap
},
// 需额外显示的值
extraValue: {
type: [Number, String],
default: uni.$u.props.avatarGroup.extraValue
}
}
}

View File

@ -0,0 +1,103 @@
<template>
<view class="u-avatar-group">
<view
class="u-avatar-group__item"
v-for="(item, index) in showUrl"
:key="index"
:style="{
marginLeft: index === 0 ? 0 : $u.addUnit(-size * gap)
}"
>
<u-avatar
:size="size"
:shape="shape"
:mode="mode"
:src="$u.test.object(item) ? keyName && item[keyName] || item.url : item"
></u-avatar>
<view
class="u-avatar-group__item__show-more"
v-if="showMore && index === showUrl.length - 1 && (urls.length > maxCount || extraValue > 0)"
@tap="clickHandler"
>
<u--text
color="#ffffff"
:size="size * 0.4"
:text="`+${extraValue || urls.length - showUrl.length}`"
align="center"
customStyle="justify-content: center"
></u--text>
</view>
</view>
</view>
</template>
<script>
import props from './props.js';
/**
* AvatarGroup 头像组
* @description 本组件一般用于展示头像的地方如个人中心或者评论列表页的用户头像展示等场所
* @tutorial https://www.uviewui.com/components/avatar.html
*
* @property {Array} urls 头像图片组 默认 []
* @property {String | Number} maxCount 最多展示的头像数量 默认 5
* @property {String} shape 头像形状 'circle' (默认) | 'square'
* @property {String} mode 图片裁剪模式默认 'scaleToFill'
* @property {Boolean} showMore 超出maxCount时是否显示查看更多的提示 默认 true
* @property {String | Number} size 头像大小 默认 40
* @property {String} keyName 指定从数组的对象元素中读取哪个属性作为图片地址
* @property {String | Number} gap 头像之间的遮挡比例0.4代表遮挡40% 默认 0.5
* @property {String | Number} extraValue 需额外显示的值
* @event {Function} showMore 头像组更多点击
* @example <u-avatar-group:urls="urls" size="35" gap="0.4" ></u-avatar-group:urls=>
*/
export default {
name: 'u-avatar-group',
mixins: [uni.$u.mpMixin, uni.$u.mixin, props],
data() {
return {
}
},
computed: {
showUrl() {
return this.urls.slice(0, this.maxCount)
}
},
methods: {
clickHandler() {
this.$emit('showMore')
}
},
}
</script>
<style lang="scss" scoped>
@import "../../libs/css/components.scss";
.u-avatar-group {
@include flex;
&__item {
margin-left: -10px;
position: relative;
&--no-indent {
// 使:first-childnvue
margin-left: 0;
}
&__show-more {
position: absolute;
top: 0;
bottom: 0;
left: 0;
right: 0;
background-color: rgba(0, 0, 0, 0.3);
@include flex;
align-items: center;
justify-content: center;
border-radius: 100px;
}
}
}
</style>

View File

@ -0,0 +1,78 @@
export default {
props: {
// 头像图片路径(不能为相对路径)
src: {
type: String,
default: uni.$u.props.avatar.src
},
// 头像形状circle-圆形square-方形
shape: {
type: String,
default: uni.$u.props.avatar.shape
},
// 头像尺寸
size: {
type: [String, Number],
default: uni.$u.props.avatar.size
},
// 裁剪模式
mode: {
type: String,
default: uni.$u.props.avatar.mode
},
// 显示的文字
text: {
type: String,
default: uni.$u.props.avatar.text
},
// 背景色
bgColor: {
type: String,
default: uni.$u.props.avatar.bgColor
},
// 文字颜色
color: {
type: String,
default: uni.$u.props.avatar.color
},
// 文字大小
fontSize: {
type: [String, Number],
default: uni.$u.props.avatar.fontSize
},
// 显示的图标
icon: {
type: String,
default: uni.$u.props.avatar.icon
},
// 显示小程序头像只对百度微信QQ小程序有效
mpAvatar: {
type: Boolean,
default: uni.$u.props.avatar.mpAvatar
},
// 是否使用随机背景色
randomBgColor: {
type: Boolean,
default: uni.$u.props.avatar.randomBgColor
},
// 加载失败的默认头像(组件有内置默认图片)
defaultUrl: {
type: String,
default: uni.$u.props.avatar.defaultUrl
},
// 如果配置了randomBgColor为true且配置了此值则从默认的背景色数组中取出对应索引的颜色值取值0-19之间
colorIndex: {
type: [String, Number],
// 校验参数规则索引在0-19之间
validator(n) {
return uni.$u.test.range(n, [0, 19]) || n === ''
},
default: uni.$u.props.avatar.colorIndex
},
// 组件标识符
name: {
type: String,
default: uni.$u.props.avatar.name
}
}
}

View File

@ -0,0 +1,172 @@
<template>
<view
class="u-avatar"
:class="[`u-avatar--${shape}`]"
:style="[{
backgroundColor: (text || icon) ? (randomBgColor ? colors[colorIndex !== '' ? colorIndex : $u.random(0, 19)] : bgColor) : 'transparent',
width: $u.addUnit(size),
height: $u.addUnit(size),
}, $u.addStyle(customStyle)]"
@tap="clickHandler"
>
<slot>
<!-- #ifdef MP-WEIXIN || MP-QQ || MP-BAIDU -->
<open-data
v-if="mpAvatar && allowMp"
type="userAvatarUrl"
:style="[{
width: $u.addUnit(size),
height: $u.addUnit(size)
}]"
/>
<!-- #endif -->
<!-- #ifndef MP-WEIXIN && MP-QQ && MP-BAIDU -->
<template v-if="mpAvatar && allowMp"></template>
<!-- #endif -->
<u-icon
v-else-if="icon"
:name="icon"
:size="fontSize"
:color="color"
></u-icon>
<u--text
v-else-if="text"
:text="text"
:size="fontSize"
:color="color"
align="center"
customStyle="justify-content: center"
></u--text>
<image
class="u-avatar__image"
v-else
:class="[`u-avatar__image--${shape}`]"
:src="avatarUrl || defaultUrl"
:mode="mode"
@error="errorHandler"
:style="[{
width: $u.addUnit(size),
height: $u.addUnit(size)
}]"
></image>
</slot>
</view>
</template>
<script>
import props from './props.js';
const base64Avatar =
"data:image/jpg;base64,/9j/4QAYRXhpZgAASUkqAAgAAAAAAAAAAAAAAP/sABFEdWNreQABAAQAAAA8AAD/4QMraHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wLwA8P3hwYWNrZXQgYmVnaW49Iu+7vyIgaWQ9Ilc1TTBNcENlaGlIenJlU3pOVGN6a2M5ZCI/PiA8eDp4bXBtZXRhIHhtbG5zOng9ImFkb2JlOm5zOm1ldGEvIiB4OnhtcHRrPSJBZG9iZSBYTVAgQ29yZSA1LjMtYzAxMSA2Ni4xNDU2NjEsIDIwMTIvMDIvMDYtMTQ6NTY6MjcgICAgICAgICI+IDxyZGY6UkRGIHhtbG5zOnJkZj0iaHR0cDovL3d3dy53My5vcmcvMTk5OS8wMi8yMi1yZGYtc3ludGF4LW5zIyI+IDxyZGY6RGVzY3JpcHRpb24gcmRmOmFib3V0PSIiIHhtbG5zOnhtcD0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wLyIgeG1sbnM6eG1wTU09Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9tbS8iIHhtbG5zOnN0UmVmPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvc1R5cGUvUmVzb3VyY2VSZWYjIiB4bXA6Q3JlYXRvclRvb2w9IkFkb2JlIFBob3Rvc2hvcCBDUzYgKFdpbmRvd3MpIiB4bXBNTTpJbnN0YW5jZUlEPSJ4bXAuaWlkOjREMEQwRkY0RjgwNDExRUE5OTY2RDgxODY3NkJFODMxIiB4bXBNTTpEb2N1bWVudElEPSJ4bXAuZGlkOjREMEQwRkY1RjgwNDExRUE5OTY2RDgxODY3NkJFODMxIj4gPHhtcE1NOkRlcml2ZWRGcm9tIHN0UmVmOmluc3RhbmNlSUQ9InhtcC5paWQ6NEQwRDBGRjJGODA0MTFFQTk5NjZEODE4Njc2QkU4MzEiIHN0UmVmOmRvY3VtZW50SUQ9InhtcC5kaWQ6NEQwRDBGRjNGODA0MTFFQTk5NjZEODE4Njc2QkU4MzEiLz4gPC9yZGY6RGVzY3JpcHRpb24+IDwvcmRmOlJERj4gPC94OnhtcG1ldGE+IDw/eHBhY2tldCBlbmQ9InIiPz7/7gAOQWRvYmUAZMAAAAAB/9sAhAAGBAQEBQQGBQUGCQYFBgkLCAYG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";
/**
* Avatar 头像
* @description 本组件一般用于展示头像的地方如个人中心或者评论列表页的用户头像展示等场所
* @tutorial https://www.uviewui.com/components/avatar.html
*
* @property {String} src 头像路径如加载失败将会显示默认头像(不能为相对路径)
* @property {String} shape 头像形状 circle (默认) | square
* @property {String | Number} size 头像尺寸可以为指定字符串(large, default, mini)或者数值 默认 40
* @property {String} mode 头像图片的裁剪类型与uni的image组件的mode参数一致如效果达不到需求可尝试传widthFix值 默认 'scaleToFill'
* @property {String} text 用文字替代图片级别优先于src
* @property {String} bgColor 背景颜色一般显示文字时用 默认 '#c0c4cc'
* @property {String} color 文字颜色 默认 '#ffffff'
* @property {String | Number} fontSize 文字大小 默认 18
* @property {String} icon 显示的图标
* @property {Boolean} mpAvatar 显示小程序头像只对百度微信QQ小程序有效 默认 false
* @property {Boolean} randomBgColor 是否使用随机背景色 默认 false
* @property {String} defaultUrl 加载失败的默认头像(组件有内置默认图片)
* @property {String | Number} colorIndex 如果配置了randomBgColor为true且配置了此值则从默认的背景色数组中取出对应索引的颜色值取值0-19之间
* @property {String} name 组件标识符 默认 'level'
* @property {Object} customStyle 定义需要用到的外部样式
*
* @event {Function} click 点击组件时触发 index: 用户传递的标识符
* @example <u-avatar :src="src" mode="square"></u-avatar>
*/
export default {
name: 'u-avatar',
mixins: [uni.$u.mpMixin, uni.$u.mixin, props],
data() {
return {
// randomBgColortrue
colors: ['#ffb34b', '#f2bba9', '#f7a196', '#f18080', '#88a867', '#bfbf39', '#89c152', '#94d554', '#f19ec2',
'#afaae4', '#e1b0df', '#c38cc1', '#72dcdc', '#9acdcb', '#77b1cc', '#448aca', '#86cefa', '#98d1ee',
'#73d1f1',
'#80a7dc'
],
avatarUrl: this.src,
allowMp: false
}
},
watch: {
// srcavatarUrlsrc
// props
src: {
immediate: true,
handler(newVal) {
this.avatarUrl = newVal
// srcerrorsrc''
if(!newVal) {
this.errorHandler()
}
}
}
},
computed: {
imageStyle() {
const style = {}
return style
}
},
created() {
this.init()
},
methods: {
init() {
// open-data
// uni.getUserInfo()
//
// #ifdef MP-WEIXIN || MP-QQ || MP-BAIDU
this.allowMp = true
// #endif
},
// name"/"
isImg() {
return this.src.indexOf('/') !== -1
},
//
errorHandler() {
this.avatarUrl = this.defaultUrl || base64Avatar
},
clickHandler() {
this.$emit('click', this.name)
}
}
}
</script>
<style lang="scss" scoped>
@import "../../libs/css/components.scss";
.u-avatar {
@include flex;
align-items: center;
justify-content: center;
&--circle {
border-radius: 100px;
}
&--square {
border-radius: 4px;
}
&__image {
&--circle {
border-radius: 100px;
}
&--square {
border-radius: 4px;
}
}
}
</style>

View File

@ -0,0 +1,54 @@
export default {
props: {
// 返回顶部的形状circle-圆形square-方形
mode: {
type: String,
default: uni.$u.props.backtop.mode
},
// 自定义图标
icon: {
type: String,
default: uni.$u.props.backtop.icon
},
// 提示文字
text: {
type: String,
default: uni.$u.props.backtop.text
},
// 返回顶部滚动时间
duration: {
type: [String, Number],
default: uni.$u.props.backtop.duration
},
// 滚动距离
scrollTop: {
type: [String, Number],
default: uni.$u.props.backtop.scrollTop
},
// 距离顶部多少距离显示单位px
top: {
type: [String, Number],
default: uni.$u.props.backtop.top
},
// 返回顶部按钮到底部的距离单位px
bottom: {
type: [String, Number],
default: uni.$u.props.backtop.bottom
},
// 返回顶部按钮到右边的距离单位px
right: {
type: [String, Number],
default: uni.$u.props.backtop.right
},
// 层级
zIndex: {
type: [String, Number],
default: uni.$u.props.backtop.zIndex
},
// 图标的样式,对象形式
iconStyle: {
type: Object,
default: uni.$u.props.backtop.iconStyle
}
}
}

View File

@ -0,0 +1,129 @@
<template>
<u-transition
mode="fade"
:customStyle="backTopStyle"
:show="show"
>
<view
class="u-back-top"
:style="[contentStyle]"
v-if="!$slots.default && !$slots.$default"
@click="backToTop"
>
<u-icon
:name="icon"
:custom-style="iconStyle"
></u-icon>
<text
v-if="text"
class="u-back-top__text"
>{{text}}</text>
</view>
<slot v-else />
</u-transition>
</template>
<script>
import props from './props.js';
// #ifdef APP-NVUE
const dom = weex.requireModule('dom')
// #endif
/**
* backTop 返回顶部
* @description 本组件一个用于长页面滑动一定距离后出现返回顶部按钮方便快速返回顶部的场景
* @tutorial https://uviewui.com/components/backTop.html
*
* @property {String} mode 返回顶部的形状circle-圆形square-方形 默认 'circle'
* @property {String} icon 自定义图标 默认 'arrow-upward' 见官方文档示例
* @property {String} text 提示文字
* @property {String | Number} duration 返回顶部滚动时间 默认 100
* @property {String | Number} scrollTop 滚动距离 默认 0
* @property {String | Number} top 距离顶部多少距离显示单位px 默认 400
* @property {String | Number} bottom 返回顶部按钮到底部的距离单位px 默认 100
* @property {String | Number} right 返回顶部按钮到右边的距离单位px 默认 20
* @property {String | Number} zIndex 层级 默认 9
* @property {Object<Object>} iconStyle 图标的样式对象形式 默认 {color: '#909399',fontSize: '19px'}
* @property {Object} customStyle 定义需要用到的外部样式
*
* @example <u-back-top :scrollTop="scrollTop"></u-back-top>
*/
export default {
name: 'u-back-top',
mixins: [uni.$u.mpMixin, uni.$u.mixin,props],
computed: {
backTopStyle() {
//
const style = {
bottom: uni.$u.addUnit(this.bottom),
right: uni.$u.addUnit(this.right),
width: '40px',
height: '40px',
position: 'fixed',
zIndex: 10,
}
return style
},
show() {
return uni.$u.getPx(this.scrollTop) > uni.$u.getPx(this.top)
},
contentStyle() {
const style = {}
let radius = 0
//
if(this.mode === 'circle') {
radius = '100px'
} else {
radius = '4px'
}
// nvue
style.borderTopLeftRadius = radius
style.borderTopRightRadius = radius
style.borderBottomLeftRadius = radius
style.borderBottomRightRadius = radius
return uni.$u.deepMerge(style, uni.$u.addStyle(this.customStyle))
}
},
methods: {
backToTop() {
// #ifdef APP-NVUE
if (!this.$parent.$refs['u-back-top']) {
uni.$u.error(`nvue页面需要给页面最外层元素设置"ref='u-back-top'`)
}
dom.scrollToElement(this.$parent.$refs['u-back-top'], {
offset: 0
})
// #endif
// #ifndef APP-NVUE
uni.pageScrollTo({
scrollTop: 0,
duration: this.duration
});
// #endif
this.$emit('click')
}
}
}
</script>
<style lang="scss" scoped>
@import '../../libs/css/components.scss';
$u-back-top-flex:1 !default;
$u-back-top-height:100% !default;
$u-back-top-background-color:#E1E1E1 !default;
$u-back-top-tips-font-size:12px !default;
.u-back-top {
@include flex;
flex-direction: column;
align-items: center;
flex:$u-back-top-flex;
height: $u-back-top-height;
justify-content: center;
background-color: $u-back-top-background-color;
&__tips {
font-size:$u-back-top-tips-font-size;
transform: scale(0.8);
}
}
</style>

View File

@ -0,0 +1,72 @@
export default {
props: {
// 是否显示圆点
isDot: {
type: Boolean,
default: uni.$u.props.badge.isDot
},
// 显示的内容
value: {
type: [Number, String],
default: uni.$u.props.badge.value
},
// 是否显示
show: {
type: Boolean,
default: uni.$u.props.badge.show
},
// 最大值,超过最大值会显示 '{max}+'
max: {
type: [Number, String],
default: uni.$u.props.badge.max
},
// 主题类型error|warning|success|primary
type: {
type: String,
default: uni.$u.props.badge.type
},
// 当数值为 0 时,是否展示 Badge
showZero: {
type: Boolean,
default: uni.$u.props.badge.showZero
},
// 背景颜色优先级比type高如设置type参数会失效
bgColor: {
type: [String, null],
default: uni.$u.props.badge.bgColor
},
// 字体颜色
color: {
type: [String, null],
default: uni.$u.props.badge.color
},
// 徽标形状circle-四角均为圆角horn-左下角为直角
shape: {
type: String,
default: uni.$u.props.badge.shape
},
// 设置数字的显示方式overflow|ellipsis|limit
// overflow会根据max字段判断超出显示`${max}+`
// ellipsis会根据max判断超出显示`${max}...`
// limit会依据1000作为判断条件超出1000显示`${value/1000}K`比如2.2k、3.34w最多保留2位小数
numberType: {
type: String,
default: uni.$u.props.badge.numberType
},
// 设置badge的位置偏移格式为 [x, y]也即设置的为top和right的值absolute为true时有效
offset: {
type: Array,
default: uni.$u.props.badge.offset
},
// 是否反转背景和字体颜色
inverted: {
type: Boolean,
default: uni.$u.props.badge.inverted
},
// 是否绝对定位
absolute: {
type: Boolean,
default: uni.$u.props.badge.absolute
}
}
}

View File

@ -0,0 +1,171 @@
<template>
<text
v-if="show && ((Number(value) === 0 ? showZero : true) || isDot)"
:class="[isDot ? 'u-badge--dot' : 'u-badge--not-dot', inverted && 'u-badge--inverted', shape === 'horn' && 'u-badge--horn', `u-badge--${type}${inverted ? '--inverted' : ''}`]"
:style="[$u.addStyle(customStyle), badgeStyle]"
class="u-badge"
>{{ isDot ? '' :showValue }}</text>
</template>
<script>
import props from './props.js';
/**
* badge 徽标数
* @description 该组件一般用于图标右上角显示未读的消息数量提示用户点击有圆点和圆包含文字两种形式
* @tutorial https://uviewui.com/components/badge.html
*
* @property {Boolean} isDot 是否显示圆点 默认 false
* @property {String | Number} value 显示的内容
* @property {Boolean} show 是否显示 默认 true
* @property {String | Number} max 最大值超过最大值会显示 '{max}+' 默认999
* @property {String} type 主题类型error|warning|success|primary 默认 'error'
* @property {Boolean} showZero 当数值为 0 是否展示 Badge 默认 false
* @property {String} bgColor 背景颜色优先级比type高如设置type参数会失效
* @property {String} color 字体颜色 默认 '#ffffff'
* @property {String} shape 徽标形状circle-四角均为圆角horn-左下角为直角 默认 'circle'
* @property {String} numberType 设置数字的显示方式overflow|ellipsis|limit 默认 'overflow'
* @property {Array}} offset 设置badge的位置偏移格式为 [x, y]也即设置的为top和right的值absolute为true时有效
* @property {Boolean} inverted 是否反转背景和字体颜色默认 false
* @property {Boolean} absolute 是否绝对定位默认 false
* @property {Object} customStyle 定义需要用到的外部样式
* @example <u-badge :type="type" :count="count"></u-badge>
*/
export default {
name: 'u-badge',
mixins: [uni.$u.mpMixin, props, uni.$u.mixin],
computed: {
// badge
boxStyle() {
let style = {};
return style;
},
//
badgeStyle() {
const style = {}
if(this.color) {
style.color = this.color
}
if (this.bgColor && !this.inverted) {
style.backgroundColor = this.bgColor
}
if (this.absolute) {
style.position = 'absolute'
// offset
if(this.offset.length) {
// toprightoffsetrighttop
const top = this.offset[0]
const right = this.offset[1] || top
style.top = uni.$u.addUnit(top)
style.right = uni.$u.addUnit(right)
}
}
return style
},
showValue() {
switch (this.numberType) {
case "overflow":
return Number(this.value) > Number(this.max) ? this.max + "+" : this.value
break;
case "ellipsis":
return Number(this.value) > Number(this.max) ? "..." : this.value
break;
case "limit":
return Number(this.value) > 999 ? Number(this.value) >= 9999 ?
Math.floor(this.value / 1e4 * 100) / 100 + "w" : Math.floor(this.value /
1e3 * 100) / 100 + "k" : this.value
break;
default:
return Number(this.value)
}
},
}
}
</script>
<style lang="scss" scoped>
@import "../../libs/css/components.scss";
$u-badge-primary: $u-primary !default;
$u-badge-error: $u-error !default;
$u-badge-success: $u-success !default;
$u-badge-info: $u-info !default;
$u-badge-warning: $u-warning !default;
$u-badge-dot-radius: 100px !default;
$u-badge-dot-size: 8px !default;
$u-badge-dot-right: 4px !default;
$u-badge-dot-top: 0 !default;
$u-badge-text-font-size: 11px !default;
$u-badge-text-right: 10px !default;
$u-badge-text-padding: 2px 5px !default;
$u-badge-text-align: center !default;
$u-badge-text-color: #FFFFFF !default;
.u-badge {
border-top-right-radius: $u-badge-dot-radius;
border-top-left-radius: $u-badge-dot-radius;
border-bottom-left-radius: $u-badge-dot-radius;
border-bottom-right-radius: $u-badge-dot-radius;
@include flex;
line-height: $u-badge-text-font-size;
text-align: $u-badge-text-align;
font-size: $u-badge-text-font-size;
color: $u-badge-text-color;
&--dot {
height: $u-badge-dot-size;
width: $u-badge-dot-size;
}
&--inverted {
font-size: 13px;
}
&--not-dot {
padding: $u-badge-text-padding;
}
&--horn {
border-bottom-left-radius: 0;
}
&--primary {
background-color: $u-badge-primary;
}
&--primary--inverted {
color: $u-badge-primary;
}
&--error {
background-color: $u-badge-error;
}
&--error--inverted {
color: $u-badge-error;
}
&--success {
background-color: $u-badge-success;
}
&--success--inverted {
color: $u-badge-success;
}
&--info {
background-color: $u-badge-info;
}
&--info--inverted {
color: $u-badge-info;
}
&--warning {
background-color: $u-badge-warning;
}
&--warning--inverted {
color: $u-badge-warning;
}
}
</style>

View File

@ -0,0 +1,46 @@
$u-button-active-opacity:0.75 !default;
$u-button-loading-text-margin-left:4px !default;
$u-button-text-color: #FFFFFF !default;
$u-button-text-plain-error-color:$u-error !default;
$u-button-text-plain-warning-color:$u-warning !default;
$u-button-text-plain-success-color:$u-success !default;
$u-button-text-plain-info-color:$u-info !default;
$u-button-text-plain-primary-color:$u-primary !default;
.u-button {
&--active {
opacity: $u-button-active-opacity;
}
&--active--plain {
background-color: rgb(217, 217, 217);
}
&__loading-text {
margin-left:$u-button-loading-text-margin-left;
}
&__text,
&__loading-text {
color:$u-button-text-color;
}
&__text--plain--error {
color:$u-button-text-plain-error-color;
}
&__text--plain--warning {
color:$u-button-text-plain-warning-color;
}
&__text--plain--success{
color:$u-button-text-plain-success-color;
}
&__text--plain--info {
color:$u-button-text-plain-info-color;
}
&__text--plain--primary {
color:$u-button-text-plain-primary-color;
}
}

View File

@ -0,0 +1,161 @@
/*
* @Author : LQ
* @Description :
* @version : 1.0
* @Date : 2021-08-16 10:04:04
* @LastAuthor : LQ
* @lastTime : 2021-08-16 10:04:24
* @FilePath : /u-view2.0/uview-ui/components/u-button/props.js
*/
export default {
props: {
// 是否细边框
hairline: {
type: Boolean,
default: uni.$u.props.button.hairline
},
// 按钮的预置样式infoprimaryerrorwarningsuccess
type: {
type: String,
default: uni.$u.props.button.type
},
// 按钮尺寸largenormalsmallmini
size: {
type: String,
default: uni.$u.props.button.size
},
// 按钮形状circle两边为半圆square带圆角
shape: {
type: String,
default: uni.$u.props.button.shape
},
// 按钮是否镂空
plain: {
type: Boolean,
default: uni.$u.props.button.plain
},
// 是否禁止状态
disabled: {
type: Boolean,
default: uni.$u.props.button.disabled
},
// 是否加载中
loading: {
type: Boolean,
default: uni.$u.props.button.loading
},
// 加载中提示文字
loadingText: {
type: [String, Number],
default: uni.$u.props.button.loadingText
},
// 加载状态图标类型
loadingMode: {
type: String,
default: uni.$u.props.button.loadingMode
},
// 加载图标大小
loadingSize: {
type: [String, Number],
default: uni.$u.props.button.loadingSize
},
// 开放能力具体请看uniapp稳定关于button组件部分说明
// https://uniapp.dcloud.io/component/button
openType: {
type: String,
default: uni.$u.props.button.openType
},
// 用于 <form> 组件,点击分别会触发 <form> 组件的 submit/reset 事件
// 取值为submit提交表单reset重置表单
formType: {
type: String,
default: uni.$u.props.button.formType
},
// 打开 APP 时,向 APP 传递的参数open-type=launchApp时有效
// 只微信小程序、QQ小程序有效
appParameter: {
type: String,
default: uni.$u.props.button.appParameter
},
// 指定是否阻止本节点的祖先节点出现点击态,微信小程序有效
hoverStopPropagation: {
type: Boolean,
default: uni.$u.props.button.hoverStopPropagation
},
// 指定返回用户信息的语言zh_CN 简体中文zh_TW 繁体中文en 英文。只微信小程序有效
lang: {
type: String,
default: uni.$u.props.button.lang
},
// 会话来源open-type="contact"时有效。只微信小程序有效
sessionFrom: {
type: String,
default: uni.$u.props.button.sessionFrom
},
// 会话内消息卡片标题open-type="contact"时有效
// 默认当前标题,只微信小程序有效
sendMessageTitle: {
type: String,
default: uni.$u.props.button.sendMessageTitle
},
// 会话内消息卡片点击跳转小程序路径open-type="contact"时有效
// 默认当前分享路径,只微信小程序有效
sendMessagePath: {
type: String,
default: uni.$u.props.button.sendMessagePath
},
// 会话内消息卡片图片open-type="contact"时有效
// 默认当前页面截图,只微信小程序有效
sendMessageImg: {
type: String,
default: uni.$u.props.button.sendMessageImg
},
// 是否显示会话内消息卡片,设置此参数为 true用户进入客服会话会在右下角显示"可能要发送的小程序"提示,
// 用户点击后可以快速发送小程序消息open-type="contact"时有效
showMessageCard: {
type: Boolean,
default: uni.$u.props.button.showMessageCard
},
// 额外传参参数用于小程序的data-xxx属性通过target.dataset.name获取
dataName: {
type: String,
default: uni.$u.props.button.dataName
},
// 节流,一定时间内只能触发一次
throttleTime: {
type: [String, Number],
default: uni.$u.props.button.throttleTime
},
// 按住后多久出现点击态,单位毫秒
hoverStartTime: {
type: [String, Number],
default: uni.$u.props.button.hoverStartTime
},
// 手指松开后点击态保留时间,单位毫秒
hoverStayTime: {
type: [String, Number],
default: uni.$u.props.button.hoverStayTime
},
// 按钮文字之所以通过props传入是因为slot传入的话
// nvue中无法控制文字的样式
text: {
type: [String, Number],
default: uni.$u.props.button.text
},
// 按钮图标
icon: {
type: String,
default: uni.$u.props.button.icon
},
// 按钮图标
iconColor: {
type: String,
default: uni.$u.props.button.icon
},
// 按钮颜色支持传入linear-gradient渐变色
color: {
type: String,
default: uni.$u.props.button.color
}
}
}

View File

@ -0,0 +1,490 @@
<template>
<!-- #ifndef APP-NVUE -->
<button
:hover-start-time="Number(hoverStartTime)"
:hover-stay-time="Number(hoverStayTime)"
:form-type="formType"
:open-type="openType"
:app-parameter="appParameter"
:hover-stop-propagation="hoverStopPropagation"
:send-message-title="sendMessageTitle"
:send-message-path="sendMessagePath"
:lang="lang"
:data-name="dataName"
:session-from="sessionFrom"
:send-message-img="sendMessageImg"
:show-message-card="showMessageCard"
@getphonenumber="getphonenumber"
@getuserinfo="getuserinfo"
@error="error"
@opensetting="opensetting"
@launchapp="launchapp"
:hover-class="!disabled && !loading ? 'u-button--active' : ''"
class="u-button u-reset-button"
:style="[baseColor, $u.addStyle(customStyle)]"
@tap="clickHandler"
:class="bemClass"
>
<template v-if="loading">
<u-loading-icon
:mode="loadingMode"
:size="loadingSize * 1.15"
:color="loadingColor"
></u-loading-icon>
<text
class="u-button__loading-text"
:style="[{ fontSize: textSize + 'px' }]"
>{{ loadingText || text }}</text
>
</template>
<template v-else>
<u-icon
v-if="icon"
:name="icon"
:color="iconColorCom"
:size="textSize * 1.35"
:customStyle="{ marginRight: '2px' }"
></u-icon>
<slot>
<text
class="u-button__text"
:style="[{ fontSize: textSize + 'px' }]"
>{{ text }}</text
>
</slot>
</template>
</button>
<!-- #endif -->
<!-- #ifdef APP-NVUE -->
<view
:hover-start-time="Number(hoverStartTime)"
:hover-stay-time="Number(hoverStayTime)"
class="u-button"
:hover-class="
!disabled && !loading && !color && (plain || type === 'info')
? 'u-button--active--plain'
: !disabled && !loading && !plain
? 'u-button--active'
: ''
"
@tap="clickHandler"
:class="bemClass"
:style="[baseColor, $u.addStyle(customStyle)]"
>
<template v-if="loading">
<u-loading-icon
:mode="loadingMode"
:size="loadingSize * 1.15"
:color="loadingColor"
></u-loading-icon>
<text
class="u-button__loading-text"
:style="[nvueTextStyle]"
:class="[plain && `u-button__text--plain--${type}`]"
>{{ loadingText || text }}</text
>
</template>
<template v-else>
<u-icon
v-if="icon"
:name="icon"
:color="iconColorCom"
:size="textSize * 1.35"
></u-icon>
<text
class="u-button__text"
:style="[
{
marginLeft: icon ? '2px' : 0,
},
nvueTextStyle,
]"
:class="[plain && `u-button__text--plain--${type}`]"
>{{ text }}</text
>
</template>
</view>
<!-- #endif -->
</template>
<script>
import button from "../../libs/mixin/button.js";
import openType from "../../libs/mixin/openType.js";
import props from "./props.js";
/**
* button 按钮
* @description Button 按钮
* @tutorial https://www.uviewui.com/components/button.html
*
* @property {Boolean} hairline 是否显示按钮的细边框 (默认 true )
* @property {String} type 按钮的预置样式infoprimaryerrorwarningsuccess (默认 'info' )
* @property {String} size 按钮尺寸largenormalmini 默认 normal
* @property {String} shape 按钮形状circle两边为半圆square带圆角 默认 'square'
* @property {Boolean} plain 按钮是否镂空背景色透明 默认 false
* @property {Boolean} disabled 是否禁用 默认 false
* @property {Boolean} loading 按钮名称前是否带 loading 图标(App-nvue 平台 ios 上为雪花Android上为圆圈) 默认 false
* @property {String | Number} loadingText 加载中提示文字
* @property {String} loadingMode 加载状态图标类型 默认 'spinner'
* @property {String | Number} loadingSize 加载图标大小 默认 15
* @property {String} openType 开放能力具体请看uniapp稳定关于button组件部分说明
* @property {String} formType 用于 <form> 组件点击分别会触发 <form> 组件的 submit/reset 事件
* @property {String} appParameter 打开 APP APP 传递的参数open-type=launchApp时有效 只微信小程序QQ小程序有效
* @property {Boolean} hoverStopPropagation 指定是否阻止本节点的祖先节点出现点击态微信小程序有效默认 true
* @property {String} lang 指定返回用户信息的语言zh_CN 简体中文zh_TW 繁体中文en 英文默认 en
* @property {String} sessionFrom 会话来源openType="contact"时有效
* @property {String} sendMessageTitle 会话内消息卡片标题openType="contact"时有效
* @property {String} sendMessagePath 会话内消息卡片点击跳转小程序路径openType="contact"时有效
* @property {String} sendMessageImg 会话内消息卡片图片openType="contact"时有效
* @property {Boolean} showMessageCard 是否显示会话内消息卡片设置此参数为 true用户进入客服会话会在右下角显示"可能要发送的小程序"提示用户点击后可以快速发送小程序消息openType="contact"时有效默认false
* @property {String} dataName 额外传参参数用于小程序的data-xxx属性通过target.dataset.name获取
* @property {String | Number} throttleTime 节流一定时间内只能触发一次 默认 0 )
* @property {String | Number} hoverStartTime 按住后多久出现点击态单位毫秒 默认 0 )
* @property {String | Number} hoverStayTime 手指松开后点击态保留时间单位毫秒 默认 200 )
* @property {String | Number} text 按钮文字之所以通过props传入是因为slot传入的话nvue中无法控制文字的样式
* @property {String} icon 按钮图标
* @property {String} iconColor 按钮图标颜色
* @property {String} color 按钮颜色支持传入linear-gradient渐变色
* @property {Object} customStyle 定义需要用到的外部样式
*
* @event {Function} click 非禁止并且非加载中才能点击
* @event {Function} getphonenumber open-type="getPhoneNumber"时有效
* @event {Function} getuserinfo 用户点击该按钮时会返回获取到的用户信息从返回参数的detail中获取到的值同uni.getUserInfo
* @event {Function} error 当使用开放能力时发生错误的回调
* @event {Function} opensetting 在打开授权设置页并关闭后回调
* @event {Function} launchapp 打开 APP 成功的回调
* @example <u-button>月落</u-button>
*/
export default {
name: "u-button",
// #ifdef MP
mixins: [uni.$u.mpMixin, uni.$u.mixin, button, openType, props],
// #endif
// #ifndef MP
mixins: [uni.$u.mpMixin, uni.$u.mixin, props],
// #endif
data() {
return {};
},
computed: {
// bem
bemClass() {
// this.bemcomputedmixin
if (!this.color) {
return this.bem(
"button",
["type", "shape", "size"],
["disabled", "plain", "hairline"]
);
} else {
// nvuecolortypetype
return this.bem(
"button",
["shape", "size"],
["disabled", "plain", "hairline"]
);
}
},
loadingColor() {
if (this.plain) {
// colorcolor使type
return this.color
? this.color
: uni.$u.config.color[`u-${this.type}`];
}
if (this.type === "info") {
return "#c9c9c9";
}
return "rgb(200, 200, 200)";
},
iconColorCom() {
// colorcolor使
// u-iconcolor
if (this.iconColor) return this.iconColor;
if (this.plain) {
return this.color ? this.color : this.type;
} else {
return this.type === "info" ? "#000000" : "#ffffff";
}
},
baseColor() {
let style = {};
if (this.color) {
// color
style.color = this.plain ? this.color : "white";
if (!this.plain) {
// 使
style["background-color"] = this.color;
}
if (this.color.indexOf("gradient") !== -1) {
// backgroundImage
// weexborderWidth
// weex西
style.borderTopWidth = 0;
style.borderRightWidth = 0;
style.borderBottomWidth = 0;
style.borderLeftWidth = 0;
if (!this.plain) {
style.backgroundImage = this.color;
}
} else {
//
style.borderColor = this.color;
style.borderWidth = "1px";
style.borderStyle = "solid";
}
}
return style;
},
// nvuetext
nvueTextStyle() {
let style = {};
// color
if (this.type === "info") {
style.color = "#323233";
}
if (this.color) {
style.color = this.plain ? this.color : "white";
}
style.fontSize = this.textSize + "px";
return style;
},
//
textSize() {
let fontSize = 14,
{ size } = this;
if (size === "large") fontSize = 16;
if (size === "normal") fontSize = 14;
if (size === "small") fontSize = 12;
if (size === "mini") fontSize = 10;
return fontSize;
},
},
methods: {
clickHandler() {
//
if (!this.disabled && !this.loading) {
// this.throttle
uni.$u.throttle(() => {
this.$emit("click");
}, this.throttleTime);
}
},
// uniapp
getphonenumber(res) {
this.$emit("getphonenumber", res);
},
getuserinfo(res) {
this.$emit("getuserinfo", res);
},
error(res) {
this.$emit("error", res);
},
opensetting(res) {
this.$emit("opensetting", res);
},
launchapp(res) {
this.$emit("launchapp", res);
},
},
};
</script>
<style lang="scss" scoped>
@import "../../libs/css/components.scss";
/* #ifndef APP-NVUE */
@import "./vue.scss";
/* #endif */
/* #ifdef APP-NVUE */
@import "./nvue.scss";
/* #endif */
$u-button-u-button-height: 40px !default;
$u-button-text-font-size: 15px !default;
$u-button-loading-text-font-size: 15px !default;
$u-button-loading-text-margin-left: 4px !default;
$u-button-large-width: 100% !default;
$u-button-large-height: 50px !default;
$u-button-normal-padding: 0 12px !default;
$u-button-large-padding: 0 15px !default;
$u-button-normal-font-size: 14px !default;
$u-button-small-min-width: 60px !default;
$u-button-small-height: 30px !default;
$u-button-small-padding: 0px 8px !default;
$u-button-mini-padding: 0px 8px !default;
$u-button-small-font-size: 12px !default;
$u-button-mini-height: 22px !default;
$u-button-mini-font-size: 10px !default;
$u-button-mini-min-width: 50px !default;
$u-button-disabled-opacity: 0.5 !default;
$u-button-info-color: #323233 !default;
$u-button-info-background-color: #fff !default;
$u-button-info-border-color: #ebedf0 !default;
$u-button-info-border-width: 1px !default;
$u-button-info-border-style: solid !default;
$u-button-success-color: #fff !default;
$u-button-success-background-color: $u-success !default;
$u-button-success-border-color: $u-button-success-background-color !default;
$u-button-success-border-width: 1px !default;
$u-button-success-border-style: solid !default;
$u-button-primary-color: #fff !default;
$u-button-primary-background-color: $u-primary !default;
$u-button-primary-border-color: $u-button-primary-background-color !default;
$u-button-primary-border-width: 1px !default;
$u-button-primary-border-style: solid !default;
$u-button-error-color: #fff !default;
$u-button-error-background-color: $u-error !default;
$u-button-error-border-color: $u-button-error-background-color !default;
$u-button-error-border-width: 1px !default;
$u-button-error-border-style: solid !default;
$u-button-warning-color: #fff !default;
$u-button-warning-background-color: $u-warning !default;
$u-button-warning-border-color: $u-button-warning-background-color !default;
$u-button-warning-border-width: 1px !default;
$u-button-warning-border-style: solid !default;
$u-button-block-width: 100% !default;
$u-button-circle-border-top-right-radius: 100px !default;
$u-button-circle-border-top-left-radius: 100px !default;
$u-button-circle-border-bottom-left-radius: 100px !default;
$u-button-circle-border-bottom-right-radius: 100px !default;
$u-button-square-border-top-right-radius: 3px !default;
$u-button-square-border-top-left-radius: 3px !default;
$u-button-square-border-bottom-left-radius: 3px !default;
$u-button-square-border-bottom-right-radius: 3px !default;
$u-button-icon-min-width: 1em !default;
$u-button-plain-background-color: #fff !default;
$u-button-hairline-border-width: 0.5px !default;
.u-button {
height: $u-button-u-button-height;
position: relative;
align-items: center;
justify-content: center;
@include flex;
/* #ifndef APP-NVUE */
box-sizing: border-box;
/* #endif */
flex-direction: row;
&__text {
font-size: $u-button-text-font-size;
}
&__loading-text {
font-size: $u-button-loading-text-font-size;
margin-left: $u-button-loading-text-margin-left;
}
&--large {
/* #ifndef APP-NVUE */
width: $u-button-large-width;
/* #endif */
height: $u-button-large-height;
padding: $u-button-large-padding;
}
&--normal {
padding: $u-button-normal-padding;
font-size: $u-button-normal-font-size;
}
&--small {
/* #ifndef APP-NVUE */
min-width: $u-button-small-min-width;
/* #endif */
height: $u-button-small-height;
padding: $u-button-small-padding;
font-size: $u-button-small-font-size;
}
&--mini {
height: $u-button-mini-height;
font-size: $u-button-mini-font-size;
/* #ifndef APP-NVUE */
min-width: $u-button-mini-min-width;
/* #endif */
padding: $u-button-mini-padding;
}
&--disabled {
opacity: $u-button-disabled-opacity;
}
&--info {
color: $u-button-info-color;
background-color: $u-button-info-background-color;
border-color: $u-button-info-border-color;
border-width: $u-button-info-border-width;
border-style: $u-button-info-border-style;
}
&--success {
color: $u-button-success-color;
background-color: $u-button-success-background-color;
border-color: $u-button-success-border-color;
border-width: $u-button-success-border-width;
border-style: $u-button-success-border-style;
}
&--primary {
color: $u-button-primary-color;
background-color: $u-button-primary-background-color;
border-color: $u-button-primary-border-color;
border-width: $u-button-primary-border-width;
border-style: $u-button-primary-border-style;
}
&--error {
color: $u-button-error-color;
background-color: $u-button-error-background-color;
border-color: $u-button-error-border-color;
border-width: $u-button-error-border-width;
border-style: $u-button-error-border-style;
}
&--warning {
color: $u-button-warning-color;
background-color: $u-button-warning-background-color;
border-color: $u-button-warning-border-color;
border-width: $u-button-warning-border-width;
border-style: $u-button-warning-border-style;
}
&--block {
@include flex;
width: $u-button-block-width;
}
&--circle {
border-top-right-radius: $u-button-circle-border-top-right-radius;
border-top-left-radius: $u-button-circle-border-top-left-radius;
border-bottom-left-radius: $u-button-circle-border-bottom-left-radius;
border-bottom-right-radius: $u-button-circle-border-bottom-right-radius;
}
&--square {
border-bottom-left-radius: $u-button-square-border-top-right-radius;
border-bottom-right-radius: $u-button-square-border-top-left-radius;
border-top-left-radius: $u-button-square-border-bottom-left-radius;
border-top-right-radius: $u-button-square-border-bottom-right-radius;
}
&__icon {
/* #ifndef APP-NVUE */
min-width: $u-button-icon-min-width;
line-height: inherit !important;
vertical-align: top;
/* #endif */
}
&--plain {
background-color: $u-button-plain-background-color;
}
&--hairline {
border-width: $u-button-hairline-border-width !important;
}
}
</style>

View File

@ -0,0 +1,80 @@
// nvue下hover-class无效
$u-button-before-top:50% !default;
$u-button-before-left:50% !default;
$u-button-before-width:100% !default;
$u-button-before-height:100% !default;
$u-button-before-transform:translate(-50%, -50%) !default;
$u-button-before-opacity:0 !default;
$u-button-before-background-color:#000 !default;
$u-button-before-border-color:#000 !default;
$u-button-active-before-opacity:.15 !default;
$u-button-icon-margin-left:4px !default;
$u-button-plain-u-button-info-color:$u-info;
$u-button-plain-u-button-success-color:$u-success;
$u-button-plain-u-button-error-color:$u-error;
$u-button-plain-u-button-warning-color:$u-error;
.u-button {
width: 100%;
&__text {
white-space: nowrap;
line-height: 1;
}
&:before {
position: absolute;
top:$u-button-before-top;
left:$u-button-before-left;
width:$u-button-before-width;
height:$u-button-before-height;
border: inherit;
border-radius: inherit;
transform:$u-button-before-transform;
opacity:$u-button-before-opacity;
content: " ";
background-color:$u-button-before-background-color;
border-color:$u-button-before-border-color;
}
&--active {
&:before {
opacity: .15
}
}
&__icon+&__text:not(:empty),
&__loading-text {
margin-left:$u-button-icon-margin-left;
}
&--plain {
&.u-button--primary {
color: $u-primary;
}
}
&--plain {
&.u-button--info {
color:$u-button-plain-u-button-info-color;
}
}
&--plain {
&.u-button--success {
color:$u-button-plain-u-button-success-color;
}
}
&--plain {
&.u-button--error {
color:$u-button-plain-u-button-error-color;
}
}
&--plain {
&.u-button--warning {
color:$u-button-plain-u-button-warning-color;
}
}
}

View File

@ -0,0 +1,99 @@
<template>
<view class="u-calendar-header u-border-bottom">
<text
class="u-calendar-header__title"
v-if="showTitle"
>{{ title }}</text>
<text
class="u-calendar-header__subtitle"
v-if="showSubtitle"
>{{ subtitle }}</text>
<view class="u-calendar-header__weekdays">
<text class="u-calendar-header__weekdays__weekday"></text>
<text class="u-calendar-header__weekdays__weekday"></text>
<text class="u-calendar-header__weekdays__weekday"></text>
<text class="u-calendar-header__weekdays__weekday"></text>
<text class="u-calendar-header__weekdays__weekday"></text>
<text class="u-calendar-header__weekdays__weekday"></text>
<text class="u-calendar-header__weekdays__weekday"></text>
</view>
</view>
</template>
<script>
export default {
name: 'u-calendar-header',
mixins: [uni.$u.mpMixin, uni.$u.mixin],
props: {
//
title: {
type: String,
default: ''
},
//
subtitle: {
type: String,
default: ''
},
//
showTitle: {
type: Boolean,
default: true
},
//
showSubtitle: {
type: Boolean,
default: true
},
},
data() {
return {
}
},
methods: {
name() {
}
},
}
</script>
<style lang="scss" scoped>
@import "../../libs/css/components.scss";
.u-calendar-header {
padding-bottom: 4px;
&__title {
font-size: 16px;
color: $u-main-color;
text-align: center;
height: 42px;
line-height: 42px;
font-weight: bold;
}
&__subtitle {
font-size: 14px;
color: $u-main-color;
height: 40px;
text-align: center;
line-height: 40px;
font-weight: bold;
}
&__weekdays {
@include flex;
justify-content: space-between;
&__weekday {
font-size: 13px;
color: $u-main-color;
line-height: 30px;
flex: 1;
text-align: center;
}
}
}
</style>

View File

@ -0,0 +1,579 @@
<template>
<view class="u-calendar-month-wrapper" ref="u-calendar-month-wrapper">
<view v-for="(item, index) in months" :key="index" :class="[`u-calendar-month-${index}`]"
:ref="`u-calendar-month-${index}`" :id="`month-${index}`">
<text v-if="index !== 0" class="u-calendar-month__title">{{ item.year }}{{ item.month }}</text>
<view class="u-calendar-month__days">
<view v-if="showMark" class="u-calendar-month__days__month-mark-wrapper">
<text class="u-calendar-month__days__month-mark-wrapper__text">{{ item.month }}</text>
</view>
<view class="u-calendar-month__days__day" v-for="(item1, index1) in item.date" :key="index1"
:style="[dayStyle(index, index1, item1)]" @tap="clickHandler(index, index1, item1)"
:class="[item1.selected && 'u-calendar-month__days__day__select--selected']">
<view class="u-calendar-month__days__day__select" :style="[daySelectStyle(index, index1, item1)]">
<text class="u-calendar-month__days__day__select__info"
:class="[item1.disabled && 'u-calendar-month__days__day__select__info--disabled']"
:style="[textStyle(item1)]">{{ item1.day }}</text>
<text v-if="getBottomInfo(index, index1, item1)"
class="u-calendar-month__days__day__select__buttom-info"
:class="[item1.disabled && 'u-calendar-month__days__day__select__buttom-info--disabled']"
:style="[textStyle(item1)]">{{ getBottomInfo(index, index1, item1) }}</text>
<text v-if="item1.dot" class="u-calendar-month__days__day__select__dot"></text>
</view>
</view>
</view>
</view>
</view>
</template>
<script>
// #ifdef APP-NVUE
// nvue
const dom = uni.requireNativePlugin('dom')
// #endif
import dayjs from '../../libs/util/dayjs.js';
export default {
name: 'u-calendar-month',
mixins: [uni.$u.mpMixin, uni.$u.mixin],
props: {
//
showMark: {
type: Boolean,
default: true
},
//
color: {
type: String,
default: '#3c9cff'
},
//
months: {
type: Array,
default: () => []
},
//
mode: {
type: String,
default: 'single'
},
//
rowHeight: {
type: [String, Number],
default: 58
},
// mode=multiple
maxCount: {
type: [String, Number],
default: Infinity
},
// mode=range
startText: {
type: String,
default: '开始'
},
// mode=range
endText: {
type: String,
default: '结束'
},
// modemultiplerange
defaultDate: {
type: [Array, String, Date],
default: null
},
//
minDate: {
type: [String, Number],
default: 0
},
//
maxDate: {
type: [String, Number],
default: 0
},
// maxDate
maxMonth: {
type: [String, Number],
default: 2
},
//
readonly: {
type: Boolean,
default: uni.$u.props.calendar.readonly
},
// mode = range
maxRange: {
type: [Number, String],
default: Infinity
},
// mode = range
rangePrompt: {
type: String,
default: ''
},
// mode = range
showRangePrompt: {
type: Boolean,
default: true
},
// mode = range
allowSameDay: {
type: Boolean,
default: false
}
},
data() {
return {
//
width: 0,
// item
item: {},
selected: []
}
},
watch: {
selectedChange: {
immediate: true,
handler(n) {
this.setDefaultDate()
}
}
},
computed: {
//
selectedChange() {
return [this.minDate, this.maxDate, this.defaultDate]
},
dayStyle(index1, index2, item) {
return (index1, index2, item) => {
const style = {}
let week = item.week
// 2
const dayWidth = Number(parseFloat(this.width / 7).toFixed(3).slice(0, -1))
//
// #ifdef APP-NVUE
style.width = uni.$u.addUnit(dayWidth)
// #endif
style.height = uni.$u.addUnit(this.rowHeight)
if (index2 === 0) {
// 0item
week = (week === 0 ? 7 : week) - 1
style.marginLeft = uni.$u.addUnit(week * dayWidth)
}
if (this.mode === 'range') {
// DCloudiOSbug
style.paddingLeft = 0
style.paddingRight = 0
style.paddingBottom = 0
style.paddingTop = 0
}
return style
}
},
daySelectStyle() {
return (index1, index2, item) => {
let date = dayjs(item.date).format("YYYY-MM-DD"),
style = {}
// dateselected0使dateSameincludes
if (this.selected.some(item => this.dateSame(item, date))) {
style.backgroundColor = this.color
}
if (this.mode === 'single') {
if (date === this.selected[0]) {
// nvue
style.borderTopLeftRadius = '3px'
style.borderBottomLeftRadius = '3px'
style.borderTopRightRadius = '3px'
style.borderBottomRightRadius = '3px'
}
} else if (this.mode === 'range') {
if (this.selected.length >= 2) {
const len = this.selected.length - 1
//
if (this.dateSame(date, this.selected[0])) {
style.borderTopLeftRadius = '3px'
style.borderBottomLeftRadius = '3px'
}
//
if (this.dateSame(date, this.selected[len])) {
style.borderTopRightRadius = '3px'
style.borderBottomRightRadius = '3px'
}
//
if (dayjs(date).isAfter(dayjs(this.selected[0])) && dayjs(date).isBefore(dayjs(this
.selected[len]))) {
style.backgroundColor = uni.$u.colorGradient(this.color, '#ffffff', 100)[90]
// mark
style.opacity = 0.7
}
} else if (this.selected.length === 1) {
// DCloudiOSbug
// nvueiOSuni-appbug
style.borderTopLeftRadius = '3px'
style.borderBottomLeftRadius = '3px'
}
} else {
if (this.selected.some(item => this.dateSame(item, date))) {
style.borderTopLeftRadius = '3px'
style.borderBottomLeftRadius = '3px'
style.borderTopRightRadius = '3px'
style.borderBottomRightRadius = '3px'
}
}
return style
}
},
//
textStyle() {
return (item) => {
const date = dayjs(item.date).format("YYYY-MM-DD"),
style = {}
//
if (this.selected.some(item => this.dateSame(item, date))) {
style.color = '#ffffff'
}
if (this.mode === 'range') {
const len = this.selected.length - 1
//
if (dayjs(date).isAfter(dayjs(this.selected[0])) && dayjs(date).isBefore(dayjs(this
.selected[len]))) {
style.color = this.color
}
}
return style
}
},
//
getBottomInfo() {
return (index1, index2, item) => {
const date = dayjs(item.date).format("YYYY-MM-DD")
const bottomInfo = item.bottomInfo
// 0
if (this.mode === 'range' && this.selected.length > 0) {
if (this.selected.length === 1) {
//
if (this.dateSame(date, this.selected[0])) return this.startText
else return bottomInfo
} else {
const len = this.selected.length - 1
// 2
if (this.dateSame(date, this.selected[0]) && this.dateSame(date, this.selected[1]) &&
len === 1) {
// 2item
return `${this.startText}/${this.endText}`
} else if (this.dateSame(date, this.selected[0])) {
return this.startText
} else if (this.dateSame(date, this.selected[len])) {
return this.endText
} else {
return bottomInfo
}
}
} else {
return bottomInfo
}
}
}
},
mounted() {
this.init()
},
methods: {
init() {
//
this.$emit('monthSelected', this.selected)
this.$nextTick(() => {
//
// nvue$nextTick100%
uni.$u.sleep(10).then(() => {
this.getWrapperWidth()
this.getMonthRect()
})
})
},
//
dateSame(date1, date2) {
return dayjs(date1).isSame(dayjs(date2))
},
// nvuecssitem
getWrapperWidth() {
// #ifdef APP-NVUE
dom.getComponentRect(this.$refs['u-calendar-month-wrapper'], res => {
this.width = res.size.width
})
// #endif
// #ifndef APP-NVUE
this.$uGetRect('.u-calendar-month-wrapper').then(size => {
this.width = size.width
})
// #endif
},
getMonthRect() {
// scroll-view
const promiseAllArr = this.months.map((item, index) => this.getMonthRectByPromise(
`u-calendar-month-${index}`))
//
Promise.all(promiseAllArr).then(
sizes => {
let height = 1
const topArr = []
for (let i = 0; i < this.months.length; i++) {
// monthsscroll-view
topArr[i] = height
height += sizes[i].height
}
// this.months[i].top()monthtop使
this.$emit('updateMonthTop', topArr)
})
},
//
getMonthRectByPromise(el) {
// #ifndef APP-NVUE
// $uGetRectuViewhttps://www.uviewui.com/js/getRect.html
// this.$uGetRectuni.$u.getRect
return new Promise(resolve => {
this.$uGetRect(`.${el}`).then(size => {
resolve(size)
})
})
// #endif
// #ifdef APP-NVUE
// nvue使dom
// promise使then
return new Promise(resolve => {
dom.getComponentRect(this.$refs[el][0], res => {
resolve(res.size)
})
})
// #endif
},
//
clickHandler(index1, index2, item) {
if (this.readonly) {
return;
}
this.item = item
const date = dayjs(item.date).format("YYYY-MM-DD")
if (item.disabled) return
//
let selected = uni.$u.deepClone(this.selected)
if (this.mode === 'single') {
//
selected = [date]
} else if (this.mode === 'multiple') {
if (selected.some(item => this.dateSame(item, date))) {
//
const itemIndex = selected.findIndex(item => item === date)
selected.splice(itemIndex, 1)
} else {
//
if (selected.length < this.maxCount) selected.push(date)
}
} else {
//
if (selected.length === 0 || selected.length >= 2) {
// 02
selected = [date]
} else if (selected.length === 1) {
//
const existsDate = selected[0]
//
if (dayjs(date).isBefore(existsDate)) {
selected = [date]
} else if (dayjs(date).isAfter(existsDate)) {
//
if(dayjs(dayjs(date).subtract(this.maxRange, 'day')).isAfter(dayjs(selected[0])) && this.showRangePrompt) {
if(this.rangePrompt) {
uni.$u.toast(this.rangePrompt)
} else {
uni.$u.toast(`选择天数不能超过 ${this.maxRange}`)
}
return
}
//
selected.push(date)
const startDate = selected[0]
const endDate = selected[1]
const arr = []
let i = 0
do {
//
arr.push(dayjs(startDate).add(i, 'day').format("YYYY-MM-DD"))
i++
//
} while (dayjs(startDate).add(i, 'day').isBefore(dayjs(endDate)))
// computedarr
arr.push(endDate)
selected = arr
} else {
//
if (selected[0] === date && !this.allowSameDay) return
selected.push(date)
}
}
}
this.setSelected(selected)
},
//
setDefaultDate() {
if (!this.defaultDate) {
//
const selected = [dayjs().format("YYYY-MM-DD")]
return this.setSelected(selected, false)
}
let defaultDate = []
const minDate = this.minDate || dayjs().format("YYYY-MM-DD")
const maxDate = this.maxDate || dayjs(minDate).add(this.maxMonth - 1, 'month').format("YYYY-MM-DD")
if (this.mode === 'single') {
// Date
if (!uni.$u.test.array(this.defaultDate)) {
defaultDate = [dayjs(this.defaultDate).format("YYYY-MM-DD")]
} else {
defaultDate = [this.defaultDate[0]]
}
} else {
//
if (!uni.$u.test.array(this.defaultDate)) return
defaultDate = this.defaultDate
}
//
defaultDate = defaultDate.filter(item => {
return dayjs(item).isAfter(dayjs(minDate).subtract(1, 'day')) && dayjs(item).isBefore(dayjs(
maxDate).add(1, 'day'))
})
this.setSelected(defaultDate, false)
},
setSelected(selected, event = true) {
this.selected = selected
event && this.$emit('monthSelected', this.selected)
}
}
}
</script>
<style lang="scss" scoped>
@import "../../libs/css/components.scss";
.u-calendar-month-wrapper {
margin-top: 4px;
}
.u-calendar-month {
&__title {
font-size: 14px;
line-height: 42px;
height: 42px;
color: $u-main-color;
text-align: center;
font-weight: bold;
}
&__days {
position: relative;
@include flex;
flex-wrap: wrap;
&__month-mark-wrapper {
position: absolute;
top: 0;
bottom: 0;
left: 0;
right: 0;
@include flex;
justify-content: center;
align-items: center;
&__text {
font-size: 155px;
color: rgba(231, 232, 234, 0.83);
}
}
&__day {
@include flex;
padding: 2px;
/* #ifndef APP-NVUE */
// vue使cssjs
width: calc(100% / 7);
box-sizing: border-box;
/* #endif */
&__select {
flex: 1;
@include flex;
align-items: center;
justify-content: center;
position: relative;
&__dot {
width: 7px;
height: 7px;
border-radius: 100px;
background-color: $u-error;
position: absolute;
top: 12px;
right: 7px;
}
&__buttom-info {
color: $u-content-color;
text-align: center;
position: absolute;
bottom: 5px;
font-size: 10px;
text-align: center;
left: 0;
right: 0;
&--selected {
color: #ffffff;
}
&--disabled {
color: #cacbcd;
}
}
&__info {
text-align: center;
font-size: 16px;
&--selected {
color: #ffffff;
}
&--disabled {
color: #cacbcd;
}
}
&--selected {
background-color: $u-primary;
@include flex;
justify-content: center;
align-items: center;
flex: 1;
border-radius: 3px;
}
&--range-selected {
opacity: 0.3;
border-radius: 0;
}
&--range-start-selected {
border-top-right-radius: 0;
border-bottom-right-radius: 0;
}
&--range-end-selected {
border-top-left-radius: 0;
border-bottom-left-radius: 0;
}
}
}
}
}
</style>

View File

@ -0,0 +1,144 @@
export default {
props: {
// 日历顶部标题
title: {
type: String,
default: uni.$u.props.calendar.title
},
// 是否显示标题
showTitle: {
type: Boolean,
default: uni.$u.props.calendar.showTitle
},
// 是否显示副标题
showSubtitle: {
type: Boolean,
default: uni.$u.props.calendar.showSubtitle
},
// 日期类型选择single-选择单个日期multiple-可以选择多个日期range-选择日期范围
mode: {
type: String,
default: uni.$u.props.calendar.mode
},
// mode=range时第一个日期底部的提示文字
startText: {
type: String,
default: uni.$u.props.calendar.startText
},
// mode=range时最后一个日期底部的提示文字
endText: {
type: String,
default: uni.$u.props.calendar.endText
},
// 自定义列表
customList: {
type: Array,
default: uni.$u.props.calendar.customList
},
// 主题色,对底部按钮和选中日期有效
color: {
type: String,
default: uni.$u.props.calendar.color
},
// 最小的可选日期
minDate: {
type: [String, Number],
default: uni.$u.props.calendar.minDate
},
// 最大可选日期
maxDate: {
type: [String, Number],
default: uni.$u.props.calendar.maxDate
},
// 默认选中的日期mode为multiple或range是必须为数组格式
defaultDate: {
type: [Array, String, Date, null],
default: uni.$u.props.calendar.defaultDate
},
// mode=multiple时最多可选多少个日期
maxCount: {
type: [String, Number],
default: uni.$u.props.calendar.maxCount
},
// 日期行高
rowHeight: {
type: [String, Number],
default: uni.$u.props.calendar.rowHeight
},
// 日期格式化函数
formatter: {
type: [Function, null],
default: uni.$u.props.calendar.formatter
},
// 是否显示农历
showLunar: {
type: Boolean,
default: uni.$u.props.calendar.showLunar
},
// 是否显示月份背景色
showMark: {
type: Boolean,
default: uni.$u.props.calendar.showMark
},
// 确定按钮的文字
confirmText: {
type: String,
default: uni.$u.props.calendar.confirmText
},
// 确认按钮处于禁用状态时的文字
confirmDisabledText: {
type: String,
default: uni.$u.props.calendar.confirmDisabledText
},
// 是否显示日历弹窗
show: {
type: Boolean,
default: uni.$u.props.calendar.show
},
// 是否允许点击遮罩关闭日历
closeOnClickOverlay: {
type: Boolean,
default: uni.$u.props.calendar.closeOnClickOverlay
},
// 是否为只读状态,只读状态下禁止选择日期
readonly: {
type: Boolean,
default: uni.$u.props.calendar.readonly
},
// 是否展示确认按钮
showConfirm: {
type: Boolean,
default: uni.$u.props.calendar.showConfirm
},
// 日期区间最多可选天数默认无限制mode = range时有效
maxRange: {
type: [Number, String],
default: uni.$u.props.calendar.maxRange
},
// 范围选择超过最多可选天数时的提示文案mode = range时有效
rangePrompt: {
type: String,
default: uni.$u.props.calendar.rangePrompt
},
// 范围选择超过最多可选天数时是否展示提示文案mode = range时有效
showRangePrompt: {
type: Boolean,
default: uni.$u.props.calendar.showRangePrompt
},
// 是否允许日期范围的起止时间为同一天mode = range时有效
allowSameDay: {
type: Boolean,
default: uni.$u.props.calendar.allowSameDay
},
// 圆角值
round: {
type: [Boolean, String, Number],
default: uni.$u.props.calendar.round
},
// 最多展示月份数量
monthNum: {
type: [Number, String],
default: 3
}
}
}

Some files were not shown because too many files have changed in this diff Show More