初始代码

This commit is contained in:
wangmingwei
2026-04-21 16:55:00 +08:00
parent be9f1657b9
commit 35101db700
1335 changed files with 211213 additions and 0 deletions

11
.gitignore vendored Normal file
View File

@@ -0,0 +1,11 @@
unpackage/dist
unpackage/debug
unpackage/cache
unpackage/release
.hbuilderx/launch.json
pages/login/index1.vue
.vite/deps
node_modules/.vite
harmony-configs/entry
.idea

332
App.vue Normal file
View File

@@ -0,0 +1,332 @@
<script>
import chat from '@/libs/chat.js'
import {
getAppVersion
} from '@/api/common.js'
import {
getMessageDetail,
checkInfo,
} from '@/api/message.js'
import {
useLocale
} from '@/locale/useLocale';
import {
useChatStore
} from '@/store/modules/chat'
import {
useUserStore
} from '@/store/modules/user'
const chatStore = useChatStore()
export default {
data() {
return {
version: 0,
resVersion: 0,
modileSystem: 'android',
Apk: ''
}
},
onLaunch() {
// #ifndef APP-HARMONY || MP || H5
/* uniPush */
// uni.getPushClientId({
// success: (res) => {
// userStore.setCid(res.cid)
// this.handlePush()
// },
// fail(err) {}
// })
/* H5+ */
/* 获取设备信息 */
uni.getSystemInfo({
success(res) {
uni.setStorageSync('systemInfo', res.ua)
}
})
this.handlePush()
// this.getAppVersion()
// 开启消息通知弹窗
this.setPermissions()
// #endif
const token = uni.getStorageSync("token");
if (!token) return
chat.initSocket()
const userStore = useUserStore()
userStore.getCurrentUser().then(res => {
const {
initLocale
} = useLocale();
initLocale()
})
},
methods: {
setPermissions() {
if (plus.os.name == 'Android') { // 判断是Android
var main = plus.android.runtimeMainActivity();
var pkName = main.getPackageName();
var uid = main.getApplicationInfo().plusGetAttribute("uid");
var NotificationManagerCompat = plus.android.importClass(
"android.support.v4.app.NotificationManagerCompat");
//android.support.v4升级为androidx
if (NotificationManagerCompat == null) {
NotificationManagerCompat = plus.android.importClass(
"androidx.core.app.NotificationManagerCompat");
}
var areNotificationsEnabled = NotificationManagerCompat.from(main).areNotificationsEnabled();
// 未开通‘允许通知’权限,则弹窗提醒开通,并点击确认后,跳转到系统设置页面进行设置
if (!areNotificationsEnabled) {
uni.showModal({
title: '通知权限开启提醒',
content: '您还没有开启通知权限,无法接受到消息通知,请前往设置!',
showCancel: false,
confirmText: '去设置',
success: function(res) {
if (res.confirm) {
var Intent = plus.android.importClass('android.content.Intent');
var Build = plus.android.importClass("android.os.Build");
//android 8.0引导
if (Build.VERSION.SDK_INT >= 26) {
var intent = new Intent('android.settings.APP_NOTIFICATION_SETTINGS');
intent.putExtra('android.provider.extra.APP_PACKAGE', pkName);
} else if (Build.VERSION.SDK_INT >= 21) { //android 5.0-7.0
var intent = new Intent('android.settings.APP_NOTIFICATION_SETTINGS');
intent.putExtra("app_package", pkName);
intent.putExtra("app_uid", uid);
} else { //(<21)其他--跳转到该应用管理的详情页
intent.setAction(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
var uri = Uri.fromParts("package", mainActivity.getPackageName(),
null);
intent.setData(uri);
}
// 跳转到该应用的系统通知设置页
main.startActivity(intent);
}
}
});
}
} else if (plus.os.name == 'iOS') { // 判断是ISO
var isOn = undefined;
var types = 0;
var app = plus.ios.invoke('UIApplication', 'sharedApplication');
var settings = plus.ios.invoke(app, 'currentUserNotificationSettings');
if (settings) {
types = settings.plusGetAttribute('types');
plus.ios.deleteObject(settings);
} else {
types = plus.ios.invoke(app, 'enabledRemoteNotificationTypes');
}
plus.ios.deleteObject(app);
isOn = (0 != types);
if (isOn == false) {
uni.showModal({
title: '通知权限开启提醒',
content: '您还没有开启通知权限,无法接受到消息通知,请前往设置!',
showCancel: false,
confirmText: '去设置',
success: function(res) {
if (res.confirm) {
var app = plus.ios.invoke('UIApplication', 'sharedApplication');
var setting = plus.ios.invoke('NSURL', 'URLWithString:', 'app-settings:');
plus.ios.invoke(app, 'openURL:', setting);
plus.ios.deleteObject(setting);
plus.ios.deleteObject(app);
}
}
});
}
}
},
getAppVersion() {
getAppVersion().then(res => {
let data = res.data.sysVersion || ''
const matches = data.match(/(\d+\.\d+\.\d+)/);
if (matches && matches.length > 0) this.Apk =
`https://cdn.yunzhupaas.com/apk/Android-java-${matches[0]}.apk`
data.trim();
this.version = Number(data.replace(/[^0-9]/ig, ""))
this.$nextTick(() => {
this.onUpdate()
})
}).catch((err) => {})
},
onUpdate() {
plus.runtime.getProperty(plus.runtime.appid, (wgtinfo) => {
let resVersion = this.define.sysVersion;
resVersion.trim();
this.resVersion = Number(resVersion.replace(/[^0-9]/ig, ""))
if (this.version != this.resVersion) {
process.env.NODE_ENV === "production" ?
uni.setStorageSync('isUpdate', 1) : uni.removeStorageSync('isUpdate')
uni.showModal({ //提醒用户更新
title: "立即更新版本",
success: (res) => {
if (res.confirm) {
uni.removeStorageSync('isUpdate')
let system = plus.os.name;
if (system === 'Android') {
// let url = devLanguage ? javaApk : dotNetApk;
if (!this.Apk) return this.$u.toast('下载链接为空')
plus.runtime.openURL(this.Apk)
// uni.downloadFile({
// //下载地址
// url: url,
// success: data => {
// if (data.statusCode === 200) {
// plus.runtime.install(data
// .tempFilePath, {
// force: false
// },
// function() {
// plus.runtime
// .restart();
// });
// }
// }
// })
} else {
plus.runtime.launchApplication({
action: `itms-apps://itunes.apple.com/cn/app/id${'appleId自行配置'}`
}, function(e) {});
}
} else if (res.cancel) {
if (this.modileSystem == 'ios') {
plus.ios.import("UIApplication")
.sharedApplication()
.performSelector("exit")
} else if (this.modileSystem == 'android') {
plus.runtime.quit();
}
}
}
})
}
})
},
// 打开聊天页面
toIm(item) {
chatStore.reduceBadgeNum(0)
uni.navigateTo({
url: '/pages/message/im/index?name=' + item.realName + '/' + item.account + '&formUserId=' +
item.formUserId +
'&headIcon=' +
item
.headIcon
})
},
// 打开日程页面
toSchedule(id) {
getMessageDetail(id).then(res => {
chatStore.setMsgInfoNum()
let bodyText = res.data.bodyText ? JSON.parse(res.data.bodyText) : {};
if (bodyText.type == 3) return
let groupId = bodyText.groupId || ''
uni.navigateTo({
url: '/pages/workFlow/schedule/detail?groupId=' + groupId +
'&id=' + bodyText.id
});
})
},
// 打开流程页面
toFlow(id) {
getMessageDetail(id).then(res => {
chatStore.setMsgInfoNum()
let bodyText = res.data.bodyText ? JSON.parse(res.data.bodyText) : {};
if (res.data.flowType == 2) {
let url = '/pages/my/entrustAgent/index'
url = bodyText.type == 1 ? url + '?index=1' : url + '?index=2'
uni.navigateTo({
url: url
});
return
}
console.log(666, res.data);
let config = {
fullName: res.data.title,
id: bodyText.operatorId || res.data.id,
...bodyText
}
checkInfo(bodyText.operatorId || config.taskId, config.opType).then(res => {
config.opType = res.data.opType;
setTimeout(() => {
uni.navigateTo({
url: '/pages/workFlow/flowBefore/index?config=' +
this.yunzhupaas.base64.encode(JSON.stringify(config))
});
}, 300)
})
})
},
// 处理推送消息
handlePush() {
// #ifndef APP-HARMONY || MP || H5
/* H5+ */
plus.push.addEventListener(
'click',
msg => {
const messageType = msg.payload.messageType
// 公告跟系统消息
if (messageType == 1 || messageType == 3) {
uni.navigateTo({
url: '/pages/message/messageDetail/index?id=' + msg.payload.id
});
return
}
// 流程消息(包括委托)
if (messageType == 2) {
return this.toFlow(msg.payload.id)
}
// 日程消息
if (messageType == 4) {
return this.toSchedule(msg.payload.id)
}
// 聊天
if (messageType == 100) {
return this.toIm(msg.payload)
}
})
/* uniPush */
// uni.onPushMessage((res) => {
// // const pages = getCurrentPages();
// // const currentRoute = pages[pages.length - 1].$page.fullPath
// let payload = res.data.payload
// let text = JSON.parse(this.yunzhupaas.base64.decode(payload.text))
// let content = text.type == 1 ? '公告' : text.type == 2 ? '流程' : '聊天'
// let title = text.type == 3 ? text.name : text.title
// if (res.type === 'receive') {
// uni.createPushMessage({
// title,
// content: `你有一条${content}消息`,
// payload,
// icon: './static/logo.png',
// success: (res) => {},
// fail: (err) => {}
// })
// } else {
// if (text.type == 1) {
// uni.navigateTo({
// url: '/pages/message/messageDetail/index?id=' + text.id
// });
// } else if (text.type == 2) {
// this.toFlow(text)
// } else {
// this.toIm(text)
// }
// }
// })
// #endif
},
}
}
</script>
<style lang="scss">
/*每个页面公共css */
@import "@/uni_modules/vk-uview-ui/index.scss";
@import "@/assets/iconfont/ym/iconfont.css";
@import "@/assets/iconfont/custom/iconfont.css";
@import "@/assets/scss/common.scss";
@import "@/assets/scss/components.scss";
</style>

33
README.md Normal file
View File

@@ -0,0 +1,33 @@
#yunzhupaas-app-vue3
## 一 环境要求
### 1.1 开发环境
- 操作系统:`Windows 10/11``MacOS`
- `Node.js` v16.15.x(某些情况下可能需要安装 Python3)及以上版本;
- `HBuilder X` (最新版)
### 1.2 运行环境
`Nginx` 建议使用 `1.18.0` 及以上版本、兼容 `OpenResty``TongHttpServer` 6.0(国产信创)
## 二 关联项目
> 需要使用下表中的对应分支
| 项目 | 分支 | 说明 |
| ------------------------- | ------------- | ------------------------------------------|
| **后端**(任一后端服务) | | |
| yunzhupaas-java-boot | v5.2.x-stable | Java 单体项目源码 |
| yunzhupaas-java-cloud | v5.2.x-stable | Java 微服务项目源码 |
| yunzhupaas-dotnet | v5.2.x-stable | .NET 单体项目源码 |
| yunzhupaas-dotnet-cloud | v5.2.x-stable | .NET 微服务项目源码 |
## 三 使用说明
### 3.1 高德地图配置
打开 `/utils/define.ts` 配置文件,修改 `aMapWebKey`
打开 `manifest.json` 文件点击app模块配置修改高德地图相关配置信息。点击web配置修改高德地图相关配置信息。

92
api/apply/apply.js Normal file
View File

@@ -0,0 +1,92 @@
import request from '@/utils/request'
// 获取应用菜单
export function getMenuList(data) {
return request({
url: '/api/app/Menu',
method: 'get',
data,
options: {
load: false
}
})
}
// 获取常用 1-流程 2-应用
export function getUsualList() {
return request({
url: '/api/system/MenuData',
method: 'get',
options: {
load: false
}
})
}
//流程常用更多
export function getCommonFlowTree(id) {
return request({
url: `/api/workflow/template/CommonFlowTree`,
method: 'get'
})
}
// 获取常用流程
export function getFlowUsualList(data) {
return request({
url: '/api/workflow/template/Selector',
method: 'get',
data,
options: {
load: false
}
})
}
// 获取常用全部 1-流程 2-应用
export function getAppDataList(data) {
return request({
url: '/api/system/MenuData/getAppDataList',
data,
options: {
load: false
}
})
}
// 获取添加流程
export function setCommonFlow(id) {
return request({
url: `/api/workflow/template/SetCommonFlow/${id}`,
method: 'post'
})
}
export function addUsual(id) {
return request({
url: `/api/system/MenuData/${id}`,
method: 'post'
})
}
export function delUsual(id) {
return request({
url: `/api/system/MenuData/${id}`,
method: 'delete'
})
}
export function getFlowList(data) {
return request({
url: '/api/workflow/template/Selector',
data
})
}
export function getDataList(data) {
return request({
url: `/api/system/MenuData/getDataList`,
data
})
}
export function getChildList(id) {
return request({
url: `/api/app/Menu/getChildList/${id}`
})
}
export function getChildMenuList(data) {
return request({
url: '/api/app/Menu/getMenuList?keyword=' + data.keyword,
data
})
}

42
api/apply/order.js Normal file
View File

@@ -0,0 +1,42 @@
import request from '@/utils/request'
// 删除订单
export function Delete(id) {
return request({
url: `/api/extend/CrmOrder/${id}`,
method: 'DELETE'
})
}
// 获取订单列表
export function getOrderList(data, options) {
return request({
url: `/api/extend/CrmOrder`,
method: 'get',
data,
options
})
}
// 获取商品列表
export function getGoodsList(data) {
return request({
url: `/api/extend/CrmOrder/Goods`,
method: 'get',
data,
options: {
load: false
}
})
}
// 获取客户列表
export function getCustomerList(keyword) {
return request({
url: `/api/extend/CrmOrder/Customer`,
method: 'get',
data: {
keyword: keyword || ''
},
options: {
load: false
}
})
}

49
api/apply/reportLog.js Normal file
View File

@@ -0,0 +1,49 @@
import request from '@/utils/request'
//获取我发出的日志
export function getSendList(data, options) {
return request({
url: `/api/extend/WorkLog/Send`,
method: 'GET',
data,
options
})
}
//获取收到的日志
export function getReceiveList(data, options) {
return request({
url: `/api/extend/WorkLog/Receive`,
method: 'GET',
data,
options
})
}
//日志info
export function getLogInfo(id) {
return request({
url: `/api/extend/WorkLog/${id}`,
method: 'GET',
})
}
//日志保存
export function createLog(data) {
return request({
url: `/api/extend/WorkLog`,
method: 'POST',
data
})
}
//日志修改
export function updateLog(data) {
return request({
url: `/api/extend/WorkLog/${data.id}`,
method: 'PUT',
data
})
}
//日志删除
export function delLog(id) {
return request({
url: `/api/extend/WorkLog/${id}`,
method: 'DELETE'
})
}

80
api/apply/visualDev.js Normal file
View File

@@ -0,0 +1,80 @@
import request from '@/utils/request'
// 获取列表表单配置JSON
export function getConfigData(modelId, type) {
return request({
url: `/api/visualdev/OnlineDev/${modelId}/Config?type=${type}`,
method: 'GET'
})
}
// 获取数据列表
export function getModelList(modelId, data, options) {
return request({
url: `/api/visualdev/OnlineDev/${modelId}/List`,
method: 'POST',
data,
options: {
load: false
}
})
}
// 添加数据
export function createModel(modelId, data) {
return request({
url: `/api/visualdev/OnlineDev/${modelId}`,
method: 'POST',
data
})
}
// 修改数据
export function updateModel(modelId, data) {
return request({
url: `/api/visualdev/OnlineDev/${modelId}/${data.id}`,
method: 'PUT',
data
})
}
// 获取数据信息
export function getModelInfo(modelId, id) {
return request({
url: `/api/visualdev/OnlineDev/${modelId}/${id}`,
method: 'GET'
})
}
// 删除数据
export function deteleModel(data, id) {
return request({
url: `/api/visualdev/OnlineDev/batchDelete/${id}`,
method: 'POST',
data
})
}
// 表单外链
export function getConfig(id) {
return request({
url: `/api/visualdev/OnlineDev/${id}/Config`,
method: 'GET'
})
}
// 修改记录
export function getOnlineLog(modelId, id) {
return request({
url: `/api/visualdev/OnlineLog?modelId=${modelId}&dataId=${id}`,
method: 'GET'
})
}
//自定义按钮发起流程
export function launchFlow(data, id) {
return request({
url: `/api/visualdev/OnlineDev/${id}/actionLaunchFlow`,
method: 'POST',
data
})
}
// 获取关联表单数据详情
export function getDataChange(data, modelId) {
return request({
url: `/api/visualdev/OnlineDev/${modelId}/DataChange`,
method: 'post',
data
})
}

46
api/apply/webDesign.js Normal file
View File

@@ -0,0 +1,46 @@
import request from '@/utils/request'
// 获取列表表单配置JSON
export function getConfig(modelId, encryption) {
return request({
url: `/api/visualdev/ShortLink/${modelId}/Config?encryption=${encryption}`,
method: 'GET'
})
}
// 获取数据详情
export function getDataChange(modelId, id, encryption) {
return request({
url: `/api/visualdev/ShortLink/${modelId}/${id}/DataChange` + (encryption ? '?encryption=' +
encryption : ''),
method: 'GET'
})
}
export function createModel(modelId, data, encryption) {
return request({
url: `/api/visualdev/ShortLink/${modelId}?encryption=${encryption}`,
method: 'POST',
data
})
}
// 表单外链表单信息
export function getShortLink(id, encryption) {
return request({
url: `/api/visualdev/ShortLink/getConfig/${id}?encryption=${encryption}`,
method: 'GET'
})
}
//表单外链密码验证
export function checkPwd(data) {
return request({
url: `/api/visualdev/ShortLink/checkPwd`,
method: 'POST',
data
})
}
// 表单外链列表
export function listLink(id, data, encryption) {
return request({
url: `/api/visualdev/ShortLink/${id}/ListLink?encryption=${encryption}`,
method: 'POST',
data
})
}

687
api/common.js Normal file
View File

@@ -0,0 +1,687 @@
import request from '@/utils/request'
//app版本升级
export function versionUpgrade(appName) {
return request({
url: `/api/file/AppStartInfo/${appName}`,
})
}
export function getAppVersion() {
return request({
url: `/api/app/Version`
})
}
// 获取数据字典数据
export function getDictionaryDataAll() {
return request({
url: '/api/system/DictionaryData/All',
options: {
load: false
}
})
}
// 获取字典数据下拉框列表
export function getDictionaryDataSelector(dictionaryTypeId) {
return request({
url: `/api/system/DictionaryData/${dictionaryTypeId}/Data/Selector`,
options: {
load: false
}
})
}
// 获取关联表单数据详情
export function getRelationFormDetail(modelId, data) {
return request({
url: `/api/visualdev/OnlineDev/${modelId}/DataChange`,
method: 'post',
data
})
}
// 获取关联表单弹窗列表
export function getRelationSelect(id, data, options) {
return request({
url: `/api/visualdev/Base/${id}/FieldDataSelect`,
data,
options: {
load: false
}
})
}
// 获取弹窗选择远端接口数据
export function getPopSelect(id, data, options) {
return request({
url: `/api/system/DataInterface/${id}/Actions/List`,
method: 'POST',
data,
options: {
load: true
}
})
}
// 获取多条接口数据
export function getDataInterfaceDataInfoByIds(id, data) {
return request({
url: `/api/system/DataInterface/${id}/Actions/InfoByIds`,
method: 'POST',
data
})
}
// 获取组织/公司下拉框列表
export function getOrganizeSelector() {
return request({
url: '/api/permission/Organize/Selector/0',
options: {
load: false
}
})
}
// 获取部门下拉框列表(公司+部门)
export function getDepartmentSelector() {
return request({
url: '/api/permission/Organize/Department/Selector/0',
options: {
load: false
}
})
}
// 获取部门下拉框列表(公司+部门)
export function selectAsyncList(data, id) {
return request({
url: `/api/permission/Organize/Department/SelectAsyncList/${id}`,
options: {
load: false
},
data
})
}
// 获取部门下拉框列表(公司+部门)回写
export function selectedList(data) {
return request({
url: `/api/permission/Organize/SelectedList`,
method: 'POST',
options: {
load: false
},
data
})
}
// 获取岗位下拉列表(公司+部门+岗位)
export function getPositionSelector() {
return request({
url: '/api/permission/Position/Selector',
options: {
load: false
}
})
}
// 获取用户下拉框列表(公司+部门+用户)
export function getUserSelector() {
return request({
url: '/api/permission/Users/Selector',
options: {
load: false
}
})
}
// 通过部门id,岗位id,角色id,分组id,用户id获取用户列表(带分页)
export const getUsersByUserCondition = (data) => {
return request({
url: '/api/permission/Users/UserCondition',
method: 'post',
data
})
}
// 通过部门id获取部门树形
export const getOrgByOrganizeCondition = (data) => {
return request({
url: `/api/permission/Organize/OrganizeCondition`,
method: 'post',
data
})
}
// 通过部门id,岗位id获取岗位树形
export const getPositionByPositionCondition = (data) => {
return request({
url: `/api/permission/Position/PositionCondition`,
method: 'post',
data
})
}
// 获取用户下拉框列表(用户选择加载)
export function getUserSelectorNew(organizeId, keyword) {
return request({
url: `/api/permission/Users/ImUser/Selector/${organizeId}`,
method: 'POST',
data: {
keyword
},
options: {
load: false
}
})
}
// 获取用户基本信息
export const getUserInfoList = ids => {
return request({
url: '/api/permission/Users/getUserList',
method: 'post',
data: {
ids
}
})
}
// 获取我的下属
export const getSubordinates = (keyword) => {
return request({
url: '/api/permission/Users/getSubordinates',
method: 'post',
data: {
keyword
}
})
}
// 获取当前组织用户
export const getOrganization = (keyword) => {
return request({
url: '/api/permission/Users/getOrganization',
method: 'get',
data: {
keyword,
organizeId: '0'
}
})
}
//获取用户详情
export function getUesrDetail(id) {
return request({
url: '/api/app/User/' + id,
method: 'GET'
})
}
// 获取所有用户列表
export function getUserAll() {
return request({
url: '/api/permission/Users/All',
options: {
load: false
}
})
}
// 获取通讯录用户列表(分页)
export function getImUser(data, options) {
return request({
url: '/api/permission/Users/ImUser',
data,
options: {
load: false
}
})
}
// 获取接口数据
export function getDataInterfaceRes(id, data) {
return request({
url: `/api/system/DataInterface/${id}/Actions/Preview`,
method: 'post',
options: {
load: false
},
data: data || {}
})
}
// 用户登录
export function login(data) {
return request({
url: '/api/oauth/Login',
method: 'post',
data,
header: {
'Content-Type': 'application/x-www-form-urlencoded',
}
})
}
// 账号注销
export function accountCancel(token) {
return request({
url: '/api/oauth/logoutCurrentUser',
method: 'post',
token,
header: {
'Content-Type': 'application/x-www-form-urlencoded',
}
})
}
//获取验证码
export function clickSms(account) {
return request({
url: 'https://app.yunzhupaas.com/api/Saas/Tenant/SmsCode/' + account,
method: 'GET',
header: {
'Content-Type': 'application/x-www-form-urlencoded',
}
})
}
//验证码登录
export function loginSms(data) {
return request({
url: 'https://app.yunzhupaas.com/api/Saas/Tenant/LoginSms',
method: 'POST',
data,
header: {
'Content-Type': 'application/x-www-form-urlencoded',
}
})
}
// 退出登录
export function logout() {
return request({
url: '/api/oauth/Logout'
})
}
// 获取当前用户信息
export function getCurrentUser() {
return request({
url: '/api/oauth/CurrentUser?type=' + 'app',
options: {
load: false
}
})
}
// 修改密码信息发送
export function updatePasswordMessage() {
return request({
url: '/api/oauth/updatePasswordMessage',
method: 'POST',
data: {},
options: {
load: false
}
})
}
// 用户登录测试
export function login2(data) {
return request({
url: '/api/oauth',
method: 'GET',
data,
options: {
load: false
}
})
}
export function getBillNumber(enCode) {
return request({
url: `/api/system/BillRule/BillNumber/${enCode}`,
method: 'GET',
options: {
load: false
}
})
}
// 获取系统配置
export function getSystemConfig() {
return request({
url: '/api/system/SysConfig',
method: 'GET'
})
}
// 获取下载文件链接
export function getDownloadUrl(type, fileId) {
return request({
url: `/api/file/Download/${type}/${fileId}`,
method: 'GET'
})
}
// 修改当前用户密码
export function updatePassword(data) {
return request({
url: '/api/permission/Users/Current/Actions/ModifyPassword',
method: 'POST',
data
})
}
// 获取我的下属
export function getSubordinate(id) {
return request({
url: `/api/permission/Users/Current/Subordinate/${id ? id : '0'}`,
method: 'GET'
})
}
// 获取默认配置
export function getConfig(account) {
return request({
url: `/api/oauth/getConfig/${account}`,
method: 'get'
})
}
// 获取行政区划下拉框数据
export function getProvinceSelector(id) {
return request({
url: `/api/system/Area/${id}/Selector/0`,
method: 'GET'
})
}
// 获取行政区划下拉框数据
export function getProvinceSelectorInfoList(idsList) {
return request({
url: `/api/system/Area/GetAreaByIds`,
method: 'post',
data: {
idsList
}
})
}
// 设置主要组织、主要岗位
export function setMajor(data) {
return request({
url: `/api/permission/Users/Current/major`,
method: 'put',
data
})
}
// 获取当前用户所有组织
export function getUserOrganizes(data) {
return request({
url: `/api/permission/Users/Current/getUserOrganizes`,
method: 'GET',
data
})
}
// 获取当前用户所有岗位
export function getUserPositions(data) {
return request({
url: `/api/permission/Users/Current/getUserPositions`,
method: 'GET',
data
})
}
// 获取当前用户个人资料
export function UserSettingInfo() {
return request({
url: '/api/permission/Users/Current/BaseInfo',
method: 'GET'
})
}
// 更新当前用户个人资料
export function UpdateUser(data) {
return request({
url: '/api/permission/Users/Current/BaseInfo',
method: 'PUT',
data
})
}
// 更新当前用户头像
export function UpdateAvatar(name) {
return request({
url: `/api/permission/Users/Current/Avatar/${name}`,
method: 'PUT'
})
}
// 获取分组下拉框列表
export const getGroupSelector = () => {
return request({
url: '/api/permission/Group/Selector',
method: 'GET'
})
}
// 获取分组列表
export const getGroupCondition = (data) => {
return request({
url: '/api/permission/Group/GroupCondition',
method: 'POST',
data
})
}
// 获取角色下拉框列表
export const getRoleSelector = () => {
return request({
url: '/api/permission/Role/Selector',
method: 'GET',
options: {
load: false
}
})
}
// 获取角色下拉框列表
export const getRoleCondition = (data) => {
return request({
url: '/api/permission/Role/RoleCondition',
method: 'POST',
data
})
}
// app第三方登录
export const getCallback = (data) => {
return request({
url: `/api/oauth/socials/app/callback/${data.source}?uuid=` + data.uuid,
method: 'GET'
})
}
// 第三方登录
export function otherlogin(data, ticket) {
return request({
url: `/api/oauth/socials/render/${data}` + '?ticket=' + ticket,
method: 'get'
})
}
// 获取登陆配置
export function getLoginConfig() {
return request({
url: '/api/oauth/getLoginConfig',
})
}
//获取登录票据
export function getTicket() {
return request({
url: `/api/oauth/getTicket`,
method: 'GET',
})
}
// 轮询获取登陆状态
export function getTicketStatus(ticket) {
return request({
url: `/api/oauth/getTicketStatus/${ticket}`,
method: 'GET',
})
}
// 获取第三方列表
export const getSocialsUserList = () => {
return request({
url: '/api/permission/socials/login',
method: 'GET'
})
}
// 第三方登录回调列表后点击登录
export function socialsLogin(data) {
return request({
url: `/api/oauth/Login/socials`,
data,
header: {
'Content-Type': 'application/x-www-form-urlencoded'
},
})
}
// 获取签名列表
export const getSignImgList = () => {
return request({
url: '/api/permission/Users/Current/SignImg',
method: 'GET',
options: {
load: false
}
})
}
// 新增签名
export const createSignImg = (data) => {
return request({
url: '/api/permission/Users/Current/SignImg',
method: 'post',
data,
options: {
load: false
}
})
}
// 设置默认签名
export const setDefSignImg = (id) => {
return request({
url: `/api/permission/Users/Current/${id}/SignImg`,
method: 'put',
options: {
load: false
}
})
}
// 删除签名
export const delSignImg = (id) => {
return request({
url: `/api/permission/Users/Current/${id}/SignImg`,
method: 'delete',
options: {
load: false
}
})
}
// 获取选中组织、岗位、角色、用户基本信息
export const getSelectedList = ids => {
return request({
url: '/api/permission/Users/getSelectedList',
method: 'post',
data: {
ids
}
})
}
// 通过组织、岗位、角色、用户ids获取选中用户基本信息
export const getSelectedUserList = data => {
return request({
url: '/api/permission/Users/getSelectedUserList',
method: 'post',
data
})
}
// 委托选择用户
export const getReceiveUserList = data => {
return request({
url: '/api/permission/Users/ReceiveUserList',
method: 'get',
data
})
}
// 获取用户下拉框列表
export const getListByAuthorize = (organizeId, keyword) => {
return request({
url: `/api/permission/Users/GetListByAuthorize/${organizeId}`,
method: 'post',
data: {
keyword
}
})
}
// 获取默认当前值部门ID
export function getDefaultCurrentValueDepartmentId(data) {
return request({
url: `/api/permission/Organize/getDefaultCurrentValueDepartmentId`,
method: 'post',
data
})
}
// 获取默认当前值部门ID同步
export async function getDefaultCurrentValueDepartmentIdAsync(data) {
return new Promise(resolve => {
request({
url: `/api/permission/Organize/getDefaultCurrentValueDepartmentId`,
method: 'post',
data
}).then(ret => {
resolve(ret)
})
})
}
// 获取默认当前值用户ID
export function getDefaultCurrentValueUserId(data) {
return request({
url: `/api/permission/Users/getDefaultCurrentValueUserId`,
method: 'post',
data
})
}
// 获取默认当前值用户ID同步
export async function getDefaultCurrentValueUserIdAsync(data) {
return new Promise(resolve => {
request({
url: `/api/permission/Users/getDefaultCurrentValueUserId`,
method: 'post',
data
}).then(ret => {
resolve(ret)
})
})
}
// 查询附近数据
export function getAroundList(data) {
return request({
url: '/api/system/Location/around',
method: 'get',
data
})
}
//根据关键字查询附近数据
export function getTextList(data) {
return request({
url: '/api/system/Location/text',
method: 'get',
data
})
}
//逆地理编码
export function getAddress(data) {
return request({
url: '/api/system/Location/regeo',
method: 'get',
data
})
}
// 更改扫码凭证状态-已扫码
export function setCodeCertificateStatus(ticket, status) {
return request({
url: `/api/oauth/setCodeCertificateStatus/${ticket}/${status}`,
method: 'GET',
options: {
load: false
}
})
}
// 扫码确认登录
export function confirmLogin(ticket) {
return request({
url: `/api/oauth/confirmLogin/${ticket}`,
method: 'GET',
options: {
load: false
}
})
}
export function getLangJson(locale) {
const header = locale ? {
"Accept-Language": locale
} : {}
return request({
url: '/api/system/BaseLang/LangJson',
method: 'GET',
header
})
}

40
api/commonWords.js Normal file
View File

@@ -0,0 +1,40 @@
import request from '@/utils/request'
//获取常用语
export function getSelector() {
return request({
url: `/api/system/CommonWords/Selector?type=App`,
method: 'get'
})
}
// 获取常用语列表
export function commonWords(data) {
return request({
url: `/api/system/CommonWords`,
method: 'get',
data
})
}
// 审批常用语新建
export function Create(data) {
return request({
url: '/api/system/CommonWords',
method: 'post',
data
})
}
// 审批常用语编辑
export function Update(data) {
return request({
url: `/api/system/CommonWords/${data.id}`,
method: 'put',
data
})
}
// 删除审批常用语详情
export function Delete(id) {
return request({
url: `/api/system/CommonWords/${id}`,
method: 'DELETE'
})
}

44
api/home.js Normal file
View File

@@ -0,0 +1,44 @@
import request from '@/utils/request'
// 获取通知公告
export function getNotice(data) {
return request({
url: '/api/visualdev/Dashboard/Notice',
method: 'post',
data,
options: {
load: false
}
})
}
// 获取未读邮件
export function getEmail() {
return request({
url: '/api/visualdev/Dashboard/Email',
method: 'get',
options: {
load: false
}
})
}
// 获取待办事项
export function getFlowTodo(type) {
return request({
url: `/api/visualdev/Dashboard/FlowTodo?type=${type}`,
method: 'get',
options: {
load: false
}
})
}
// 获取我的待办事项
export function getMyFlowTodo() {
return request({
url: '/api/visualdev/Dashboard/MyFlowTodo',
method: 'get',
options: {
load: false
}
})
}

60
api/message.js Normal file
View File

@@ -0,0 +1,60 @@
import request from '@/utils/request'
// 获取IM对话列表
export function getIMReply() {
return request({
url: '/api/message/imreply',
options: {
load: true
}
})
}
//获取消息列表
export function getMessageList(data) {
return request({
url: '/api/message',
data,
options: {
load: false
}
})
}
//获取消息列表
export function getUnReadMsgNum(data) {
return request({
url: '/api/message/getUnReadMsgNum',
data,
options: {
load: false
}
})
}
// 全部已读
export function MessageAllRead(data) {
return request({
url: '/api/message/Actions/ReadAll',
method: 'POST',
data
})
}
//消息详情
export function getMessageDetail(id) {
return request({
url: `/api/message/ReadInfo/${id}`,
method: 'get'
})
}
// 判断是否有查看消息详情权限(消息通知用)
export function checkInfo(taskOperatorId, opType) {
return request({
url: `/api/workflow/operator/${taskOperatorId}/Info?opType=${opType}`,
method: 'get'
})
}
// 删除会话列表
export function relocation(id) {
return request({
url: `/api/message/imreply/relocation/${id}`,
method: 'delete'
})
}

73
api/portal/portal.js Normal file
View File

@@ -0,0 +1,73 @@
import request from '@/utils/request'
//门户列表
export function PortalList() {
return request({
url: `/api/visualdev/Portal/Selector?platform=App&type=1`,
method: 'get',
options: {
load: false
}
})
}
//更新门户
export function SetPortal(id) {
return request({
url: `/api/visualdev/Portal/${id}/Actions/SetDefault?platform=App`,
method: 'put',
options: {
load: false
}
})
}
//门户列表切换后列表
export function auth(id) {
return request({
url: `/api/visualdev/Portal/${id}/auth?platform=App`,
method: 'get',
options: {
load: false
}
})
}
//获取门户地图数据
export function geojson(code) {
return request({
url: `/api/system/atlas/geojson?code=${code}&hasChildren=true`,
method: 'get',
options: {
load: false
}
})
}
//获取省市区树
export function getAtlas() {
return request({
url: `/api/system/atlas`,
method: 'get',
options: {
load: false
}
})
}
// 获取发送配置列表列表
export const getMsgTemplate = data => {
return request({
url: '/api/message/SendMessageConfig/getSendConfigList',
method: 'GET',
data,
options: {
load: false
}
})
}
// 预览
export const getPreviewPortal = id => {
return request({
url: '/api/visualdev/Portal/' + id,
method: 'GET',
options: {
load: false
}
})
}

11
api/signature.js Normal file
View File

@@ -0,0 +1,11 @@
import request from '@/utils/request'
// 通过id获取签章下拉框列表
export function getListByIds(data) {
return request({
url: '/api/system/Signature/ListByIds',
method: 'post',
data
})
}

139
api/workFlow/document.js Normal file
View File

@@ -0,0 +1,139 @@
import request from '@/utils/request'
// 获取文档列表
export function getDocumentList(data) {
return request({
url: `/api/extend/Document?keyword=${data.keyword}&parentId=${data.parentId}`,
method: 'get'
})
}
// 文件下载
export function packDownload(data) {
return request({
url: `/api/extend/Document/PackDownload`,
method: 'POST',
data
})
}
// 文件重命名
export function resetFileName(data) {
return request({
url: `/api/extend/Document/${data.id}`,
method: 'PUT',
data
})
}
// 文件重命名详情
export function fileDetail(id) {
return request({
url: `/api/extend/Document/${id}`,
method: 'get'
})
}
// 新建文件夹
export function addFolder(data) {
return request({
url: `/api/extend/Document`,
method: 'POST',
data
})
}
// 文件删除
export function batchDelete(data) {
return request({
url: `/api/extend/Document/BatchDelete`,
method: 'POST',
data
})
}
// 文件回收站
export function trash(data) {
return request({
url: `/api/extend/Document/Trash`,
method: 'GET',
data
})
}
// 文件回收站删除
export function trashDelete(data) {
return request({
url: `/api/extend/Document/Trash`,
method: 'post',
data
})
}
// 文件还原
export function recovery(data) {
return request({
url: `/api/extend/Document/Trash/Actions/Recovery`,
method: 'POST',
data
})
}
// 文件树列表
export function folderTree(data) {
return request({
url: `/api/extend/Document/FolderTree`,
method: 'POST',
data
})
}
// 文件移动
export function folderMove(data) {
return request({
url: `/api/extend/Document/Actions/MoveTo/${data.id}`,
method: 'PUT',
data
})
}
// 文件共享列表
export function shareFolderList(data) {
return request({
url: `/api/extend/Document/Share`,
method: 'GET',
data
})
}
// 文件共享
export function shareFolder(data) {
return request({
url: `/api/extend/Document/Actions/Share`,
method: 'POST',
data
})
}
// 共享给我
export function shareTome(data) {
return request({
url: `/api/extend/Document/ShareTome`,
method: 'GET',
data
})
}
// 取消共享
export function cancelShare(data) {
return request({
url: `/api/extend/Document/Actions/CancelShare`,
method: 'POST',
data
})
}
// 获取共享人员
export function shareUser(id) {
return request({
url: `/api/extend/Document/ShareUser/${id}`,
method: 'GET'
})
}
// 更新共享人员
export function shareAdjustment(data) {
return request({
url: `/api/extend/Document/Actions/ShareAdjustment/${data.ids}`,
method: 'POST',
data
})
}

84
api/workFlow/entrust.js Normal file
View File

@@ -0,0 +1,84 @@
import request from '@/utils/request'
// 获取流程委托列表
export function FlowDelegateList(data) {
return request({
url: `/api/workflow/delegate`,
method: 'get',
data
})
}
// 获取流程委托信息
export function FlowDelegateInfo(id) {
return request({
url: `/api/workflow/delegate/${id}`,
method: 'get'
})
}
// 删除流程委托
export function DeleteDelagate(id) {
return request({
url: `/api/workflow/delegate/${id}`,
method: 'DELETE'
})
}
// 新建流程委托
export function Create(data) {
return request({
url: `/api/workflow/delegate`,
method: 'post',
data
})
}
// 更新流程委托
export function Update(data) {
return request({
url: `/api/workflow/delegate/${data.id}`,
method: 'PUT',
data
})
}
// 获取流程的所有委托人
export function getDelegateUser(id) {
return request({
url: `/api/workflow/delegate/UserList?templateId=${id}`,
method: 'get'
})
}
// 获取一个委托终止
export function entrustStop(id) {
return request({
url: `/api/workflow/delegate/Stop/${id}`,
method: 'put',
data: {}
})
}
// 获取用户下拉框列表
export const getListByAuthorize = (organizeId, keyword) => {
return request({
url: `/api/permission/Users/GetListByAuthorize/${organizeId}`,
method: 'post',
data: {
keyword
}
})
}
// 获取用户下拉框列表
export function getPrincipalDetails(id) {
return request({
url: `/api/workflow/delegate/Info/${id}`,
method: 'get'
})
}
// 接受委托
export function entrustHandle(id, data) {
return request({
url: `/api/workflow/delegate/Notarize/${id}?type=${data.type}`,
method: 'post',
data: {}
})
}

221
api/workFlow/flowBefore.js Normal file
View File

@@ -0,0 +1,221 @@
import request from '@/utils/request'
// 获取待我审批信息
export function FlowTask(id, data) {
return request({
url: `/api/workflow/task/${id}`,
method: 'get',
data,
options: {
load: true
}
})
}
// 流程记录
export function recordList(data) {
return request({
url: `/api/workflow/operator/RecordList`,
method: 'get',
data
})
}
// 获取流程任务
export function taskList(data) {
return request({
url: `/api/workflow/trigger/task/List`,
method: 'get',
data
})
}
//减签列表
export function AddSignUserIdList(data, id) {
return request({
url: `/api/workflow/operator/AddSignUserIdList/${id}`,
method: 'post',
data
})
}
//减签
export function ReduceApprover(data, id) {
return request({
url: `/api/workflow/operator/ReduceApprover/${id}`,
method: 'post',
data
})
}
// 流程签收
export function SignFor(data) {
return request({
url: `/api/workflow/operator/Sign`,
method: 'post',
data
})
}
// 退回
export function back(id) {
return request({
url: `/api/workflow/operator/SendBackNodeList/${id}`,
method: 'get'
})
}
// 确认退回
export function sendBack(data, id) {
return request({
url: `/api/workflow/operator/SendBack/${id}`,
method: 'post',
data
})
}
// 开始办理
export function Transact(data) {
return request({
url: `/api/workflow/operator/Transact`,
method: 'post',
data
})
}
// 待我审核审核
export function Audit(id, data) {
return request({
url: `/api/workflow/operator/Audit/${id}`,
method: 'post',
data,
options: {
load: true
}
})
}
// 待我审核退回
export function Reject(id, data) {
return request({
url: `/api/workflow/operator/Audit/${id}`,
method: 'post',
data
})
}
// 撤回审核
export function auditRecall(id, data) {
return request({
url: `/api/workflow/operator/Recall/${id}`,
method: 'post',
data
})
}
export function launchRecall(id, data) {
return request({
url: `/api/workflow/task/Recall/${id}`,
method: 'PUT',
data
})
}
//减签
export function addSignUserIdList(id, data) {
return request({
url: `/api/workflow/operator/AddSignUserIdList/${id}`,
method: 'POST',
data
})
}
// 驳回审核
export function cancel(id, data) {
return request({
url: `/api/workflow/Engine/FlowBefore/Cancel/${id}`,
method: 'post',
data
})
}
// 待我审核转审
export function Transfer(id, data) {
return request({
url: `/api/workflow/operator/Transfer/${id}`,
method: 'post',
data
})
}
// 审批汇总
export function getRecordList(id, data) {
return request({
url: `/api/workflow/Engine/FlowBefore/RecordList/${id}`,
method: 'get',
data
})
}
// 待我审核保存草稿
export function saveAudit(id, data) {
return request({
url: `/api/workflow/operator/SaveAudit/${id}`,
method: 'post',
data
})
}
export function saveAssist(id, data) {
return request({
url: `/api/workflow/operator/AssistSave/${id}`,
method: 'post',
data
})
}
// 判断是否有候选人
export function Candidates(id, data) {
return request({
url: `/api/workflow/operator/CandidateNode/${id}`,
method: 'post',
data
})
}
// 获取候选人列表(分页)
export function CandidateUser(id, data) {
return request({
url: `/api/workflow/operator/CandidateUser/${id}`,
method: 'post',
data
})
}
// 获取审批退回类型
export function RejectList(id) {
return request({
url: `/api/workflow/Engine/FlowBefore/RejectList/${id}`,
method: 'get'
})
}
//协办
export function Assist(id, data) {
return request({
url: `/api/workflow/operator/Assist/${id}`,
method: 'post',
data
})
}
// 加签
export function FreeApprover(id, data) {
return request({
url: `/api/workflow/operator/AddSign/${id}`,
method: 'post',
data
})
}
// 返回多个子流程信息
export function SubFlowInfo(id) {
return request({
url: `/api/workflow/Engine/FlowBefore/SubFlowInfo/${id}`,
method: 'get'
})
}
// 获取流程实例相关人员(分页)
export function getTaskUserList(taskId, data) {
return request({
url: `/api/workflow/task/TaskUserList/${taskId}`,
method: 'get',
data
})
}

120
api/workFlow/flowEngine.js Normal file
View File

@@ -0,0 +1,120 @@
import request from '@/utils/request'
// 获取流程引擎列表
export function FlowEngineList(data) {
return request({
url: `/api/workflow/Engine/flowTemplate`,
method: 'get',
data
})
}
// 获取流程引擎信息
export function FlowEngineInfo(id) {
return request({
url: `/api/workflow/Engine/flowTemplate/${id}`,
method: 'get'
})
}
//获取流程引擎分页
export function getFlowSelector(data) {
return request({
url: `/api/workflow/template/Selector`,
method: 'get',
data,
options: {
load: false
}
})
}
//表单预览
export function flowForm(id) {
return request({
url: `/api/flowForm/Form/${id}`,
method: 'get'
})
}
// 列表ListAll
export function FlowEngineListAll() {
return request({
url: `/api/workflow/Engine/flowTemplate/ListAll`,
method: 'get',
options: {
load: false
}
})
}
// 流程引擎下拉框
export function FlowEngineSelector(type) {
return request({
url: `/api/workflow/Engine/flowTemplate/Selector`,
method: 'get',
data: {
type
}
})
}
// 获取流程评论列表
export function getCommentList(data) {
return request({
url: `/api/workflow/comment`,
method: 'get',
data
})
}
// 新建流程评论
export function createComment(data) {
return request({
url: `/api/workflow/comment`,
method: 'post',
data
})
}
// 删除流程评论
export function delComment(id) {
return request({
url: `/api/workflow/comment/${id}`,
method: 'delete'
})
}
// 委托可选全部流程
export function FlowEngineAll(data) {
return request({
url: `/api/workflow/Engine/flowTemplate/getflowAll`,
method: 'get',
data
})
}
// 获取引擎id
export function getFlowIdByCode() {
return request({
url: `/api/extend/CrmOrder`,
method: 'get'
})
}
// 获取待办未读
export function getFlowTodoCount(data) {
return request({
url: `/api/visualdev/Dashboard/FlowTodoCount`,
method: 'post',
data
})
}
// 委托 通过list<flowId>获取流程引擎列表
export function getFlowEngineListByIds(data) {
return request({
url: `/api/workflow/template/GetFlowList`,
method: 'post',
data
})
}
// 获取流程版本Id和发起节点表单id(大流程id)
export function getFlowStartFormId(id) {
return request({
url: `/api/workflow/template/StartFormId/${id}`,
method: 'get',
})
}

View File

@@ -0,0 +1,16 @@
import request from '@/utils/request'
// 撤销
export function Revoke(id, data) {
return request({
url: `/api/workflow/task/Revoke/${id}`,
method: 'PUT',
data
})
}
// 发起催办
export function Press(id) {
return request({
url: `/api/workflow/task/Press/${id}`,
method: 'post'
})
}

65
api/workFlow/schedule.js Normal file
View File

@@ -0,0 +1,65 @@
import request from '@/utils/request'
// 获取日程安排列表
export function List(data) {
return request({
url: '/api/system/Schedule/AppList',
method: 'get',
data,
options: {
load: false
}
})
}
// 新建日程安排
export function ScheduleCreate(data) {
return request({
url: '/api/system/Schedule',
method: 'post',
data,
options: {
load: false
}
})
}
// 删除日程安排
export function ScheduleDelete(id, type) {
return request({
url: `/api/system/Schedule/${id}/${type}`,
method: 'DELETE',
options: {
load: false
}
})
}
// 获取日程安排信息
export function ScheduleInfo(id) {
return request({
url: `/api/system/Schedule/${id}`,
method: 'get',
options: {
load: false
}
})
}
// 更新日程安排
export function ScheduleUpdate(data, type) {
return request({
url: `/api/system/Schedule/${data.id}/${type}`,
method: 'PUT',
data,
options: {
load: false
}
})
}
//查看日程详情
export function ScheduleDetail(groupId, id) {
return request({
url: `/api/system/Schedule/detail?groupId=${groupId}&id=${id}`,
method: 'get',
options: {
load: false
}
})
}

49
api/workFlow/template.js Normal file
View File

@@ -0,0 +1,49 @@
import request from '@/utils/request'
// 获取发起
export function getFlowLaunchList(data) {
return request({
url: `/api/workflow/task`,
method: 'get',
data,
options: {
load: false
}
})
}
// 删除流程发起
export function delFlowLaunch(id) {
return request({
url: '/api/workflow/task/' + id,
method: 'delete',
});
}
// 获取待签
export function getOperatorList(data) {
return request({
url: `/api/workflow/operator/List/${data.category}`,
method: 'get',
data,
options: {
load: false
}
})
}
// 获取流程发起列表
// export function TreeList() {
// return request({
// url: `/api/workflow/template/TreeList`,
// method: 'get'
// })
// }
// 获取流程发起列表
// export function OperatorList() {
// return request({
// url: `api/workflow/operator/List/0`,
// method: 'get'
// })
// }

View File

@@ -0,0 +1,35 @@
import request from '@/utils/request'
// 新建表单
export function Create(data) {
return request({
url: `/api/workflow/task`,
method: 'post',
data,
options: {
load: true
}
})
}
// 修改表单
export function Update(data) {
return request({
url: `/api/workflow/task/${data.id}`,
method: 'put',
data
})
}
//通过表单id获取流程id
export function getFormById(id) {
return request({
url: `/api/flowForm/Form/getFormById/${id}`,
method: 'get'
})
}
//查看发起表单
export function getStartFormInfo(id) {
return request({
url: `/api/workflow/task/ViewStartForm/${id}`,
method: 'get'
})
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

1004
assets/scss/common.scss Normal file

File diff suppressed because it is too large Load Diff

187
assets/scss/components.scss Normal file
View File

@@ -0,0 +1,187 @@
.yunzhupaas-tree-select-popup {
height: 100%;
z-index: 9999 !important;
.yunzhupaas-tree-select-body {
height: 100%;
display: flex;
flex-direction: column;
.yunzhupaas-tree-select-title {
display: flex;
align-items: center;
height: 100rpx;
padding: 0 16rpx !important;
.backIcon {
font-size: 40rpx;
color: #000;
}
.title {
flex: 1;
text-align: center;
padding-right: 40rpx;
font-size: 32rpx;
}
}
.yunzhupaas-tree-select-search {
padding: 10px 12px;
}
.yunzhupaas-tree-selected {
width: 100%;
padding: 0 44rpx 0;
.yunzhupaas-tree-selected-head {
width: 100%;
height: 60rpx;
display: flex;
justify-content: space-between;
.clear-btn {
color: #2979ff;
}
}
.yunzhupaas-tree-selected-box {
width: 100%;
display: flex;
justify-content: center;
border-bottom: 1rpx solid #c0c4cc;
.select-list {
max-height: 150rpx;
padding-top: 10rpx;
justify-content: flex-start;
flex-wrap: wrap;
.u-selectTag {
margin-bottom: 10rpx;
margin-left: 10rpx;
}
}
.yunzhupaas-tree-selected-list{
display: flex;
justify-content: flex-start;
flex-wrap: wrap;
padding-top: 10rpx;
.u-selectTag {
width: 310rpx;
border: 1px solid #2194fa;
background-color: #e8f4fe;
line-height: 40rpx;
margin: 10rpx;
padding-left: 10rpx;
display: flex;
align-items: center;
border-radius: 8rpx;
&.u-selectTag-flow{
.yunzhupaas-tree-selected-content{
width: 100%;
margin-left: 0;
}
}
.yunzhupaas-tree-selected-content {
width: 74%;
margin-left: 10rpx;
.name-box{
color: #353535;
display: flex;
.name {
flex: 1;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.close {
width: 26px;
padding-right: 8rpx;
justify-content: flex-end;
color: #2194fa;
}
}
.organize {
color: #a0a1a1;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis
}
}
}
}
.user-select-list{
max-height: 240rpx;
display: flex;
justify-content: flex-start;
flex-wrap: wrap;
padding-top: 10rpx;
}
}
}
.yunzhupaas-tree-select-tree {
flex: 1;
overflow: auto;
.list-box{
height: 100%;
.list-item{
display: flex;
width: 100%;
padding: 0 10px;
box-sizing: border-box;
.radio-label{
display: flex;
width: 100%;
}
.list-item-content{
flex: 1;
}
}
}
}
}
}
.nodata {
height: 100%;
margin: auto;
align-items: center;
justify-content: center;
color: #909399;
.noDataIcon {
width: 300rpx;
height: 210rpx;
}
}
.yunzhupaas-date-range {
width: 100%;
display: flex;
.u-input__input {
text-align: center !important;
}
}
.yunzhupaas-bottom-actions,
.yunzhupaas-tree-select-actions {
background-color: #fff;
display: flex;
width: 100%;
height: 88rpx;
box-shadow: 0 -2rpx 8rpx #e1e5ec;
z-index: 999999;
flex-shrink: 0;
.buttom-btn {
width: 100%;
/* #ifndef MP */
height: 88rpx !important;
line-height: 88rpx !important;
border-radius: 0 !important;
&::after {
border: none !important;
}
/* #endif */
/* #ifdef MP */
.u-btn {
width: 100%;
height: 88rpx !important;
line-height: 88rpx !important;
border-radius: 0 !important;
&::after {
border: none !important;
}
}
/* #endif */
}
}

View File

@@ -0,0 +1,168 @@
<template>
<view class="commonTabs-v">
<view class="icon-ym u-tabs-box" v-if="list.length" :class="{'boxShadow':isBoxShadow}">
<view class="apply-tabs">
<u-tabs :list="list" v-model="tabCurrent" @change="change" :is-scroll="isScroll" :name="prop"
:height="height">
</u-tabs>
</view>
<view class="more-icon" :class="icon" @click="iconClick "></view>
</view>
<u-popup v-model="showPopup" mode="bottom" closeable close-icon-color="#666666">
<view class="classifyTitle">
全部分类
</view>
<scroll-view scroll-y="true" :style="{'height':scrollHeight+'rpx'}">
<view class="classify-scroll-view u-flex">
<view v-for="(item,index) in list" :key="index" @click="classifyItem(index)"
class="classify-item u-font-28 u-line-1">
{{item.fullName}}
</view>
</view>
</scroll-view>
</u-popup>
</view>
</template>
<script>
export default {
props: {
list: {
type: Array,
default: () => []
},
current: {
type: Number,
default: 0
},
scrollHeight: {
type: String,
default: '360'
},
prop: {
type: String,
default: 'fullName'
},
icon: {
type: String,
default: 'icon-ym icon-ym-app-more'
},
height: {
type: String,
default: '84'
},
type: {
type: String,
default: 'flow'
},
isBoxShadow: {
type: Boolean,
default: false
},
isScroll: {
type: Boolean,
default: true
}
},
data() {
return {
tabCurrent: 0,
showPopup: false,
categoryList: []
}
},
watch: {
current: {
handler(val) {
this.tabCurrent = val
},
immediate: true
}
},
methods: {
classifyItem(index) {
this.change(index)
},
iconClick() {
if (this.type != 'flow') return this.$emit('iconClick');
this.showPopup = true
},
change(e) {
this.tabCurrent = e;
this.showPopup = false;
this.$emit('change', e);
}
}
}
</script>
<style lang="scss">
.commonTabs-v {
.boxShadow {
box-shadow: 0 0 10rpx rgba(0, 0, 0, 0.1);
}
.u-tabs-box {
position: relative;
.apply-tabs {
width: 94%;
.u-tabs {
height: 2.75rem;
}
}
.more-icon {
position: absolute;
top: 0;
right: 0;
/* #ifdef MP */
height: 85rpx;
line-height: 85rpx;
/* #endif */
/* #ifndef MP */
height: 88rpx;
line-height: 88rpx;
/* #endif */
text-align: center;
padding: 0 16rpx;
background-color: #fff;
opacity: 0.9;
box-shadow: 0 0 20rpx rgba(0, 0, 0, 0.1);
}
}
.classifyTitle {
font-family: PingFang SC;
height: 110rpx;
width: 100%;
line-height: 110rpx;
padding-left: 20rpx;
padding-right: 20rpx;
font-size: 32rpx;
color: #333333;
font-weight: 500;
}
.classify-scroll-view {
padding-bottom: 70rpx;
padding: 0 20rpx 64rpx;
justify-content: flex-start;
flex-wrap: wrap;
.classify-item {
width: 22%;
text-align: center;
margin: 10rpx;
background-color: #EEF0F4;
border-radius: 8rpx;
background: rgba(238, 240, 244, 0.39);
color: #666666;
line-height: 58rpx;
padding: 0 20rpx;
}
}
}
</style>

View File

@@ -0,0 +1,53 @@
<template>
<view class="u-flex-col buttom-btn-left-inner" @click.stop="handleClick"
:class="btnType === 'reject' ? 'reject' : ''">
<u-icon v-if="customIcon" :name="iconName" :size="size" :custom-prefix="btnIcon"></u-icon>
<u-icon v-else :name="iconName" :size="size"></u-icon>
<text>{{btnText}}</text>
</view>
</template>
<script>
export default {
props: {
btnLoading: {
type: Boolean,
default: false
},
customIcon: {
type: Boolean,
default: false
},
btnText: {
type: String,
default: ''
},
btnIcon: {
type: String,
default: 'icon-ym icon-ym-add-cancel'
},
btnType: {
type: String,
default: 'cancel'
},
iconName: {
type: String,
default: 'icon-ym'
},
size: {
type: [Number, String],
default: 24
}
},
methods: {
handleClick() {
if (this.btnType === 'cancel') return this.yunzhupaas.goBack()
if (this.btnType === 'more') return this.$emit('handleBtn', this.btnLoading ? false : true)
if (this.btnType === 'save' || this.btnType === 'reject') return this.$emit('handleBtn')
}
}
}
</script>
<style>
</style>

View File

@@ -0,0 +1,314 @@
<template>
<u-popup class="yunzhupaas-select" :maskCloseAble="maskCloseAble" mode="bottom" v-model="showPopup"
:safeAreaInsetBottom="safeAreaInsetBottom" @close="close" :height="height" :mask-close-able="false">
<view class="u-select">
<view class="u-select__header" @touchmove.stop.prevent="">
<view class="u-select__header__cancel u-select__header__btn" :style="{ color: cancelColor }"
hover-class="u-hover-class" :hover-stay-time="150" @tap="close()"
style="width: 60rpx;text-align: center;">
<text v-if="cancelBtn">{{cancelText}}</text>
</view>
<view class="u-select__header__title" style="flex: 1;text-align: center;">
{{title}}
</view>
<view class="u-select__header__confirm u-select__header__btn" :style="{ color: confirmColor }"
style="width: 60rpx;text-align: center;" hover-class="u-hover-class" :hover-stay-time="150"
@touchmove.stop="" @tap.stop="handleConfirm()">
<text v-if="confirmBtn">{{confirmText}}</text>
</view>
</view>
<view class="search-box_sticky" v-if=" isFlow || filterable">
<view class="search-box">
<u-search :placeholder="$t('app.apply.pleaseKeyword')" height="72" :show-action="false"
bg-color="#f0f2f6" shape="square" v-model="searchValue">
</u-search>
</view>
</view>
<view class="u-select__body u-select__body__multiple">
<scroll-view :scroll-y="true" style="height: 100%">
<u-checkbox-group v-model="innerValue" v-if="multiple">
<u-checkbox v-model="item.checked" v-for="(item, index) in columnList" :key="index"
:name="item[valueName]">
{{item[labelName]}}
</u-checkbox>
</u-checkbox-group>
<u-radio-group wrap v-model="checkedValue" v-else>
<u-radio @change="radioGroupChange(item,i)" :name="item[valueName]"
v-for="(item,i) in columnList" :key="i">
{{item[labelName]}}
</u-radio>
</u-radio-group>
<view v-if="!columnList.length" class="notData-box u-flex-col">
<view class="u-flex-col notData-inner">
<image :src="icon" class="iconImg"></image>
</view>
<text class="notData-inner-text">{{$t('common.noData')}}</text>
</view>
</scroll-view>
</view>
</view>
</u-popup>
</template>
<script>
import resources from '@/libs/resources.js'
export default {
name: 'YunzhupaasMultSelect',
props: {
list: {
type: Array,
default: () => []
},
height: {
type: [Number, String],
default: ''
},
multiple: {
type: Boolean,
default: false
},
filterable: {
type: Boolean,
default: false
},
cancelBtn: {
type: Boolean,
default: true
},
confirmBtn: {
type: Boolean,
default: true
},
show: {
type: Boolean,
default: false
},
cancelColor: {
type: String,
default: '#606266'
},
confirmColor: {
type: String,
default: '#2979ff'
},
safeAreaInsetBottom: {
type: Boolean,
default: false
},
maskCloseAble: {
type: Boolean,
default: true
},
defaultValue: {
type: Array,
default: () => []
},
labelName: {
type: String,
default: 'fullName'
},
valueName: {
type: String,
default: 'id'
},
title: {
type: String,
default: ''
},
cancelText: {
type: String,
default: '取消'
},
confirmText: {
type: String,
default: '确认'
},
isFlow: {
type: Boolean,
default: false
}
},
data() {
return {
columnData: [],
innerValue: [],
lastSelectIndex: [],
showPopup: false,
checkedValue: '',
searchValue: '',
icon: resources.message.nodata,
}
},
watch: {
show: {
handler(val) {
this.showPopup = val
if (val) setTimeout(() => this.init(), 10);
},
immediate: true,
},
},
computed: {
columnList() {
return this.columnData.filter((o) => (o[this.labelName] && o[this.labelName].match(this.searchValue)))
}
},
methods: {
init() {
this.setColumnData();
this.setDefault();
},
setColumnData() {
this.columnData = this.list.map((o, i) => ({
...o,
checked: false
}))
},
// 获取默认选中的值
setDefault() {
this.searchValue = ''
this.checkedValue = ''
if (this.multiple) {
this.innerValue = this.defaultValue
outer: for (let i = 0; i < this.innerValue.length; i++) {
inner: for (let j = 0; j < this.columnData.length; j++) {
if (this.innerValue[i] === this.columnData[j][this.valueName]) {
this.columnData[j].checked = true
break inner
}
}
}
} else {
for (let j = 0; j < this.columnData.length; j++) {
if (this.defaultValue[0] === this.columnData[j][this.valueName]) {
this.checkedValue = this.columnData[j][this.valueName]
this.innerValue = this.columnData[j]
}
}
}
},
radioGroupChange(e) {
this.innerValue = [{
...e,
checked: true
}]
},
handleConfirm() {
if (this.multiple) {
let data = {
indexs: [],
list: [],
label: '',
value: uni.$u.deepClone(this.innerValue)
}
if (!this.isFlow) {
for (let i = 0; i < this.columnData.length; i++) {
const item = this.columnData[i]
if (this.columnData[i].checked) {
data.list.push(uni.$u.deepClone(item))
data.indexs.push(i)
if (!data.label) {
data.label += item[this.labelName]
} else {
data.label += ',' + item[this.labelName]
}
}
}
}
this.$emit('confirm', data);
} else {
if (this.isFlow && !this.innerValue.length) return this.$u.toast("请选择流程");
this.$emit('confirm', this.innerValue);
}
this.close()
},
close() {
this.$emit('close');
},
}
}
</script>
<style scoped lang="scss">
.notData-box {
width: 100%;
height: 100%;
justify-content: center;
align-items: center;
margin-top: -50px;
.notData-inner {
width: 286rpx;
height: 222rpx;
align-items: center;
.iconImg {
width: 100% !important;
height: 100% !important;
}
}
.notData-inner-text {
color: #909399;
}
}
.u-select {
&__header {
display: flex;
flex-direction: row;
align-items: center;
justify-content: space-between;
height: 40px;
padding: 0 20px;
position: relative;
::after {
content: "";
position: absolute;
border-bottom: 0.5px solid #eaeef1;
transform: scaleY(0.5);
bottom: 0;
right: 0;
left: 0;
}
}
&__body {
width: 100%;
height: 500rpx;
overflow: hidden;
background-color: #fff;
&__picker-view {
height: 100%;
box-sizing: border-box;
&__item {
display: flex;
align-items: center;
justify-content: center;
font-size: 32rpx;
padding: 0 8rpx;
}
}
.u-checkbox-group {
padding: 0 30rpx;
.u-checkbox {
height: 25px;
line-height: 25px;
width: 100% !important;
display: flex;
margin: 6rpx 0;
:deep(uni-text) {
flex: 1;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}
}
}
}
}
</style>

View File

@@ -0,0 +1,254 @@
<template>
<view class="swipe-item-v">
<view v-for="(item, index) in listData" :key="index" class="list-item" @click="onItemClick(item)"
:style="{'margin-bottom':marginB+'rpx'}">
<view class="swipe-container" :style="{'border-radius':borderR+'rpx'}">
<view class="content-wrapper" :style="{ transform: `translateX(${item.offsetX}px)` }"
@touchstart="!item.swipeAction && handleTouchStart($event, index)"
@touchmove="!item.swipeAction && handleTouchMove($event, index)"
@touchend="!item.swipeAction && handleTouchEnd(index)">
<!-- 使用插槽渲染自定义内容 -->
<slot :item="item" :index="index"></slot>
</view>
<view class="action-buttons" :style="{ width: `${actionWidth}px` }">
<view v-for="(btn, btnIndex) in buttonsData" :key="btnIndex" class="btn" :style="{
background: btn.style.backgroundColor,
opacity: (item.swipeAction) ? 0.5 : 1
}" @tap="!item.swipeAction && handleButtonClick(btn.value, item, index,btn)">
<text class="btn-text">{{ btn.text }}</text>
<text v-if="btn.icon" class="iconfont" :class="btn.icon"></text>
</view>
</view>
</view>
</view>
</view>
</template>
<script>
/*
列表数据
[{
id: 1,
title: '列表项 1',
offsetX: 0,
startX: 0,
startY: 0,
isHorizontal: false,
swipeAction: false
}]
滑动操作按钮数据
[{
text: '编辑',
icon: 'icon-edit',
value: 'edit',
style:{
backgroundColor: '#007aff' // 添加背景色配置
}
}]
*/
export default {
name: 'SwipeAction',
props: {
// 列表数据
list: {
type: Array,
default: () => []
},
// 按钮配置
buttons: {
type: Array,
default: () => []
},
// 唯一标识字段
rowKey: {
type: String,
default: 'id'
},
marginB: {
type: [String, Number],
default: '0'
},
borderR: {
type: [String, Number],
default: '0'
}
},
data() {
return {
listData: [], // 处理后的列表数据
buttonsData: [], // 处理后的按钮数据
currentOpenIndex: -1, // 当前打开的item索引
actionWidth: 0, // 操作按钮总宽度
buttonWidth: 160
}
},
watch: {
list: {
handler(newVal) {
// 为列表数据添加必要的属性
this.listData = newVal.map(item => ({
...item,
offsetX: 0,
startX: 0,
startY: 0,
isHorizontal: false
}));
},
immediate: true
},
buttons: {
handler(newVal) {
this.buttonsData = newVal;
this.calculateActionWidth();
},
immediate: true
}
},
methods: {
// 计算操作按钮总宽度
calculateActionWidth() {
this.actionWidth = this.buttonsData.length * this.buttonWidth / 2;
},
// 点击整行
onItemClick(item) {
this.$emit('click', item);
},
// 按钮点击事件
handleButtonClick(value, item, index, btn) {
this.$emit('action', {
value,
item,
index,
btn
});
// 操作完成后收起
this.closeSwipe(index);
},
// 关闭滑动
closeSwipe(index) {
if (index === undefined) {
// 关闭所有
this.listData.forEach(item => item.offsetX = 0);
this.currentOpenIndex = -1;
} else {
// 关闭指定项
this.listData[index].offsetX = 0;
this.currentOpenIndex = -1;
}
},
// 触摸开始
handleTouchStart(e, index) {
const item = this.listData[index];
item.startX = e.touches[0].clientX;
item.startY = e.touches[0].clientY;
item.isHorizontal = false;
// 关闭其他打开的项
if (this.currentOpenIndex !== -1 && this.currentOpenIndex !== index) {
this.closeSwipe(this.currentOpenIndex);
}
},
// 触摸移动
handleTouchMove(e, index) {
const item = this.listData[index];
const deltaX = e.touches[0].clientX - item.startX;
const deltaY = Math.abs(e.touches[0].clientY - item.startY);
if (!item.isHorizontal) {
if (deltaY > 5) return;
if (Math.abs(deltaX) > 5) item.isHorizontal = true;
}
if (item.isHorizontal) {
const validDeltaX = Math.min(0, deltaX);
const maxOffset = -this.actionWidth;
item.offsetX = Math.max(maxOffset, validDeltaX);
e.preventDefault();
}
},
// 触摸结束
handleTouchEnd(index) {
const item = this.listData[index];
const threshold = this.actionWidth * 0.3;
if (item.offsetX <= -threshold) {
item.offsetX = -this.actionWidth;
this.currentOpenIndex = index;
} else {
item.offsetX = 0;
this.currentOpenIndex = -1;
}
}
}
}
</script>
<style scoped lang="scss">
.swipe-item-v {
.list-item {
.swipe-container {
position: relative;
overflow: hidden;
background: #fff;
.content-wrapper {
position: relative;
z-index: 2;
background: inherit;
transition: transform 0.3s ease;
.item-content {
padding: 40rpx;
background: #fff;
}
}
.action-buttons {
position: absolute;
top: 0;
right: 0;
bottom: 0;
display: flex;
/* 增加宽度 */
z-index: 1;
.btn {
flex: 1;
display: flex;
align-items: center;
justify-content: center;
padding: 0 20rpx;
gap: 10rpx;
transition: opacity 0.3s ease;
&.disabled {
opacity: 0.5;
cursor: not-allowed;
}
.btn-text {
color: #fff;
font-size: 28rpx;
text-align: center;
word-break: break-all;
display: -webkit-box;
line-height: 1.3;
}
.iconfont {
color: #fff;
font-size: 32rpx;
}
}
}
}
}
}
</style>

View File

@@ -0,0 +1,304 @@
<template>
<view class="assistantMsg-v">
<view class="u-p-l-20 u-p-r-20 u-p-t-20" v-if="statusList.length">
<u-subsection :list="statusList" :current="subsectionIndex" active-color="#2979FF" inactive-color="#999999"
bg-color="#F2F3F7" font-size="24" :bold="false" @change="subsection"></u-subsection>
</view>
<view v-if="tabData.data?.length">
<view class="u-p-l-20 u-p-r-20 u-p-t-20 u-p-b-20" v-if="subsectionId == 1">
<text>{{tabData.data}}</text>
</view>
<view v-if="subsectionId != 1">
<view class="u-flex-col list-v">
<view class="u-flex item" v-for="(item,index) in tabData.data" :key="index">
<view v-if="subsectionId == 2" class="linkBox">
<!-- #ifndef APP-HARMONY -->
<u-link :href="item.urlAddress" under-line>{{item.fullName}}</u-link>
<!-- #endif -->
<!-- #ifdef APP-HARMONY -->
<text @click="jumpLink(item.urlAddress)" class="linkColor">{{item.fullName}}</text>
<!-- #endif -->
</view>
<view class="list-inner u-flex" v-if="subsectionId == 3">
<view class="u-flex list-inner-box" @click="downLoad(item)">
<view class="item-icon ">
<u-image :src="getRecordImg(item.uploaderUrl)" width="84" height="84" />
</view>
<view class="u-flex-col r-content ">
<view class="u-line-1 name">{{item.fileName}}</view>
<text>
{{item.fileDate ? $u.timeFormat(item.fileDate, 'yyyy-mm-dd hh:MM:ss'):''}}</text>
</view>
</view>
</view>
<view class="group-box-inner" v-if="subsectionId == 4">
<u-cell-group :border="false">
<u-cell-item :border-bottom="false" :title="item.interfaceName"
hover-class="cell-hover-class" @click="jump(item)"></u-cell-item>
</u-cell-group>
</view>
</view>
</view>
</view>
</view>
<view class="u-p-20" v-else>
<NoData paddingTop="0" backgroundColor="#fff" zIndex="9"></NoData>
</view>
</view>
</template>
<script>
import resources from "@/libs/resources.js";
import NoData from '@/components/noData'
const wordTypeList = ['doc', 'docx'];
const excelTypeList = ['xls', 'xlsx'];
const pptTypeList = ['ppt', 'pptx'];
const pdfTypeList = ['pdf'];
const zipTypeList = ['rar', 'zip', 'arj', 'z', '7z'];
const txtTypeList = ['txt', 'log'];
const codeTypeList = ['html', 'cs', 'xml'];
const imgTypeList = ['png', 'jpg', 'jpeg', 'bmp', 'gif'];
const videoTypeList = ['avi', 'wmv', 'mpg', 'mpeg', 'mov', 'rm', 'ram', 'swf', 'flv', 'mp4', 'mp3', 'wma', 'avi', 'rm',
'rmvb', 'flv', 'mpg', 'mkv'
];
import {
packDownload,
} from "@/api/workFlow/document";
export default {
components: {
NoData
},
props: {
auxiliaryInfo: {
type: Array,
default: () => []
},
formData: {
type: Object,
default: () => {}
}
},
data() {
return {
subsectionIndex: 0,
wordImg: resources.document.wordImg,
excelImg: resources.document.excelImg,
pptImg: resources.document.pptImg,
pdfImg: resources.document.pdfImg,
rarImg: resources.document.rarImg,
txtImg: resources.document.txtImg,
codeImg: resources.document.codeImg,
imageImg: resources.document.imageImg,
audioImg: resources.document.audioImg,
blankImg: resources.document.blankImg,
folderImg: resources.document.folderImg,
}
},
computed: {
baseURL() {
return this.define.baseURL
},
statusList() {
let list = this.auxiliaryInfo.filter(o => o && o.config && o.config.on);
list = list.map(o => ({
...o,
name: o.fullName
}))
return list
},
subsectionId() {
return this.statusList[this.subsectionIndex]?.id
},
tabData() {
const configKeyMap = {
1: 'content',
2: 'linkList',
3: 'fileList',
4: 'dataList'
};
const configKey = configKeyMap[this.subsectionId] || null;
if (configKey) {
return {
data: this.statusList[this.subsectionIndex].config[configKey] || (configKey === 'content' ? '' :
[]),
show: this.statusList[this.subsectionIndex].config.on
};
}
return {};
}
},
methods: {
jumpLink(url) {
if (!url.startsWith("https://")) return this.$u.toast('无效链接')
uni.navigateTo({
url: `/pages/workFlow/webView/index?data=${url}`
})
},
getRecordImg(ext) {
if (!ext) return this.folderImg;
const match = ext.match(/\.([^\.]+)$/);
if (match) ext = match[1]
if (wordTypeList.includes(ext)) return this.wordImg;
if (excelTypeList.includes(ext)) return this.excelImg;
if (pptTypeList.includes(ext)) return this.pptImg;
if (pdfTypeList.includes(ext)) return this.pdfImg;
if (zipTypeList.includes(ext)) return this.rarImg;
if (txtTypeList.includes(ext)) return this.txtImg;
if (codeTypeList.includes(ext)) return this.codeImg;
if (imgTypeList.includes(ext)) return this.imageImg;
if (videoTypeList.includes(ext)) return this.audioImg;
return this.blankImg;
},
subsection(e) {
this.subsectionIndex = e
},
jump(item) {
const templateJson = this.getParamList(item.templateJson)
let data = {
...item,
templateJson
}
setTimeout(() => {
uni.navigateTo({
url: "/pages/workFlow/assistantMsg/viewData?data=" + encodeURIComponent(JSON
.stringify(data))
})
}, 800)
},
getParamList(templateJson) {
if (!this.formData) return templateJson;
for (let i = 0; i < templateJson.length; i++) {
const e = templateJson[i];
const data = this.formData;
if (e.sourceType == 1) {
e.defaultValue = data[e.relationField] || data[e.relationField] == 0 || data[e.relationField] ==
false ? data[e.relationField] : '';
}
}
return templateJson;
},
downLoad(item) {
let data = {
ids: [item?.id]
}
packDownload(data).then(res => {
// #ifdef H5
const fileUrl = this.baseURL + res.data.url + '&name=' + encodeURI(res.data.name);
window.location.href = fileUrl;
// #endif
// #ifdef MP
this.previewFile(res.data)
// #endif
// #ifdef APP-PLUS
this.downloadFile(res.data.url);
// #endif
})
},
previewFile(item) {
let fileTypes = ['doc', 'xls', 'ppt', 'pdf', 'docx', 'xlsx', 'pptx']
let url = item.url
let fileType = url.split('.')[1]
if (fileTypes.includes(fileType)) {
uni.downloadFile({
url: this.baseURL + url,
success: (res) => {
let filePath = res.tempFilePath;
uni.openDocument({
filePath: encodeURI(filePath),
showMenu: true,
fileType: fileType,
success: (res) => {
console.log('打开文档成功');
},
fail(err) {
console.log('小程序', err);
}
});
}
});
} else {
this.$u.toast(
'该文件类型无法打开'
)
}
},
downloadFile(url) {
uni.downloadFile({
url: this.baseURL + url,
success: res => {
if (res.statusCode === 200) {
uni.saveFile({
tempFilePath: res.tempFilePath,
success: red => {
uni.showToast({
icon: 'none',
mask: true,
title: '文件已保存:' + red.savedFilePath, //保存路径
duration: 3000,
});
setTimeout(() => {
uni.openDocument({
filePath: red.savedFilePath,
success: ress => {},
fail(err) {}
});
}, 500)
}
});
}
}
});
}
}
}
</script>
<style lang="scss">
.list-v {
.item {
min-height: 80rpx;
width: 100%;
border-bottom: 1rpx solid #d7d7d7;
padding: 20rpx;
.linkBox {
.linkColor {
color: #007BFF;
}
}
.list-inner {
width: 100%;
.list-inner-box {
width: 100%;
.item-icon {
background-color: #FFFFFF;
border-radius: 8rpx;
}
.r-content {
max-width: 86%;
margin-left: 14rpx;
.name {
text-align: left;
}
}
}
}
.group-box-inner {
width: 100%;
::v-deep {
.u-cell {
padding: 0;
}
}
}
}
}
</style>

View File

@@ -0,0 +1,490 @@
<template>
<view>
<u-time-line>
<u-time-line-item nodeTop="2" class="u-p-b-20" v-for="item,index in list" :key="index">
<template v-slot:node>
<view class="u-node" :style="{ background: getTimeLineTagColor(item.type) }"></view>
</template>
<template v-slot:content>
<view class="u-font-24 content">
<view class="start" v-if="item.type == '0'">
<view class="u-m-b-20 u-p-l-8 log-title u-flex">
<text>创建</text>
<text>{{item.creatorTime ? $u.timeFormat(item.creatorTime, 'yyyy-mm-dd hh:MM:ss'):''}}</text>
</view>
<view class="u-flex avatar-box" style="background-color: #F5F5F5;">
<u-avatar :src="baseURL + item.headIcon" size="mini" mode="circle"
class="avatar"></u-avatar>
<text class="u-m-l-8">{{item.creatorUserName}}</text>
</view>
</view>
<view class="avatar-block" v-else>
<view class="u-m-b-20 u-p-l-8 u-flex log-title">
<text>编辑</text>
<text>{{item.creatorTime ? $u.timeFormat(item.creatorTime, 'yyyy-mm-dd hh:MM:ss'):''}}</text>
</view>
<view class="u-flex avatar-box ">
<view class="u-flex">
<u-avatar :src="baseURL + item.headIcon" size="mini" mode="circle"
class="avatar"></u-avatar>
<text class="u-m-l-8">{{item.creatorUserName}}</text>
</view>
<view>
<text class="u-m-l-8">{{``}}</text>
<text class="u-m-l-8" style="color: red;">{{item.dataLog.length}}</text>
<text class="u-m-l-8">处更改</text>
</view>
</view>
<view class="dataLog-child">
<view class="dataLog-item" v-for="child,i in item.dataLog" :key="i">
<!-- 子表 -->
<view class="child-line" v-if="child.yunzhupaasKey === 'table'">
<view class="field-child">
<text class="table-name">{{child.fieldName}}</text>
<view class="u-flex table-detail">
<text>已修改</text>
<view class="u-m-l-20 approver-list-r u-flex" @click="openChild(child)">
<view class="txt">详情</view>
<text class="icon-ym icon-ym-right"></text>
</view>
</view>
</view>
</view>
<!-- 主表 -->
<view class="ordinary-field" v-else>
<view class="u-m-b-10 left">{{child.fieldName}}</view>
<view class="right">
<view class="val" v-if="child.nameModified">
<text style="color: #efbd47;">已修改</text>
</view>
<view class="val" v-else>
<template v-if="child.yunzhupaasKey === 'sign'">
<view v-if="child.oldData !== child.newData">
<text v-if="child.oldData" class="u-m-r-8 txt line-through"
@click="previewImage(child.oldData,child.yunzhupaasKey)">
旧签名
</text>
<text v-if="child.newData">
<text>修改为</text>
<text class="u-m-l-8 txt"
@click="previewImage(child.newData,child.yunzhupaasKey)">
新签名
</text>
</text>
</view>
<text v-if="child.oldData === child.newData"
@click="previewImage(child.oldData,child.yunzhupaasKey)">签名</text>
</template>
<template v-else-if="child.yunzhupaasKey === 'signature'">
<view v-if="child.oldData !== child.newData">
<text v-if="child.oldData" class="u-m-r-8 txt line-through"
@click="previewImage(child.oldData)">
旧签章
</text>
<text v-if="child.newData">
<text>修改为</text>
<text class="u-m-l-8 txt"
@click="previewImage(child.newData)">
新签章
</text>
</text>
</view>
<text v-if="child.oldData === child.newData"
@click="previewImage(child.oldData)">签章</text>
</template>
<template v-else>
<text v-if="child.oldData !== child.newData">
<text class="line-through">{{child.oldData}}</text>
<text class="u-m-l-16 u-m-r-16"
v-if="!child.oldData || child.newData ">修改为</text>
<text>{{child.newData}}</text>
</text>
<text v-if="child.oldData === child.newData">未修改</text>
</template>
</view>
</view>
</view>
</view>
</view>
</view>
</view>
</template>
</u-time-line-item>
</u-time-line>
</view>
<uni-popup ref="flowStepPopup" background-color="#fff" border-radius="8rpx 8rpx 0 0" :is-mask-click="false">
<view class="timeLine-popup-content u-flex-col">
<view class="u-flex head-title notice-warp">
<text class="text">修改详情</text>
<text class="text icon-ym icon-ym-fail" @click="popupClose"></text>
</view>
<view class="table-content">
<view class="table-content-inner" v-for="(item,index) in chidData">
<view class="table-content-title">
{{item.yunzhupaas_type == '0' ? '新增' : item.yunzhupaas_type == '2' ? '删除' : '编辑'}}
</view>
<view class="table-field u-flex-col">
<view class="u-flex table-field-item" v-for="(field,i) in item.chidField" :key="i"
:style="{backgroundColor:item.yunzhupaas_type == '0'?'#defee9':item.yunzhupaas_type == '2'?'#ffd2d2':''}">
<view class="label">{{field.label}}</view>
<!-- 显示已修改未修改 -->
<view class="val" v-if="field.nameModified">
<text v-if="field.oldData !== field.newData" style="color: #efbd47;"
:class="item.yunzhupaas_type == '2' ? 'line-through' : ''">已修改</text>
<text v-if="field.oldData === field.newData"
:class="item.yunzhupaas_type == '2' ? 'line-through' : ''">{{item.yunzhupaas_type == 0 ? '' : '未修改'}}</text>
</view>
<view class="val" v-else>
<!-- 签名电子签章 -->
<template v-if="field.yunzhupaasKey === 'sign'">
<view v-if="field.oldData !== field.newData" class="val">
<text v-if="field.oldData" class="u-m-r-8 txt"
:class="item.yunzhupaas_type == '2' || item.yunzhupaas_type == '1' ? 'line-through' : ''"
@click="previewImage(field.oldData,field.yunzhupaasKey)">
旧签名
</text>
<template class="" v-if="item.yunzhupaas_type != 2">
<text v-if="field.newData && field.oldData">修改为</text>
<text class="u-m-l-8 txt"
@click="previewImage(field.newData,field.yunzhupaasKey)">
新签名
</text>
</template>
</view>
<text @click="previewImage(field.oldData,field.yunzhupaasKey)" class="txt"
v-if="field.oldData === field.newData">{{item.yunzhupaas_type == 0 ||(!field.oldData && !field.newData)? '' : '签名'}}</text>
</template>
<template v-else-if="field.yunzhupaasKey === 'signature'">
<view v-if="field.oldData !== field.newData" class="val">
<text v-if="field.oldData" class="u-m-r-8 txt txt-left"
:class="item.yunzhupaas_type == '2' || item.yunzhupaas_type == '1' ? 'line-through' : ''"
@click="previewImage(field.oldData)">
旧签章
</text>
<template class="" v-if="item.yunzhupaas_type != 2">
<text v-if="field.newData && field.oldData">修改为</text>
<text class="u-m-l-8 txt text-right" @click="previewImage(field.newData)">
新签章
</text>
</template>
</view>
<text @click="previewImage(field.oldData)" class="txt"
v-if="field.oldData === field.newData">{{item.yunzhupaas_type == 0 ||(!field.oldData && !field.newData) ? '' : '签章'}}</text>
</template>
<!-- 签名电子签章end -->
<template v-else>
<view class="u-flex modify-box" v-if="field.oldData !== field.newData ">
<view class="modify modify-left"
:style="{'text-align':item.yunzhupaas_type == '2'? 'end' : 'center'}"
:class=" item.yunzhupaas_type == '2' || item.yunzhupaas_type == '1' ? 'line-through' : ''"
v-if="field.oldData">
{{field.oldData}}
</view>
<view v-if="field.newData && field.oldData" class="modify-center">修改为
</view>
<view class="modify modify-right"
:style="{'text-align': item.yunzhupaas_type == '0'? 'end' : 'center'}"
:class="item.yunzhupaas_type == '2' ? 'line-through' : ''" v-if="field.newData">
{{field.newData}}
</view>
</view>
<view v-if="field.oldData === field.newData" class="modify-else"
:class="item.yunzhupaas_type == '2' ? 'line-through' : ''">
{{field.oldData}}
</view>
</template>
</view>
</view>
</view>
</view>
</view>
</view>
</uni-popup>
</template>
<script>
import {
recordList
} from '@/api/workFlow/flowBefore'
import {
useDefineSetting
} from '@/utils/useDefineSetting';
export default {
props: {
dataLogList: {
type: Array,
default: () => []
}
},
data() {
return {
useDefine: useDefineSetting(),
recordList: [],
chidData: [],
chidField: [],
childItem: {}
}
},
computed: {
baseURL() {
return this.define.baseURL
},
list() {
let dataLogList = JSON.parse(JSON.stringify(this.dataLogList))
if (dataLogList.length) {
let dataLogData = dataLogList.map(o => ({
...o,
dataLog: JSON.parse(o.dataLog)
}))
return dataLogData
}
}
},
methods: {
previewImage(url, yunzhupaasKey) {
// #ifndef MP
let baseURL = yunzhupaasKey == 'sign' ? url : (this.baseURL + url)
uni.previewImage({
urls: [baseURL]
});
// #endif
},
openChild(child) {
this.childItem = child || {}
let chidData = this.childItem.chidData || [];
let chidField = this.childItem.chidField || [];
let data = chidData.map(o => {
let item = {
yunzhupaas_type: o.yunzhupaas_type,
chidField: []
};
chidField.forEach(chid => {
if (o.hasOwnProperty(chid.prop)) {
let val = o[chid.prop]
if (chid.yunzhupaasKey === "calculate" && !chid.prop) return
let newData = {
...chid,
newData: val,
oldData: o[`yunzhupaas_old_${chid.prop}`] ? o[`yunzhupaas_old_${chid.prop}`] : ''
};
item.chidField.push(newData);
} else {
item.chidField.push({
...chid,
newData: '',
oldData: ''
});
}
});
return item;
});
this.chidData = data
this.$nextTick(() => {
this.$refs.flowStepPopup.open('bottom')
})
},
getTimeLineTagColor(status) {
return status == 0 ? '#08AF28' : '#0177FF';
},
popupClose() {
this.$refs.flowStepPopup.close()
}
}
}
</script>
<style lang="scss">
.line-through {
text-decoration: line-through;
}
.modify-else {
overflow: hidden;
word-break: break-all;
text-overflow: ellipsis;
}
.timeLine-popup-content {
height: 1200rpx;
overflow-y: scroll;
.head-title {
justify-content: space-between;
color: #333333;
padding: 0 20rpx;
/* #ifdef APP */
// padding: 20rpx 0;
/* #endif */
height: 80rpx;
}
.notice-warp {
top: -2rpx;
height: 80rpx;
// border-bottom: 1rpx solid #ececec;
}
.table-content {
padding: 0 20rpx;
margin-top: 80rpx;
.table-content-inner {
margin-bottom: 40rpx;
.table-content-title {
min-height: 80rpx;
background-color: #f5f5f5;
padding: 16rpx 20rpx;
border-radius: 8rpx 8rpx 0 0;
color: #303133;
}
.table-field {
.table-field-item {
min-height: 80rpx;
padding: 16rpx 20rpx;
justify-content: space-between;
align-items: center;
border-bottom: 1rpx solid #ececec;
color: #606266;
&:last-child {
border-radius: 0rpx 0rpx 8rpx 8rpx;
}
.label {
flex: 0.3;
}
.val {
font-size: 24rpx;
text-align: right;
flex: 0.7;
.txt {
color: #4aa8ff;
}
.modify-box {
justify-content: flex-end;
.modify {
padding: 8rpx;
border-radius: 8rpx;
color: #606266;
}
.modify-center {
width: 100rpx;
text-align: center;
}
.modify-right {
width: 200rpx;
word-wrap: break-word;
background-color: #defee9;
text-align: center;
}
.modify-left {
width: 200rpx;
word-wrap: break-word;
background-color: #ffd2d2;
text-align: center;
}
}
}
}
}
}
}
}
.u-node {
width: 20rpx;
height: 20rpx;
border-radius: 50%;
}
.content {
.start {
.log-title {
justify-content: space-between;
}
// box-shadow: 0 6rpx 12rpx rgba(2, 7, 28, 0.16);
.avatar-box {
padding: 20rpx;
}
}
.avatar-block {
.log-title {
justify-content: space-between;
}
border-radius: 8rpx;
// box-shadow: 0 6rpx 12rpx rgba(2, 7, 28, 0.16);
.avatar-box {
justify-content: space-between;
background-color: #F5F5F5;
border-bottom: 1rpx solid #ececec;
padding: 20rpx;
}
.dataLog-child {
background-color: #F5F5F5;
// padding: 0 20rpx;
.dataLog-item {
padding: 20rpx;
&:last-child {
border-bottom: none;
}
.ordinary-field {
align-items: flex-start;
.left {
flex: 0.2;
}
.right {
flex: 0.8;
.val {
font-size: 24rpx;
flex: 0.8;
.txt {
color: #4aa8ff;
}
}
}
}
.child-line {
.field-child {
justify-content: space-between;
.table-detail {
justify-content: space-between;
}
.approver-list-r {
height: 46rpx;
.txt {
height: 36rpx;
}
}
}
}
}
}
}
}
</style>

View File

@@ -0,0 +1,142 @@
<template>
<view class="u-flex extra-val" v-for="(extra,e) in getExtraList" :key="e" v-if="getExtraList.length">
<view class="u-flex-col extra-child" v-if="extra.yunzhupaasKey === 'table'">
<view class="title" v-if="!extraObj[extra.value]?.length">{{extra.label}}</view>
<view class="extra-child-item" v-for="(item,i) in extraObj[extra.value]" :key="i"
v-if="extraObj[extra.value]?.length">
<view class="u-flex-col extra-child-item-hd">
<view class="title">{{extra.label}}</view>
<view class="title">{{`(${i+1})`}}</view>
</view>
<view class="u-flex child" v-for="(child,c) in extra.children" :key="c">
<view class="txt u-m-b-8">{{child.title}}</view>
<view class="txt val u-line-1">
{{extraObj[extra.value][i][child.dataIndex] }}
</view>
</view>
</view>
<view class="u-text-center" v-if="!extraObj[extra.value]?.length">
暂无数据
</view>
</view>
<view class="u-flex extra" v-else>
<view class="txt">{{extra.label}}</view>
<view class="txt val u-line-1" v-if="extraObj">{{extraObj[extra.value]}}</view>
</view>
</view>
</template>
<script>
export default {
props: {
extraOptions: {
type: Array,
default: () => []
},
extraObj: {
type: Object,
default: () => {}
}
},
computed: {
getExtraList() {
const extraOptions = this.extraOptions.filter(o => !!o.value);
let list = [];
for (let i = 0; i < extraOptions.length; i++) {
const e = extraOptions[i];
if (!e.value.includes('-')) {
list.push(e);
} else {
let value = e.value.split('-')[0];
let childValue = e.value.split('-')[1];
let label = e.label.split('-')[0];
let childLabel = e.label.replace(label + '-', '');
let newItem = {
yunzhupaasKey: 'table',
value,
label,
title: label,
dataIndex: value,
children: [],
tableName: value
};
e.dataIndex = childValue;
e.title = childLabel;
if (!list.some(o => o.value === value)) list.push(newItem);
for (let i = 0; i < list.length; i++) {
if (list[i].value === value) {
list[i].children.push(e);
break;
}
}
}
}
return list;
}
}
}
</script>
<style lang="scss">
.extra-val {
min-height: 58rpx;
margin-bottom: 0.8rem;
justify-content: space-between;
&:last-child {
margin-bottom: 0;
}
.extra-child {
width: 100%;
border: 1rpx solid #f0f2f6;
border-radius: 8rpx 8rpx 0 0;
margin-bottom: 20rpx;
.title {
padding-left: 10rpx;
background-color: #f0f2f6;
}
.extra-child-item {
.extra-child-item-hd {
background-color: #f0f2f6;
border-radius: 8rpx 8rpx 0 0;
padding-left: 10rpx;
.title {
height: 58rpx;
}
}
.child {
justify-content: space-between;
// padding-left: 10rpx;
min-height: 58rpx;
border-bottom: 2rpx solid #f0f2f6;
padding: 14rpx;
}
}
}
.extra {
width: 100%;
justify-content: space-between;
padding-left: 10rpx;
min-height: 2.18rem;
}
.txt {
width: 160rpx;
line-height: 1.2rem;
font-size: 28rpx;
}
.val {
text-align: right;
width: 300rpx;
overflow: hidden;
}
}
</style>

400
components/index.js Normal file
View File

@@ -0,0 +1,400 @@
/* eslint-disable no-nested-ternary */
/* eslint-disable no-restricted-syntax */
/* eslint-disable guard-for-in */
/**
* num 小于0左缩进num*2个空格 大于0右缩进num*2个空格。
* @param {string} str 代码
* @param {number} num 缩进次数
* @param {number} len 【可选】缩进单位,空格数
*/
export function indent(str, num, len = 2) {
if (num === 0) return str
const isLeft = num < 0;
const result = [];
let reg;
let
spaces = ''
if (isLeft) {
num *= -1
reg = new RegExp(`(^\\s{0,${num * len}})`, 'g')
} else {
for (let i = 0; i < num * len; i++) spaces += ' '
}
str.split('\n').forEach(line => {
line = isLeft ? line.replace(reg, '') : spaces + line
result.push(line)
})
return result.join('\n')
}
// 首字母大小
export function titleCase(str) {
return str.replace(/( |^)[a-z]/g, L => L.toUpperCase())
}
// 下划转驼峰
export function camelCase(str) {
return str.replace(/-[a-z]/g, str1 => str1.substr(-1).toUpperCase())
}
export function isNumberStr(str) {
return /^[+-]?(0|([1-9]\d*))(\.\d+)?$/g.test(str)
}
export const exportDefault = 'export default '
export const beautifierConf = {
html: {
indent_size: '2',
indent_char: ' ',
max_preserve_newlines: '-1',
preserve_newlines: false,
keep_array_indentation: false,
break_chained_methods: false,
indent_scripts: 'separate',
brace_style: 'end-expand',
space_before_conditional: true,
unescape_strings: false,
jslint_happy: false,
end_with_newline: true,
wrap_line_length: '110',
indent_inner_html: true,
comma_first: false,
e4x: true,
indent_empty_lines: true
},
js: {
indent_size: '2',
indent_char: ' ',
max_preserve_newlines: '-1',
preserve_newlines: false,
keep_array_indentation: false,
break_chained_methods: false,
indent_scripts: 'normal',
brace_style: 'end-expand',
space_before_conditional: true,
unescape_strings: false,
jslint_happy: true,
end_with_newline: true,
wrap_line_length: '110',
indent_inner_html: true,
comma_first: false,
e4x: true,
indent_empty_lines: true
}
}
function stringify(obj) {
return JSON.stringify(obj, (key, val) => {
if (typeof val === 'function') {
return `${val}`
}
return val
})
}
function parse(str) {
JSON.parse(str, (k, v) => {
if (v.indexOf && v.indexOf('function') > -1) {
return eval(`(${v})`)
}
return v
})
}
export function jsonClone(obj) {
return parse(stringify(obj))
}
// 深拷贝对象
export function deepClone(obj) {
const _toString = Object.prototype.toString
// null, undefined, non-object, function
if (!obj || typeof obj !== 'object') {
return obj
}
// DOM Node
if (obj.nodeType && 'cloneNode' in obj) {
return obj.cloneNode(true)
}
// Date
if (_toString.call(obj) === '[object Date]') {
return new Date(obj.getTime())
}
// RegExp
if (_toString.call(obj) === '[object RegExp]') {
const flags = []
if (obj.global) {
flags.push('g')
}
if (obj.multiline) {
flags.push('m')
}
if (obj.ignoreCase) {
flags.push('i')
}
return new RegExp(obj.source, flags.join(''))
}
const result = Array.isArray(obj) ? [] : obj.constructor ? new obj.constructor() : {}
for (const key in obj) {
result[key] = deepClone(obj[key])
}
return result
}
/**
* 将用户输入的连续单个数字合并为一个数
* @param {Array} expressions - 记录计算表达式的数组
* @returns {Array} 新的数组
*/
export const mergeNumberOfExps = expressions => {
const res = []
const isNumChar = n => /^[\d|\.]$/.test(n)
for (let i = 0; i < expressions.length; i++) {
if (i > 0 && isNumChar(expressions[i - 1]) && isNumChar(expressions[i])) {
res[res.length - 1] += expressions[i]
continue
}
res.push(expressions[i])
}
return res
}
/**
* 校验表达式是否符合计算法则
* @param {Array} expressions - 合并数字后的表达式数组
* @returns {Boolean}
*/
export const validExp = (expressions, mergeNum = true) => {
const temp = mergeNum ? mergeNumberOfExps(expressions) : expressions
const arr = temp.filter(t => !'()'.includes(t))
// 去括号后 length应该为奇数 并且第一个字符和最后一个字符应该为数字而非计算符号
if (temp.length % 2 === 0 || arr.length % 2 === 0 || Number.isNaN(+arr[0]) || Number.isNaN(+arr[arr.length -
1])) {
return false
}
for (let i = 0; i < arr.length - 1; i += 2) {
if (typeof(+arr[i]) !== 'number' || !Number.isNaN(+arr[i + 1])) return false
}
return true
}
/**
* 中缀转后缀(逆波兰 Reverse Polish Notation
* @param {Array} exps - 中缀表达式数组
*/
export const toRPN = exps => {
const s1 = [] // 符号栈
const s2 = [] // 输出栈
const getTopVal = (stack) => stack.length > 0 ? stack[stack.length - 1] : null
const levelCompare = (c1, c2) => {
const getIndex = c => ['+-', '×÷', '()'].findIndex(t => t.includes(c))
return getIndex(c1) - getIndex(c2)
}
exps.forEach(t => {
if (typeof t === 'string' && Number.isNaN(Number(t))) { // 是符号
if (t === '(') {
s1.push(t)
} else if (t === ')') {
let popVal
do {
popVal = s1.pop()
popVal !== '(' && s2.push(popVal)
} while (s1.length && popVal !== '(')
} else {
let topVal = getTopVal(s1)
if (!topVal) { // s1 为空 直接push
s1.push(t)
} else {
while (topVal && topVal !== '(' && levelCompare(topVal, t) >= 0) { // 优先级 >= t 弹出到s2
s2.push(s1.pop())
topVal = getTopVal(s1)
}
s1.push(t)
}
}
return
}
s2.push(t) // 数字直接入栈
})
while (s1.length) {
s2.push(s1.pop())
}
return s2
}
/**
* 计算后缀表达式的值
* @param {Array} rpnExps - 后缀表达式
*/
export const calcRPN = rpnExps => {
rpnExps = rpnExps.concat()
const calc = (x, y, type) => {
let a1 = Number(x),
a2 = Number(y)
switch (type) {
case '+':
return a1 + a2;
case '-':
return a1 - a2;
case '×':
return a1 * a2;
case '÷':
return a1 / a2;
}
}
for (let i = 2; i < rpnExps.length; i++) {
if ('+-×÷'.includes(rpnExps[i])) {
let val = calc(rpnExps[i - 2], rpnExps[i - 1], rpnExps[i])
rpnExps.splice(i - 2, 3, val)
i = i - 2
}
}
return rpnExps[0]
}
/**
* 简易防抖函数
* @param {Function} func -防抖目标函数
* @param {Number} gap - 防抖时间间隔
*/
export const debounce = (func, gap) => {
let timer
return function() {
timer && clearTimeout(timer)
timer = setTimeout(() => {
func.apply(this, arguments)
}, gap)
}
}
//计算年或者月
export function getDateDay(Target, type, monthNum) {
let date = new Date()
let year = date.getFullYear() //获取当前日期的年份
let month = (date.getMonth() + 1 < 10 ? '0' + (date.getMonth() + 1) : date.getMonth() + 1) //获取当前日期的月份
let day = date.getDate() //获取当前日期的日
let hours = date.getHours() < 10 ? '0' + date.getHours() : date.getHours()
let minutes = date.getMinutes() < 10 ? '0' + date.getMinutes() : date.getMinutes()
let seconds = date.getSeconds() < 10 ? '0' + date.getSeconds() : date.getSeconds()
let days = new Date(year, month, 0)
days = days.getDate(); //获取当前日期中的月的天数
let year2 = year;
let month2;
if (Target == 2) {
if (type == 5) {
month2 = parseInt(month) + parseInt(monthNum)
if (month2 > 12) {
year2 = parseInt(year2) + parseInt((parseInt(month2) / 12 == 0 ? 1 : parseInt(month2) / 12));
month2 = parseInt(month2) % 12;
}
} else if (type == 4) {
month2 = parseInt(month) - monthNum;
if (month2 <= 0) {
let absM = Math.abs(month2);
year2 = parseInt(year2) - Math.ceil(absM / 12 == 0 ? 1 : parseInt(absM) / 12);
month2 = 12 - (absM % 12);
}
}
} else if (Target == 1) {
month2 = parseInt(month)
if (type == 5) {
year2 = parseInt(year) + parseInt(monthNum)
} else if (type == 4) {
year2 = parseInt(year) - parseInt(monthNum)
}
}
let day2 = day;
let days2 = new Date(year2, month2, 0);
days2 = days2.getDate();
if (day2 > days2) {
day2 = days2;
}
if (month2 < 10) {
month2 = '0' + month2;
}
let t2 = year2 + '-' + month2 + '-' + day2 + ' ' + hours + ':' + minutes + ':' + seconds;
return t2;
}
//计算日
export function getLaterData(days) {
let date = new Date();
date.setDate(date.getDate() + days);
let month = date.getMonth() + 1;
let day = date.getDate();
let hours = date.getHours() < 10 ? '0' + date.getHours() : date.getHours()
let minutes = date.getMinutes() < 10 ? '0' + date.getMinutes() : date.getMinutes()
let seconds = date.getSeconds() < 10 ? '0' + date.getSeconds() : date.getSeconds()
return date.getFullYear() + '-' + ('0' + month).slice(-2) + '-' + ('0' + day).slice(-2) + ' ' + hours + ':' +
minutes + ':' + seconds;
}
export function getBeforeData(num) {
let dateArray = []
//获取今天日期
let myDate = new Date()
let hours = myDate.getHours() < 10 ? '0' + myDate.getHours() : myDate.getHours()
let minutes = myDate.getMinutes() < 10 ? '0' + myDate.getMinutes() : myDate.getMinutes()
let seconds = myDate.getSeconds() < 10 ? '0' + myDate.getSeconds() : myDate.getSeconds()
let today = myDate.getFullYear() + '-' + (myDate.getMonth() + 1) + "-" + myDate.getDate();
myDate.setDate(myDate.getDate() - num)
let dateTemp; // 临时日期数据
let flag = 1;
for (let i = 0; i < num; i++) {
dateTemp = myDate.getFullYear() + '-' + (myDate.getMonth() + 1) + "-" + myDate.getDate()
dateArray.push({
date: dateTemp
})
myDate.setDate(myDate.getDate() + flag);
}
dateArray.push({
date: today
})
let arr = []
let newArr = []
dateArray.forEach(item => {
arr.push(item.date.split('-'))
})
for (let i = 0; i < arr.length; i++) {
if (arr[i][1] < 10) {
arr[i][1] = "0" + arr[i][1]
}
if (arr[i][2] < 10) {
arr[i][2] = "0" + arr[i][2]
}
}
for (let j = 0; j < arr.length; j++) {
newArr.push(arr[j].join("-"))
}
return newArr[0] + ' ' + hours + ':' + minutes + ':' + seconds
}
export function getBeforeTime(type, val) {
let date = new Date()
if (type == 4 || type == 1) {
date.setHours((Number(date.getHours()) - Number(val)))
} else if (type == 5 || type == 2) {
date.setMinutes((Number(date.getMinutes()) - Number(val)))
} else if (type == 6 || type == 3) {
date.setSeconds((Number(date.getSeconds()) - Number(val)))
}
return date
}
export function getLaterTime(type, val) {
let date = new Date()
if (type == 4 || type == 1) {
date.setHours((Number(date.getHours()) + Number(val)))
} else if (type == 5 || type == 2) {
date.setMinutes((Number(date.getMinutes()) + Number(val)))
} else if (type == 6 || type == 3) {
date.setSeconds((Number(date.getSeconds()) + Number(val)))
}
return date
}

View File

@@ -0,0 +1,200 @@
<template>
<text :class="classObj.wrapper" @click.stop="handleClick">
<text :class="[classObj.input, {'is-indeterminate': indeterminate, 'is-checked': checked, 'is-disabled': disabled}]">
<text :class="classObj.inner"></text>
</text>
</text>
</template>
<script>
export default {
data() {
return {
classObj: {}
}
},
props: {
type: {
type: String,
validator(t) {
return t === 'radio' || t === 'checkbox'
}
},
checked: Boolean,
disabled: Boolean,
indeterminate: Boolean
},
created() {
this.classObj = {
wrapper: `ly-${this.type}`,
input: `ly-${this.type}__input`,
inner: `ly-${this.type}__inner`
}
},
methods: {
handleClick() {
this.$emit('check', this.checked);
}
}
}
</script>
<style>
/* lyRadio/lyCheckbox-start */
.ly-checkbox,
.ly-radio {
color: #606266;
font-weight: 500;
font-size: 28rpx;
cursor: pointer;
user-select: none;
padding-right: 16rpx
}
.ly-checkbox__input,
.ly-radio__input {
cursor: pointer;
outline: 0;
line-height: 1;
vertical-align: middle
}
.ly-checkbox__input.is-disabled .ly-checkbox__inner,
.ly-radio__input.is-disabled .ly-radio__inner {
background-color: #edf2fc;
border-color: #DCDFE6;
cursor: not-allowed
}
.ly-checkbox__input.is-disabled .ly-checkbox__inner::after,
.ly-radio__input.is-disabled .ly-radio__inner::after {
cursor: not-allowed;
border-color: #C0C4CC
}
.ly-checkbox__input.is-disabled .ly-checkbox__inner+.ly-checkbox__label,
.ly-radio__input.is-disabled .ly-radio__inner+.ly-radio__label {
cursor: not-allowed
}
.ly-checkbox__input.is-disabled.is-checked .ly-checkbox__inner,
.ly-radio__input.is-disabled.is-checked .ly-radio__inner {
background-color: #F2F6FC;
border-color: #DCDFE6
}
.ly-checkbox__input.is-disabled.is-checked .ly-checkbox__inner::after,
.ly-radio__input.is-disabled.is-checked .ly-radio__inner::after {
border-color: #C0C4CC
}
.ly-checkbox__input.is-disabled.is-indeterminate .ly-checkbox__inner {
background-color: #F2F6FC;
border-color: #DCDFE6
}
.ly-checkbox__input.is-disabled.is-indeterminate .ly-checkbox__inner::before {
background-color: #C0C4CC;
border-color: #C0C4CC
}
.ly-checkbox__input.is-checked .ly-checkbox__inner,
.ly-radio__input.is-checked .ly-radio__inner,
.ly-checkbox__input.is-indeterminate .ly-checkbox__inner {
background-color: #409EFF;
border-color: #409EFF
}
.ly-checkbox__input.is-disabled+text.ly-checkbox__label,
.ly-radio__input.is-disabled+text.ly-radio__label {
color: #C0C4CC;
cursor: not-allowed
}
.ly-checkbox__input.is-checked .ly-checkbox__inner::after,
.ly-radio__input.is-checked .ly-radio__inner::after {
-webkit-transform: rotate(45deg) scaleY(1);
transform: rotate(45deg) scaleY(1)
}
.ly-checkbox__input.is-checked+.ly-checkbox__label,
.ly-radio__input.is-checked+.ly-radio__label {
color: #409EFF
}
.ly-checkbox__input.is-focus .ly-checkbox__inner,
.ly-radio__input.is-focus .ly-radio__inner {
border-color: #409EFF
}
.ly-checkbox__input.is-indeterminate .ly-checkbox__inner::before {
content: '';
position: absolute;
display: block;
background-color: #FFF;
height: 6rpx;
-webkit-transform: scale(.5);
transform: scale(.5);
left: 0;
right: 0;
top: 10rpx
}
.ly-checkbox__input.is-indeterminate .ly-checkbox__inner::after {
display: none
}
.ly-checkbox__inner,
.ly-radio__inner {
display: inline-block;
position: relative;
border: 2rpx solid #DCDFE6;
border-radius: 4rpx;
-webkit-box-sizing: border-box;
box-sizing: border-box;
width: 28rpx;
height: 28rpx;
background-color: #FFF;
z-index: 1;
-webkit-transition: border-color .25s cubic-bezier(.71, -.46, .29, 1.46), background-color .25s cubic-bezier(.71, -.46, .29, 1.46);
transition: border-color .25s cubic-bezier(.71, -.46, .29, 1.46), background-color .25s cubic-bezier(.71, -.46, .29, 1.46)
}
.ly-radio__inner {
border-radius: 50%;
width: 34rpx !important;
height: 34rpx !important;
}
.ly-checkbox__inner::after,
.ly-radio__inner::after {
-webkit-box-sizing: content-box;
box-sizing: content-box;
content: "";
border: 2rpx solid #FFF;
border-left: 0;
border-top: 0;
height: 14rpx;
left: 10rpx;
position: absolute;
top: 2rpx;
-webkit-transform: rotate(45deg) scaleY(0);
transform: rotate(45deg) scaleY(0);
width: 6rpx;
-webkit-transition: -webkit-transform .15s ease-in .05s;
transition: -webkit-transform .15s ease-in .05s;
transition: transform .15s ease-in .05s;
transition: transform .15s ease-in .05s, -webkit-transform .15s ease-in .05s;
-webkit-transform-origin: center;
transform-origin: center
}
.ly-radio__inner::after {
left: 12rpx !important;
top: 6rpx !important;
}
/* lyRadio/lyCheckbox-end */
</style>

View File

@@ -0,0 +1,401 @@
<template>
<view ref="node" name="LyTreeNode" v-show="node.visible" class="ly-tree-node" :class="{
'is-expanded': expanded,
'is-hidden': !node.visible,
'is-checked': !node.disabled && node.checked
}" role="treeitem" @tap.stop="handleClick">
<view class="ly-tree-node__content" :class="{
'is-current': node.isCurrent && highlightCurrent
}" :style="{
'padding-left': (node.level - 1) * indent + 'px'
}">
<text @tap.stop="handleExpandIconClick" :class="[
{
'is-leaf': node.isLeaf,
expanded: !node.isLeaf && node.expanded
},
'ly-tree-node__expand-icon',
iconClass ? iconClass : 'ly-iconfont ly-icon-caret-right'
]">
</text>
<ly-checkbox v-if="checkboxVisible || radioVisible" :type="checkboxVisible ? 'checkbox' : 'radio'"
:checked="node.checked" :indeterminate="node.indeterminate" :disabled="!!node.disabled"
@check="handleCheckChange(!node.checked)" />
<text v-if="node.loading" class="ly-tree-node__loading-icon ly-iconfont ly-icon-loading">
</text>
<template v-if="node.icon && node.icon.length > 0">
<image v-if="node.icon.indexOf('/') !== -1" class="ly-tree-node__icon" mode="widthFix" :src="node.icon"
@error="handleImageError">
</image>
<text v-else class="ly-tree-node__icon" :class="node.icon">
</text>
</template>
<text class="ly-tree-node__label u-line-1">{{node.label}}</text>
</view>
<view v-if="!renderAfterExpand || childNodeRendered" v-show="expanded" class="ly-tree-node__children"
role="group">
<ly-tree-node v-for="cNodeId in node.childNodesId" :nodeId="cNodeId"
:render-after-expand="renderAfterExpand" :show-checkbox="showCheckbox" :show-radio="showRadio"
:check-only-leaf="checkOnlyLeaf" :key="getNodeKey(cNodeId)" :indent="indent" :icon-class="iconClass">
</ly-tree-node>
</view>
</view>
</template>
<script>
import {
getNodeKey
} from './tool/util.js';
import lyCheckbox from './components/ly-checkbox.vue';
export default {
name: 'LyTreeNode',
componentName: 'LyTreeNode',
components: {
lyCheckbox
},
props: {
nodeId: [Number, String],
renderAfterExpand: {
type: Boolean,
default: true
},
checkOnlyLeaf: {
type: Boolean,
default: false
},
showCheckbox: {
type: Boolean,
default: false
},
showRadio: {
type: Boolean,
default: false
},
indent: Number,
iconClass: String
},
data() {
return {
node: {
indeterminate: false,
checked: false,
expanded: false
},
expanded: false,
childNodeRendered: false,
oldChecked: null,
oldIndeterminate: null,
highlightCurrent: false
};
},
inject: ['tree'],
computed: {
checkboxVisible() {
if (this.checkOnlyLeaf) {
return this.showCheckbox && this.node.isLeaf;
}
return this.showCheckbox;
},
radioVisible() {
if (this.checkOnlyLeaf) {
return this.showRadio && this.node.isLeaf;
}
return this.showRadio;
}
},
watch: {
'node.indeterminate'(val) {
this.handleSelectChange(this.node.checked, val);
},
'node.checked'(val) {
this.handleSelectChange(val, this.node.indeterminate);
},
'node.expanded'(val) {
this.$nextTick(() => this.expanded = val);
if (val) {
this.childNodeRendered = true;
}
}
},
methods: {
getNodeKey(nodeId) {
let node = this.tree.store.root.getChildNodes([nodeId])[0];
return getNodeKey(this.tree.nodeKey, node.data);
},
handleSelectChange(checked, indeterminate) {
if (this.oldChecked !== checked && this.oldIndeterminate !== indeterminate) {
if (this.checkOnlyLeaf && !this.node.isLeaf) return;
if (this.checkboxVisible) {
const allNodes = this.tree.store._getAllNodes();
this.tree.$emit('check-change', {
checked,
indeterminate,
node: this.node,
data: this.node.data,
checkedall: allNodes.every(item => item.checked)
});
} else {
this.tree.$emit('radio-change', {
checked,
node: this.node,
data: this.node.data,
checkedall: false
});
}
}
if (!this.expanded && this.tree.expandOnCheckNode && checked) {
this.handleExpandIconClick();
}
this.oldChecked = checked;
this.indeterminate = indeterminate;
},
handleClick() {
this.tree.store.setCurrentNode(this.node);
this.tree.$emit('current-change', {
node: this.node,
data: this.tree.store.currentNode ? this.tree.store.currentNode.data : null,
currentNode: this.tree.store.currentNode
});
this.tree.currentNode = this.node;
if (this.tree.expandOnClickNode) {
this.handleExpandIconClick();
}
if (this.tree.checkOnClickNode && !this.node.disabled) {
(this.checkboxVisible || this.radioVisible) && this.handleCheckChange(!this.node.checked);
}
this.tree.$emit('node-click', this.node);
},
handleExpandIconClick() {
if (this.node.isLeaf) return;
if (this.expanded) {
this.tree.$emit('node-collapse', this.node);
this.node.collapse();
} else {
this.node.expand();
this.tree.$emit('node-expand', this.node);
if (this.tree.accordion) {
uni.$emit(`${this.tree.elId}-tree-node-expand`, this.node);
}
}
},
handleCheckChange(checked) {
if (this.node.disabled) return;
if (this.checkboxVisible) {
this.node.setChecked(checked, !(this.tree.checkStrictly || this.checkOnlyLeaf));
} else {
this.node.setRadioChecked(checked);
}
this.$nextTick(() => {
this.tree.$emit('check', {
node: this.node,
data: this.node.data,
checkedNodes: this.tree.store.getCheckedNodes(),
checkedKeys: this.tree.store.getCheckedKeys(),
halfCheckedNodes: this.tree.store.getHalfCheckedNodes(),
halfCheckedKeys: this.tree.store.getHalfCheckedKeys()
});
});
uni.$emit('updateKey')
},
handleImageError() {
this.node.icon = this.tree.defaultNodeIcon;
}
},
created() {
if (!this.tree) {
throw new Error('Can not find node\'s tree.');
}
this.node = this.tree.store.nodesMap[this.nodeId];
this.highlightCurrent = this.tree.highlightCurrent;
if (this.node.expanded) {
this.expanded = true;
this.childNodeRendered = true;
}
const props = this.tree.props || {};
const childrenKey = props['children'] || 'children';
this.$watch(`node.data.${childrenKey}`, () => {
this.node.updateChildren();
});
if (this.tree.accordion) {
uni.$on(`${this.tree.elId}-tree-node-expand`, node => {
if (this.node.id !== node.id && this.node.level === node.level) {
this.node.collapse();
}
});
}
},
beforeDestroy() {
this.$parent = null;
}
};
</script>
<style>
.ly-tree-node {
white-space: nowrap;
outline: 0
}
.ly-tree-node__content {
display: flex;
align-items: center;
height: 70rpx;
}
.ly-tree-node__content.is-current {
background-color: #F5F7FA;
}
.ly-tree-node__content>.ly-tree-node__expand-icon {
padding: 12rpx;
}
.ly-tree-node__checkbox {
display: flex;
margin-right: 16rpx;
width: 40rpx;
height: 40rpx;
}
.ly-tree-node__checkbox>image {
width: 40rpx;
height: 40rpx;
}
.ly-tree-node__expand-icon {
color: #C0C4CC;
font-size: 28rpx;
-webkit-transform: rotate(0);
transform: rotate(0);
-webkit-transition: -webkit-transform .3s ease-in-out;
transition: -webkit-transform .3s ease-in-out;
transition: transform .3s ease-in-out;
transition: transform .3s ease-in-out, -webkit-transform .3s ease-in-out
}
.ly-tree-node__expand-icon.expanded {
-webkit-transform: rotate(90deg);
transform: rotate(90deg)
}
.ly-tree-node__expand-icon.is-leaf {
color: transparent;
}
.ly-tree-node__icon {
width: 34rpx;
/* height: 34rpx; */
overflow: hidden;
margin-right: 16rpx;
}
.ly-tree-node__label {
font-size: 28rpx
}
.ly-tree-node__loading-icon {
margin-right: 16rpx;
font-size: 28rpx;
color: #C0C4CC;
-webkit-animation: rotating 2s linear infinite;
animation: rotating 2s linear infinite
}
.ly-tree-node>.ly-tree-node__children {
overflow: hidden;
background-color: transparent
}
.ly-tree-node>.ly-tree-node__children.collapse-transition {
transition: height .3s ease-in-out;
}
.ly-tree-node.is-expanded>.ly-tree-node__children {
display: block
}
.ly-tree-node_collapse {
overflow: hidden;
padding-top: 0;
padding-bottom: 0;
}
/* lyTree-end */
/* iconfont-start */
@font-face {
font-family: "ly-iconfont";
src: url('data:application/x-font-woff2;charset=utf-8;base64,d09GMgABAAAAAAPsAAsAAAAACKwAAAOeAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHEIGVgCDBgqFDIQPATYCJAMMCwgABCAFhG0HQBtfB8gekiSCdAwUAKgCFMA5Hj7H0PeTlABUr57PVyGqugqzSWJnNwWoWJjx/9rUr4TPL1ZSQpU2mycqwoRwIN3p+MkqMqyEW+OtMBLPSUBb8v//XtWMKTavxYIUsT/Wy1qbQzkBDOYEKGB7dVpPyVqgCnJNwvMvhZl10nMCtQbFoPVhY8ZDncJfF4grbqpQ13AqE52hWqgcOFrEQ6hWnW5VfMCD7Pfjn4WoI6nI/K0bl0MNGPBz0qcflVqYnvCA4vNDPUXGPFCIw8HgtsqiOK9SrW2smm6sVITElWlpISMdVBn8wyMJopLfXg+myZ48KCrSkvj9g37U1ItbXYke4APwXxK3N4TuehyBfmM0I3zbNdt7uk3VnjPtzX0rnIl7z7bZvb/thHohsu9QuykKo+Cws4nL7LsPmI3n2qN9B9upZEIKd4hu0NCKi0rt7fNtdl+I1N25hOJMDQK6odS123tROR7Pg8toEhDaF+kR0TYjxW6M58F5+ZNQOxmZHtE2g+IYjxjlNy/yIRQpCmrgq5R4/3jx8PvT8Ha8d3/xiLnt4EGyaDnznzRv8vpyZ+9TFHf/ntX9e59A+b6+fPHd5+dy0wYHVvHOroWbnWe879O9DnL53bN/gUHuwm28b/n8i/V3ry4E3IoXNqS6Rvs0LhJxeNVjoUkM3LKosU+0a6rh45FVvLt+2oz7Zd53b4QOy7/9snDXHbqVu+A+f8r7PnM2H8kXrWm5c8/vLu7LqRee7HW637mz3kHc5U/RCXf25d7G8tkdgEfwIpzpkknGpaMw3ww55q9Mn9OQNyua/wB/49OOWydn4eL/6roCfjx6FMmcxfJStYRKfd3UwoHiML4rF4uMSK+SvYTuNxMHrpl8yd3Q6v32cAeo/KFaowBJlQHIqo3zi3geKtRZhErVlqDWnOGn67QRKkWpwaw1AkKza5A0egFZszf8In4HFTp9h0rNUQm1NqP1lXUmgyuDBVUlNYi2gHA98FnokUreOZaac1xV1JlMMZGKEs+QdCLVrgynPhUcO0pzzYyUjDAReGSYeBl13YCEIrCpLhOWlGE+mWRD35TQAw8UawRKJVEGQrMAwekCPpaMlpTOz49FmeZwqcREX1t3Ikoo4dMTaQmpBfzhRn9R30uZXTKXKUOSmLSKEQIeYhjqKZcrcIzhMLLRrJMSrA35UF4yGMaWGhPHm733dwJq+Z/NkSJHUXemCirjgpuWrHMD1eC+mQUAAAA=') format('woff2');
}
.ly-iconfont {
font-family: "ly-iconfont" !important;
font-size: 30rpx;
font-style: normal;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
.ly-icon-caret-right:before {
content: "\e8ee";
}
.ly-icon-loading:before {
content: "\e657";
}
/* iconfont-end */
/* animate-start */
@keyframes rotating {
0% {
-webkit-transform: rotateZ(0);
transform: rotateZ(0)
}
100% {
-webkit-transform: rotateZ(360deg);
transform: rotateZ(360deg)
}
}
/* animate-end */
</style>

View File

@@ -0,0 +1,651 @@
<template>
<view>
<template v-if="showLoading">
<view class="ly-loader ly-flex-center">
<view class="ly-loader-inner">{{$t('component.drawer.loadingText')}}</view>
</view>
</template>
<template v-else>
<view v-if="isEmpty || !visible" class="notData-box u-flex-col">
<view class="u-flex-col notData-inner">
<image :src="icon" mode="" class="iconImg"></image>
</view>
<text class="notData-inner-text">{{$t('common.noData')}}</text>
</view>
<view :key="updateKey" class="ly-tree" :class="{'is-empty': isEmpty || !visible}" role="tree"
name="LyTreeExpand" v-if="show">
<ly-tree-node v-for="nodeId in childNodesId" :nodeId="nodeId" :render-after-expand="renderAfterExpand"
:show-checkbox="showCheckbox" :show-radio="showRadio" :check-only-leaf="checkOnlyLeaf"
:key="getNodeKey(nodeId)" :indent="indent" :icon-class="iconClass">
</ly-tree-node>
</view>
</template>
</view>
</template>
<script>
import resources from '@/libs/resources.js'
import TreeStore from './model/tree-store.js';
import {
getNodeKey
} from './tool/util.js';
import LyTreeNode from './ly-tree-node.vue';
export default {
name: 'LyTree',
componentName: 'LyTree',
components: {
LyTreeNode
},
data() {
return {
updateKey: new Date().getTime(), // 数据更新的时候,重新渲染树
elId: `ly_${Math.ceil(Math.random() * 10e5).toString(36)}`,
visible: true,
store: {
ready: false
},
currentNode: null,
childNodesId: [],
mathKey: 1,
icon: resources.message.nodata,
show: true
};
},
provide() {
return {
tree: this
}
},
props: {
// 展示数据
treeData: Array,
// 自主控制loading加载避免数据还没获取到的空档出现“暂无数据”字样
ready: {
type: Boolean,
default: true
},
// 内容为空的时候展示的文本
emptyText: {
type: String,
default: '暂无数据'
},
// 是否在第一次展开某个树节点后才渲染其子节点
renderAfterExpand: {
type: Boolean,
default: true
},
// 每个树节点用来作为唯一标识的属性,整棵树应该是唯一的
nodeKey: String,
// 在显示复选框的情况下,是否严格的遵循父子不互相关联的做法,默认为 false
checkStrictly: Boolean,
// 是否默认展开所有节点
defaultExpandAll: {
type: Boolean,
default: true
},
// 切换全部展开、全部折叠
toggleExpendAll: Boolean,
// 是否在点击节点的时候展开或者收缩节点, 默认值为 true如果为 false则只有点箭头图标的时候才会展开或者收缩节点
expandOnClickNode: {
type: Boolean,
default: true
},
// 选中的时候展开节点
expandOnCheckNode: {
type: Boolean,
default: true
},
// 是否在点击节点的时候选中节点,默认值为 false即只有在点击复选框时才会选中节点
checkOnClickNode: Boolean,
checkDescendants: {
type: Boolean,
default: false
},
// 展开子节点的时候是否自动展开父节点
autoExpandParent: {
type: Boolean,
default: true
},
// 默认勾选的节点的 key 的数组
defaultCheckedKeys: Array,
// 默认展开的节点的 key 的数组
defaultExpandedKeys: Array,
// 是否展开当前节点的父节点
expandCurrentNodeParent: Boolean,
// 当前选中的节点
currentNodeKey: [String, Number],
// 是否最后一层叶子节点才显示单选/多选框
checkOnlyLeaf: {
type: Boolean,
default: false
},
// 节点是否可被选择
showCheckbox: {
type: Boolean,
default: false
},
// 节点单选
showRadio: {
type: Boolean,
default: false
},
// 配置选项
props: {
type: [Object, Function],
default () {
return {
children: 'children', // 指定子树为节点对象的某个属性值
label: 'label', // 指定节点标签为节点对象的某个属性值
disabled: 'disabled' // 指定节点选择框是否禁用为节点对象的某个属性值
};
}
},
// 是否懒加载子节点,需与 load 方法结合使用
lazy: {
type: Boolean,
default: false
},
// 是否高亮当前选中节点,默认值是 false
highlightCurrent: Boolean,
// 加载子树数据的方法,仅当 lazy 属性为true 时生效
load: Function,
// 对树节点进行筛选时执行的方法,返回 true 表示这个节点可以显示,返回 false 则表示这个节点会被隐藏
filterNodeMethod: Function,
// 搜索时是否展示匹配项的所有子节点
childVisibleForFilterNode: {
type: Boolean,
default: false
},
// 是否每次只打开一个同级树节点展开
accordion: Boolean,
// 相邻级节点间的水平缩进,单位为像素
indent: {
type: Number,
default: 18
},
// 自定义树节点的展开图标
iconClass: String,
// 是否显示节点图标如果配置为true,需要配置props中对应的图标属性名称
showNodeIcon: {
type: Boolean,
default: false
},
// 当节点图标显示出错时,显示的默认图标
defaultNodeIcon: {
type: String,
default: ''
},
// 如果数据量较大建议不要在node节点中添加parent属性会造成性能损耗
isInjectParentInNode: {
type: Boolean,
default: false
}
},
computed: {
isEmpty() {
if (this.store.root) {
const childNodes = this.store.root.getChildNodes(this.childNodesId);
return !childNodes || childNodes.length === 0 || childNodes.every(({
visible
}) => !visible);
}
return true;
},
showLoading() {
//不要删除
const a = this.mathKey
return !(this.store.getReady() && this.ready);
}
},
watch: {
toggleExpendAll(newVal) {
this.store.toggleExpendAll(newVal);
},
defaultCheckedKeys(newVal) {
this.store.setDefaultCheckedKey(newVal);
},
defaultExpandedKeys(newVal) {
this.store.defaultExpandedKeys = newVal;
this.store.setDefaultExpandedKeys(newVal);
},
checkStrictly(newVal) {
this.store.checkStrictly = newVal || this.checkOnlyLeaf;
},
'store.root.childNodesId'(newVal) {
this.childNodesId = newVal;
},
'store.root.visible'(newVal) {
this.visible = newVal;
},
childNodesId() {
this.$nextTick(() => {
this.$emit('ly-tree-render-completed');
});
},
treeData: {
handler(newVal) {
this.updateKey = new Date().getTime();
this.store.setData(newVal);
},
deep: true
}
},
methods: {
/*
* @description 对树节点进行筛选操作
* @method filter
* @param {all} value 在 filter-node-method 中作为第一个参数
* @param {Object} data 搜索指定节点的节点数据不传代表搜索所有节点假如要搜索A节点下面的数据那么nodeData代表treeData中A节点的数据
*/
filter(value, data) {
if (!this.filterNodeMethod) throw new Error('[Tree] filterNodeMethod is required when filter');
this.store.filter(value, data);
this.handleUpdateKey()
},
handleUpdateKey() {
// #ifndef MP
this.updateKey = new Date().getTime();
// #endif
// #ifdef MP
this.show = false
this.$nextTick(() => {
this.show = true
})
// #endif
},
/*
* @description 获取节点的唯一标识符
* @method getNodeKey
* @param {String, Number} nodeId
* @return {String, Number} 匹配到的数据中的某一项数据
*/
getNodeKey(nodeId) {
let node = this.store.root.getChildNodes([nodeId])[0];
return getNodeKey(this.nodeKey, node.data);
},
/*
* @description 获取节点路径
* @method getNodePath
* @param {Object} data 节点数据
* @return {Array} 路径数组
*/
getNodePath(data) {
return this.store.getNodePath(data);
},
/*
* @description 若节点可被选择(即 show-checkbox 为 true则返回目前被选中的节点所组成的数组
* @method getCheckedNodes
* @param {Boolean} leafOnly 是否只是叶子节点默认false
* @param {Boolean} includeHalfChecked 是否包含半选节点默认false
* @return {Array} 目前被选中的节点所组成的数组
*/
getCheckedNodes(leafOnly, includeHalfChecked) {
return this.store.getCheckedNodes(leafOnly, includeHalfChecked);
},
/*
* @description 若节点可被选择(即 show-checkbox 为 true则返回目前被选中的节点的 key 所组成的数组
* @method getCheckedKeys
* @param {Boolean} leafOnly 是否只是叶子节点默认false,若为 true 则仅返回被选中的叶子节点的 keys
* @param {Boolean} includeHalfChecked 是否返回indeterminate为true的节点默认false
* @return {Array} 目前被选中的节点所组成的数组
*/
getCheckedKeys(leafOnly, includeHalfChecked) {
return this.store.getCheckedKeys(leafOnly, includeHalfChecked);
},
/*
* @description 获取当前被选中节点的 data若没有节点被选中则返回 null
* @method getCurrentNode
* @return {Object} 当前被选中节点的 data若没有节点被选中则返回 null
*/
getCurrentNode() {
const currentNode = this.store.getCurrentNode();
return currentNode ? currentNode.data : null;
},
/*
* @description 获取当前被选中节点的 key若没有节点被选中则返回 null
* @method getCurrentKey
* @return {all} 当前被选中节点的 key 若没有节点被选中则返回 null
*/
getCurrentKey() {
const currentNode = this.getCurrentNode();
return currentNode ? currentNode[this.nodeKey] : null;
},
/*
* @description 设置全选/取消全选
* @method setCheckAll
* @param {Boolean} isCheckAll 选中状态,默认为true
*/
setCheckAll(isCheckAll = true) {
if (this.showRadio) throw new Error(
'You set the "show-radio" property, so you cannot select all nodes');
if (!this.showCheckbox) console.warn(
'You have not set the property "show-checkbox". Please check your settings');
this.store.setCheckAll(isCheckAll);
},
/*
* @description 设置目前勾选的节点
* @method setCheckedNodes
* @param {Array} nodes 接收勾选节点数据的数组
* @param {Boolean} leafOnly 是否只是叶子节点, 若为 true 则仅设置叶子节点的选中状态,默认值为 false
*/
setCheckedNodes(nodes, leafOnly) {
this.store.setCheckedNodes(nodes, leafOnly);
},
/*
* @description 通过 keys 设置目前勾选的节点
* @method setCheckedKeys
* @param {Array} keys 勾选节点的 key 的数组
* @param {Boolean} leafOnly 是否只是叶子节点, 若为 true 则仅设置叶子节点的选中状态,默认值为 false
*/
setCheckedKeys(keys, leafOnly) {
if (!this.nodeKey) throw new Error('[Tree] nodeKey is required in setCheckedKeys');
this.store.setCheckedKeys(keys, leafOnly);
this.handleUpdateKey()
},
/*
* @description 通过 key / data 设置某个节点的勾选状态
* @method setChecked
* @param {all} data 勾选节点的 key 或者 data
* @param {Boolean} checked 节点是否选中
* @param {Boolean} deep 是否设置子节点 ,默认为 false
*/
setChecked(data, checked, deep) {
this.store.setChecked(data, checked, deep);
},
/*
* @description 若节点可被选择(即 show-checkbox 为 true则返回目前半选中的节点所组成的数组
* @method getHalfCheckedNodes
* @return {Array} 目前半选中的节点所组成的数组
*/
getHalfCheckedNodes() {
return this.store.getHalfCheckedNodes();
},
/*
* @description 若节点可被选择(即 show-checkbox 为 true则返回目前半选中的节点的 key 所组成的数组
* @method getHalfCheckedKeys
* @return {Array} 目前半选中的节点的 key 所组成的数组
*/
getHalfCheckedKeys() {
return this.store.getHalfCheckedKeys();
},
/*
* @description 通过 node 设置某个节点的当前选中状态
* @method setCurrentNode
* @param {Object} node 待被选节点的 node
*/
setCurrentNode(node) {
if (!this.nodeKey) throw new Error('[Tree] nodeKey is required in setCurrentNode');
this.store.setUserCurrentNode(node);
},
/*
* @description 通过 key 设置某个节点的当前选中状态
* @method setCurrentKey
* @param {all} key 待被选节点的 key若为 null 则取消当前高亮的节点
*/
setCurrentKey(key) {
if (!this.nodeKey) throw new Error('[Tree] nodeKey is required in setCurrentKey');
this.store.setCurrentNodeKey(key);
},
/*
* @description 根据 data 或者 key 拿到 Tree 组件中的 node
* @method getNode
* @param {all} data 要获得 node 的 key 或者 data
*/
getNode(data) {
return this.store.getNode(data);
},
/*
* @description 删除 Tree 中的一个节点
* @method remove
* @param {all} data 要删除的节点的 data 或者 node
*/
remove(data) {
this.store.remove(data);
},
/*
* @description 为 Tree 中的一个节点追加一个子节点
* @method append
* @param {Object} data 要追加的子节点的 data
* @param {Object} parentNode 子节点的 parent 的 data、key 或者 node
*/
append(data, parentNode) {
this.store.append(data, parentNode);
},
/*
* @description 为 Tree 的一个节点的前面增加一个节点
* @method insertBefore
* @param {Object} data 要增加的节点的 data
* @param {all} refNode 要增加的节点的后一个节点的 data、key 或者 node
*/
insertBefore(data, refNode) {
this.store.insertBefore(data, refNode);
},
/*
* @description 为 Tree 的一个节点的后面增加一个节点
* @method insertAfter
* @param {Object} data 要增加的节点的 data
* @param {all} refNode 要增加的节点的前一个节点的 data、key 或者 node
*/
insertAfter(data, refNode) {
this.store.insertAfter(data, refNode);
},
/*
* @description 通过 keys 设置节点子元素
* @method updateKeyChildren
* @param {String, Number} key 节点 key
* @param {Object} data 节点数据的数组
*/
updateKeyChildren(key, data) {
if (!this.nodeKey) throw new Error('[Tree] nodeKey is required in updateKeyChild');
this.store.updateChildren(key, data);
}
},
created() {
this.isTree = true;
let props = this.props;
if (typeof this.props === 'function') props = this.props();
if (typeof props !== 'object') throw new Error('props must be of object type.');
this.store = new TreeStore({
key: this.nodeKey,
data: this.treeData,
lazy: this.lazy,
props: props,
load: this.load,
showCheckbox: this.showCheckbox,
showRadio: this.showRadio,
currentNodeKey: this.currentNodeKey,
checkStrictly: this.checkStrictly || this.checkOnlyLeaf,
checkDescendants: this.checkDescendants,
expandOnCheckNode: this.expandOnCheckNode,
defaultCheckedKeys: this.defaultCheckedKeys,
defaultExpandedKeys: this.defaultExpandedKeys,
expandCurrentNodeParent: this.expandCurrentNodeParent,
autoExpandParent: this.autoExpandParent,
defaultExpandAll: this.defaultExpandAll,
filterNodeMethod: this.filterNodeMethod,
childVisibleForFilterNode: this.childVisibleForFilterNode,
showNodeIcon: this.showNodeIcon,
isInjectParentInNode: this.isInjectParentInNode
});
this.childNodesId = this.store.root.childNodesId;
uni.$on(`updateKey`, () => {
this.handleUpdateKey()
this.mathKey++
});
},
beforeDestroy() {
if (this.accordion) {
uni.$off(`${this.elId}-tree-node-expand`)
}
uni.$off('updateKey')
}
};
</script>
<style lang="scss" scoped>
.notData-box {
width: 100%;
height: 100%;
justify-content: center;
align-items: center;
margin-top: 200rpx;
.notData-inner {
width: 286rpx;
height: 222rpx;
align-items: center;
.iconImg {
width: 100%;
height: 100%;
}
}
.notData-inner-text {
color: #909399;
}
}
.ly-tree {
position: relative;
cursor: default;
background: #FFF;
color: #606266;
padding: 30rpx;
}
.ly-tree.is-empty {
background: transparent;
}
/* lyEmpty-start */
.ly-empty {
width: 100%;
display: flex;
justify-content: center;
margin-top: 100rpx;
}
/* lyEmpty-end */
/* lyLoader-start */
.ly-loader {
margin-top: 100rpx;
display: flex;
align-items: center;
justify-content: center;
}
.ly-loader-inner,
.ly-loader-inner:before,
.ly-loader-inner:after {
background: #efefef;
animation: load 1s infinite ease-in-out;
width: .5em;
height: 1em;
}
.ly-loader-inner:before,
.ly-loader-inner:after {
position: absolute;
top: 0;
content: '';
}
.ly-loader-inner:before {
left: -1em;
}
.ly-loader-inner {
text-indent: -9999em;
position: relative;
font-size: 22rpx;
animation-delay: 0.16s;
}
.ly-loader-inner:after {
left: 1em;
animation-delay: 0.32s;
}
/* lyLoader-end */
@keyframes load {
0%,
80%,
100% {
box-shadow: 0 0 #efefef;
height: 1em;
}
40% {
box-shadow: 0 -1.5em #efefef;
height: 1.5em;
}
}
</style>

View File

@@ -0,0 +1,538 @@
import {
markNodeData,
objectAssign,
arrayFindIndex,
getChildState,
reInitChecked,
getPropertyFromData,
isNull,
NODE_KEY
} from '../tool/util';
const getStore = function(store) {
let thisStore = store;
return function() {
return thisStore;
}
}
let nodeIdSeed = 0;
export default class Node {
constructor(options) {
this.time = new Date().getTime();
this.id = nodeIdSeed++;
this.text = null;
this.checked = false;
this.indeterminate = false;
this.data = null;
this.expanded = false;
this.parentId = null;
this.visible = true;
this.isCurrent = false;
for (let name in options) {
if (options.hasOwnProperty(name)) {
if (name === 'store') {
this.store = getStore(options[name]);
} else {
this[name] = options[name];
}
}
}
if (!this.store()) {
throw new Error('[Node]store is required!');
}
// internal
this.level = 0;
this.loaded = false;
this.childNodesId = [];
this.loading = false;
this.label = getPropertyFromData(this, 'label');
this.key = this._getKey();
this.disabled = getPropertyFromData(this, 'disabled');
this.nextSibling = null;
this.previousSibling = null;
this.icon = '';
this._handleParentAndLevel();
this._handleProps();
this._handleExpand();
this._handleCurrent();
if (this.store().lazy) {
this.store()._initDefaultCheckedNode(this);
}
this.updateLeafState();
}
_getKey() {
if (!this.data || Array.isArray(this.data)) return null;
if (typeof this.data === 'object') {
const nodeKey = this.store().key;
const key = this.data[nodeKey];
if (typeof key === 'undefined') {
throw new Error(`您配置的node-key为"${nodeKey}",但数据中并未找到对应"${nodeKey}"属性的值请检查node-key的配置是否合理`)
}
return key;
}
throw new Error('不合法的data数据');
}
_handleParentAndLevel() {
if (this.parentId !== null) {
let parent = this.getParent(this.parentId);
if (this.store().isInjectParentInNode) {
this.parent = parent;
}
// 由于这里做了修改默认第一个对象不会被注册到nodesMap中所以找不到parent会报错所以默认parent的level是0
if (!parent) {
parent = {
level: 0
}
} else {
const parentChildNodes = parent.getChildNodes(parent.childNodesId);
const index = parent.childNodesId.indexOf(this.key);
this.nextSibling = index > -1 ? parentChildNodes[index + 1] : null;
this.previousSibling = index > 0 ? parentChildNodes[index - 1] : null;
}
this.level = parent.level + 1;
}
}
_handleProps() {
const props = this.store().props;
if (this.store().showNodeIcon) {
if (props && typeof props.icon !== 'undefined') {
this.icon = getPropertyFromData(this, 'icon');
} else {
console.warn('请配置props属性中的"icon"字段')
}
}
this.store().registerNode(this);
if (props && typeof props.isLeaf !== 'undefined') {
const isLeaf = getPropertyFromData(this, 'isLeaf');
if (typeof isLeaf === 'boolean') {
this.isLeafByUser = isLeaf;
}
}
}
_handleExpand() {
if (this.store().lazy !== true && this.data) {
this.setData(this.data);
if (this.store().defaultExpandAll) {
this.expanded = true;
}
} else if (this.level > 0 && this.store().lazy && this.store().defaultExpandAll) {
this.expand();
}
if (!Array.isArray(this.data)) {
markNodeData(this, this.data);
}
if (!this.data) return;
const defaultExpandedKeys = this.store().defaultExpandedKeys;
const key = this.store().key;
if (key && defaultExpandedKeys && defaultExpandedKeys.indexOf(this.key) !== -1) {
this.expand(null, this.store().autoExpandparent);
}
}
_handleCurrent() {
const key = this.store().key;
if (key && this.store().currentNodeKey !== undefined && this.key === this.store().currentNodeKey) {
this.store().currentNode = this;
this.store().currentNode.isCurrent = true;
}
}
destroyStore() {
getStore(null)
}
setData(data) {
if (!Array.isArray(data)) {
markNodeData(this, data);
}
this.data = data;
this.childNodesId = [];
let children;
if (this.level === 0 && Array.isArray(this.data)) {
children = this.data;
} else {
children = getPropertyFromData(this, 'children') || [];
}
for (let i = 0, j = children.length; i < j; i++) {
this.insertChild({
data: children[i]
});
}
}
contains(target, deep = true) {
const walk = function(parent) {
const children = parent.getChildNodes(parent.childNodesId) || [];
let result = false;
for (let i = 0, j = children.length; i < j; i++) {
const child = children[i];
if (child === target || (deep && walk(child))) {
result = true;
break;
}
}
return result;
};
return walk(this);
}
remove() {
if (this.parentId !== null) {
const parent = this.getParent(this.parentId);
parent.removeChild(this);
}
}
insertChild(child, index, batch) {
if (!child) throw new Error('insertChild error: child is required.');
if (!(child instanceof Node)) {
if (!batch) {
const children = this.getChildren(true);
if (children.indexOf(child.data) === -1) {
if (typeof index === 'undefined' || index < 0) {
children.push(child.data);
} else {
children.splice(index, 0, child.data);
}
}
}
objectAssign(child, {
parentId: isNull(this.key) ? '' : this.key,
store: this.store()
});
child = new Node(child);
}
child.level = this.level + 1;
if (typeof index === 'undefined' || index < 0) {
this.childNodesId.push(child.key);
} else {
this.childNodesId.splice(index, 0, child.key);
}
this.updateLeafState();
}
insertBefore(child, ref) {
let index;
if (ref) {
index = this.childNodesId.indexOf(ref.id);
}
this.insertChild(child, index);
}
insertAfter(child, ref) {
let index;
if (ref) {
index = this.childNodesId.indexOf(ref.id);
if (index !== -1) index += 1;
}
this.insertChild(child, index);
}
removeChild(child) {
const children = this.getChildren() || [];
const dataIndex = children.indexOf(child.data);
if (dataIndex > -1) {
children.splice(dataIndex, 1);
}
const index = this.childNodesId.indexOf(child.key);
if (index > -1) {
this.store() && this.store().deregisterNode(child);
child.parentId = null;
this.childNodesId.splice(index, 1);
}
this.updateLeafState();
}
removeChildByData(data) {
let targetNode = null;
for (let i = 0; i < this.childNodesId.length; i++) {
let node = this.getChildNodes(this.childNodesId);
if (node[i].data === data) {
targetNode = node[i];
break;
}
}
if (targetNode) {
this.removeChild(targetNode);
}
}
// 为了避免APP端parent嵌套结构导致报错这里parent需要从nodesMap中获取
getParent(parentId) {
try {
if (!parentId.toString()) return null;
return this.store().nodesMap[parentId];
} catch (error) {
return null;
}
}
// 为了避免APP端childNodes嵌套结构导致报错这里childNodes需要从nodesMap中获取
getChildNodes(childNodesId) {
let childNodes = [];
if (childNodesId.length === 0) return childNodes;
childNodesId.forEach((key) => {
childNodes.push(this.store().nodesMap[key]);
})
return childNodes;
}
expand(callback, expandparent) {
const done = () => {
if (expandparent) {
let parent = this.getParent(this.parentId);
while (parent && parent.level > 0) {
parent.expanded = true;
parent = this.getParent(parent.parentId);
}
}
this.expanded = true;
if (callback) callback();
};
if (this.shouldLoadData()) {
this.loadData(function(data) {
if (Array.isArray(data)) {
if (this.checked) {
this.setChecked(true, true);
} else if (!this.store().checkStrictly) {
reInitChecked(this);
}
done();
}
});
} else {
done();
}
}
doCreateChildren(array, defaultProps = {}) {
array.forEach((item) => {
this.insertChild(objectAssign({
data: item
}, defaultProps), undefined, true);
});
}
collapse() {
this.expanded = false;
}
shouldLoadData() {
return this.store().lazy === true && this.store().load && !this.loaded;
}
updateLeafState() {
if (this.store().lazy === true && this.loaded !== true && typeof this.isLeafByUser !== 'undefined') {
this.isLeaf = this.isLeafByUser;
return;
}
const childNodesId = this.childNodesId;
if (!this.store().lazy || (this.store().lazy === true && this.loaded === true)) {
this.isLeaf = !childNodesId || childNodesId.length === 0;
return;
}
this.isLeaf = false;
}
setChecked(value, deep, recursion, passValue) {
this.indeterminate = value === 'half';
this.checked = value === true;
if (this.checked && this.store().expandOnCheckNode) {
this.expand(null, true)
}
if (this.store().checkStrictly) return;
if (this.store().showRadio) return;
if (!(this.shouldLoadData() && !this.store().checkDescendants)) {
let childNodes = this.getChildNodes(this.childNodesId);
let {
all,
allWithoutDisable
} = getChildState(childNodes);
if (!this.isLeaf && (!all && allWithoutDisable)) {
this.checked = false;
value = false;
}
const handleDescendants = () => {
if (deep) {
let childNodes = this.getChildNodes(this.childNodesId)
for (let i = 0, j = childNodes.length; i < j; i++) {
const child = childNodes[i];
passValue = passValue || value !== false;
const isCheck = child.disabled ? child.checked : passValue;
child.setChecked(isCheck, deep, true, passValue);
}
const {
half,
all
} = getChildState(childNodes);
if (!all) {
this.checked = all;
this.indeterminate = half;
}
}
};
if (this.shouldLoadData()) {
this.loadData(() => {
handleDescendants();
reInitChecked(this);
}, {
checked: value !== false
});
return;
} else {
handleDescendants();
}
}
if (!this.parentId) return;
let parent = this.getParent(this.parentId);
if (parent && parent.level === 0) return;
if (!recursion) {
reInitChecked(parent);
}
}
setRadioChecked(value) {
const allNodes = this.store()._getAllNodes().sort((a, b) => b.level - a.level);
allNodes.forEach(node => node.setChecked(false, false));
this.checked = value === true;
}
getChildren(forceInit = false) {
if (this.level === 0) return this.data;
const data = this.data;
if (!data) return null;
const props = this.store().props;
let children = 'children';
if (props) {
children = props.children || 'children';
}
if (data[children] === undefined) {
data[children] = null;
}
if (forceInit && !data[children]) {
data[children] = [];
}
return data[children];
}
updateChildren() {
let childNodes = this.getChildNodes(this.childNodesId);
const newData = this.getChildren() || [];
const oldData = childNodes.map((node) => node.data);
const newDataMap = {};
const newNodes = [];
newData.forEach((item, index) => {
const key = item[NODE_KEY];
const isNodeExists = !!key && arrayFindIndex(oldData, data => data[NODE_KEY] === key) >= 0;
if (isNodeExists) {
newDataMap[key] = {
index,
data: item
};
} else {
newNodes.push({
index,
data: item
});
}
});
if (!this.store().lazy) {
oldData.forEach((item) => {
if (!newDataMap[item[NODE_KEY]]) this.removeChildByData(item);
});
}
newNodes.forEach(({
index,
data
}) => {
this.insertChild({
data
}, index);
});
this.updateLeafState();
}
loadData(callback, defaultProps = {}) {
if (this.store().lazy === true &&
this.store().load && !this.loaded &&
(!this.loading || Object.keys(defaultProps).length)
) {
this.loading = true;
const resolve = (children) => {
this.loaded = true;
this.loading = false;
this.childNodesId = [];
this.doCreateChildren(children, defaultProps);
this.updateLeafState();
callback && callback.call(this, children);
};
this.store().load(this, resolve);
} else {
callback && callback.call(this);
}
}
}

View File

@@ -0,0 +1,428 @@
import Node from './node';
import {
getNodeKey,
getPropertyFromData
} from '../tool/util';
export default class TreeStore {
constructor(options) {
this.ready = false;
this.currentNode = null;
this.currentNodeKey = null;
Object.assign(this, options);
if (!this.key) {
throw new Error('[Tree] nodeKey is required');
}
this.nodesMap = {};
this.root = new Node({
data: this.data,
store: this
});
if (this.lazy && this.load) {
const loadFn = this.load;
loadFn(this.root, (data) => {
this.root.doCreateChildren(data);
this._initDefaultCheckedNodes();
this.ready = true;
uni.$emit('updateKey') //加了异步才会展示数据
});
} else {
this._initDefaultCheckedNodes();
this.ready = true;
}
}
getReady() {
return this.ready
}
filter(value, data) {
const filterNodeMethod = this.filterNodeMethod;
const lazy = this.lazy;
const _self = this;
const traverse = function(node) {
const childNodes = node.root ? node.root.getChildNodes(node.root.childNodesId) : node.getChildNodes(
node.childNodesId);
childNodes.forEach((child) => {
if (data && typeof data === 'object') {
let nodePath = _self.getNodePath(child.data);
if (!nodePath.some(pathItem => pathItem[_self.key] === data[_self.key])) {
child.visible = false;
traverse(child);
return;
}
}
if (_self.childVisibleForFilterNode) {
let parent = child.getParent(child.parentId);
child.visible = filterNodeMethod.call(child, value, child.data, child) || (parent &&
parent.visible);
} else {
child.visible = filterNodeMethod.call(child, value, child.data, child);
}
traverse(child);
});
if (!node.visible && childNodes.length) {
let allHidden = true;
allHidden = !childNodes.some(child => child.visible);
if (node.root) {
node.root.visible = allHidden === false;
} else {
node.visible = allHidden === false;
}
}
if (!value) return;
if (node.visible && !node.isLeaf && !lazy) node.expand();
};
traverse(this);
}
setData(newVal) {
const instanceChanged = newVal !== this.root.data;
if (instanceChanged) {
this.root.setData(newVal);
this._initDefaultCheckedNodes();
} else {
this.root.updateChildren();
}
}
getNode(data) {
if (data instanceof Node) return data;
const key = typeof data !== 'object' ? data : getNodeKey(this.key, data);
if (!key) return null;
return this.nodesMap[key] || null;
}
insertBefore(data, refData) {
const refNode = this.getNode(refData);
let parent = refNode.getParent(refNode.parentId);
parent.insertBefore({
data
}, refNode);
}
insertAfter(data, refData) {
const refNode = this.getNode(refData);
let parent = refNode.getParent(refNode.parentId);
parent.insertAfter({
data
}, refNode);
}
remove(data) {
const node = this.getNode(data);
if (node && node.parentId !== null) {
let parent = node.getParent(node.parentId);
if (node === this.currentNode) {
this.currentNode = null;
}
parent.removeChild(node);
}
}
append(data, parentData) {
const parentNode = parentData ? this.getNode(parentData) : this.root;
if (parentNode) {
parentNode.insertChild({
data
});
}
}
_initDefaultCheckedNodes() {
const defaultCheckedKeys = this.defaultCheckedKeys || [];
const nodesMap = this.nodesMap;
let checkedKeyfromData = [];
let totalCheckedKeys = []
for (let key in nodesMap) {
let checked = getPropertyFromData(nodesMap[key], 'checked') || false;
checked && checkedKeyfromData.push(key);
}
totalCheckedKeys = Array.from(new Set([...defaultCheckedKeys, ...checkedKeyfromData]));
totalCheckedKeys.forEach((checkedKey) => {
const node = nodesMap[checkedKey];
if (node) {
node.setChecked(true, !this.checkStrictly);
}
});
}
_initDefaultCheckedNode(node) {
const defaultCheckedKeys = this.defaultCheckedKeys || [];
if (defaultCheckedKeys.indexOf(node.key) !== -1) {
node.setChecked(true, !this.checkStrictly);
}
}
toggleExpendAll(isExpandAll) {
const allNodes = this._getAllNodes();
allNodes.forEach(item => {
const node = this.getNode(item.key);
if (node) isExpandAll ? node.expand() : node.collapse();
});
}
setCheckAll(isCkeckAll) {
const allNodes = this._getAllNodes();
allNodes.forEach(item => {
item.setChecked(isCkeckAll, false);
});
}
setDefaultCheckedKey(newVal) {
if (newVal !== this.defaultCheckedKeys) {
this.defaultCheckedKeys = newVal;
this._initDefaultCheckedNodes();
}
}
registerNode(node) {
const key = this.key;
if (!key || !node || !node.data) return;
const nodeKey = node.key;
if (nodeKey !== undefined) this.nodesMap[node.key] = node;
}
deregisterNode(node) {
const key = this.key;
if (!key || !node || !node.data) return;
let childNodes = node.getChildNodes(node.childNodesId);
childNodes.forEach(child => {
this.deregisterNode(child);
});
delete this.nodesMap[node.key];
}
getNodePath(data) {
if (!this.key) throw new Error('[Tree] nodeKey is required in getNodePath');
const node = this.getNode(data);
if (!node) return [];
const path = [node.data];
let parent = node.getParent(node.parentId);
while (parent && parent !== this.root) {
path.push(parent.data);
parent = parent.getParent(parent.parentId);
}
return path.reverse();
}
getCheckedNodes(leafOnly = false, includeHalfChecked = false) {
const checkedNodes = [];
const traverse = function(node) {
const childNodes = node.root ? node.root.getChildNodes(node.root.childNodesId) : node.getChildNodes(
node.childNodesId);
childNodes.forEach((child) => {
if ((child.checked || (includeHalfChecked && child.indeterminate)) && (!leafOnly || (
leafOnly && child.isLeaf))) {
checkedNodes.push(child.data);
}
traverse(child);
});
};
traverse(this);
return checkedNodes;
}
getCheckedKeys(leafOnly = false, includeHalfChecked = false) {
return this.getCheckedNodes(leafOnly, includeHalfChecked).map((data) => (data || {})[this.key]);
}
getHalfCheckedNodes() {
const nodes = [];
const traverse = function(node) {
const childNodes = node.root ? node.root.getChildNodes(node.root.childNodesId) : node.getChildNodes(
node.childNodesId);
childNodes.forEach((child) => {
if (child.indeterminate) {
nodes.push(child.data);
}
traverse(child);
});
};
traverse(this);
return nodes;
}
getHalfCheckedKeys() {
return this.getHalfCheckedNodes().map((data) => (data || {})[this.key]);
}
_getAllNodes() {
const allNodes = [];
const nodesMap = this.nodesMap;
for (let nodeKey in nodesMap) {
if (nodesMap.hasOwnProperty(nodeKey)) {
allNodes.push(nodesMap[nodeKey]);
}
}
return allNodes;
}
updateChildren(key, data) {
const node = this.nodesMap[key];
if (!node) return;
const childNodes = node.getChildNodes(node.childNodesId);
for (let i = childNodes.length - 1; i >= 0; i--) {
const child = childNodes[i];
this.remove(child.data);
}
for (let i = 0, j = data.length; i < j; i++) {
const child = data[i];
this.append(child, node.data);
}
}
_setCheckedKeys(key, leafOnly = false, checkedKeys) {
const allNodes = this._getAllNodes().sort((a, b) => b.level - a.level);
const cache = Object.create(null);
const keys = Object.keys(checkedKeys);
allNodes.forEach(node => node.setChecked(false, false));
for (let i = 0, j = allNodes.length; i < j; i++) {
const node = allNodes[i];
let nodeKey = node.data[key];
if (typeof nodeKey === 'undefined') continue;
nodeKey = nodeKey.toString();
let checked = keys.indexOf(nodeKey) > -1;
if (!checked) {
if (node.checked && !cache[nodeKey]) {
node.setChecked(false, false);
}
continue;
}
let parent = node.getParent(node.parentId);
while (parent && parent.level > 0) {
cache[parent.data[key]] = true;
parent = parent.getParent(parent.parentId);
}
if (node.isLeaf || this.checkStrictly) {
node.setChecked(true, false);
continue;
}
node.setChecked(true, true);
if (leafOnly) {
node.setChecked(false, false);
const traverse = function(node) {
const childNodes = node.getChildNodes(node.childNodesId);
childNodes.forEach((child) => {
if (!child.isLeaf) {
child.setChecked(false, false);
}
traverse(child);
});
};
traverse(node);
}
}
}
setCheckedNodes(array, leafOnly = false) {
const key = this.key;
const checkedKeys = {};
array.forEach((item) => {
checkedKeys[(item || {})[key]] = true;
});
this._setCheckedKeys(key, leafOnly, checkedKeys);
}
setCheckedKeys(keys, leafOnly = false) {
this.defaultCheckedKeys = keys;
const key = this.key;
const checkedKeys = {};
keys.forEach((key) => {
checkedKeys[key] = true;
});
this._setCheckedKeys(key, leafOnly, checkedKeys);
}
setDefaultExpandedKeys(keys) {
keys = keys || [];
this.defaultExpandedKeys = keys;
keys.forEach((key) => {
const node = this.getNode(key);
if (node) node.expand(null, this.autoExpandParent);
});
}
setChecked(data, checked, deep) {
const node = this.getNode(data);
if (node) {
node.setChecked(!!checked, deep);
}
}
getCurrentNode() {
return this.currentNode;
}
setCurrentNode(currentNode) {
const prevCurrentNode = this.currentNode;
if (prevCurrentNode) {
prevCurrentNode.isCurrent = false;
}
this.currentNode = currentNode;
this.currentNode.isCurrent = true;
this.expandCurrentNodeParent && this.currentNode.expand(null, true)
}
setUserCurrentNode(node) {
const key = node[this.key];
const currNode = this.nodesMap[key];
this.setCurrentNode(currNode);
}
setCurrentNodeKey(key) {
if (key === null || key === undefined) {
this.currentNode && (this.currentNode.isCurrent = false);
this.currentNode = null;
return;
}
const node = this.getNode(key);
if (node) {
this.setCurrentNode(node);
}
}
};

View File

@@ -0,0 +1,115 @@
export const NODE_KEY = '$treeNodeId';
export const markNodeData = function(node, data) {
if (!data || data[NODE_KEY]) return;
Object.defineProperty(data, NODE_KEY, {
value: node.id,
enumerable: false,
configurable: false,
writable: false
});
};
export const getNodeKey = function(key, data) {
if (!data) return null;
if (!key) return data[NODE_KEY];
return data[key];
};
export const objectAssign = function(target) {
for (let i = 1, j = arguments.length; i < j; i++) {
let source = arguments[i] || {};
for (let prop in source) {
if (source.hasOwnProperty(prop)) {
let value = source[prop];
if (value !== undefined) {
target[prop] = value;
}
}
}
}
return target;
};
// TODO: use native Array.find, Array.findIndex when IE support is dropped
export const arrayFindIndex = function(arr, pred) {
for (let i = 0; i !== arr.length; ++i) {
if (pred(arr[i])) {
return i;
}
}
return -1;
};
export const getChildState = function(node) {
let all = true;
let none = true;
let allWithoutDisable = true;
for (let i = 0, j = node.length; i < j; i++) {
const n = node[i];
if (n.checked !== true || n.indeterminate) {
all = false;
if (!n.disabled) {
allWithoutDisable = false;
}
}
if (n.checked !== false || n.indeterminate) {
none = false;
}
}
return {
all,
none,
allWithoutDisable,
half: !all && !none
};
};
export const reInitChecked = function(node) {
if (!node || node.childNodesId.length === 0) return;
let childNodes = node.getChildNodes(node.childNodesId);
const {
all,
none,
half
} = getChildState(childNodes);
if (all) {
node.checked = true;
node.indeterminate = false;
} else if (half) {
node.checked = false;
node.indeterminate = true;
} else if (none) {
node.checked = false;
node.indeterminate = false;
}
let parent = node.getParent(node.parentId);
if (!parent || parent.level === 0) return;
if (!node.store().checkStrictly) {
reInitChecked(parent);
}
};
export const getPropertyFromData = function(node, prop) {
const props = node.store().props;
const data = node.data || {};
const config = props[prop];
if (typeof config === 'function') {
return config(data, node);
} else if (typeof config === 'string') {
return data[config];
} else if (typeof config === 'undefined') {
const dataProp = data[prop];
return dataProp === undefined ? '' : dataProp;
}
};
export const isNull = function(v) {
return v === undefined || v === null || v === '';
}

View File

@@ -0,0 +1,63 @@
<template>
<view class="notData-box u-flex-col"
:style="{'padding-top':paddingTop+'rpx','margin-top':marginTop+'rpx','background-color':backgroundColor,'z-index':zIndex}">
<view class="u-flex-col notData-inner">
<image :src="icon" mode="" class="notData-inner-img"></image>
<text class="notData-inner-text">{{$t('common.noData')}}</text>
</view>
</view>
</template>
<script>
import resources from '@/libs/resources.js'
export default {
props: {
paddingTop: {
type: [String, Number],
default: 300
},
marginTop: {
type: [String, Number],
default: 0
},
zIndex: {
type: [String, Number],
default: 999
},
backgroundColor: {
type: String,
default: '#f0f2f6'
}
},
data() {
return {
icon: resources.message.nodata,
}
},
}
</script>
<style lang="scss">
.notData-box {
width: 100%;
height: 100%;
justify-content: center;
align-items: center;
.notData-inner {
width: 154px;
height: 170px;
align-items: center;
.notData-inner-text {
padding: 30rpx 0;
color: #909399;
}
.notData-inner-img {
width: 100%;
height: 100%;
}
}
}
</style>

View File

@@ -0,0 +1,71 @@
<template>
<view class="u-line-1 u-flex select-box" @click="openSelect">
<view class="u-flex content-box">
<view class="content" :style="{textAlign:textAlign,width:type === 'dateTime' ? '100%' : '500prx' }">
<text class="u-line-1" v-if="modelValue">{{modelValue}}</text>
<text v-else class="placeholder-style">{{placeholder}}</text>
</view>
</view>
<view class="u-input__right-icon--select u-input__right-icon__item">
<u-icon :name="selectOpen ? 'arrow-up' : 'arrow-right'" size="26" color="#c0c4cc"></u-icon>
</view>
</view>
</template>
<script>
export default {
props: {
modelValue: {
default: ''
},
textAlign: {
type: String,
default: 'end'
},
placeholder: {
type: String,
default: '请选择'
},
type: {
type: String,
default: ''
},
selectOpen: {
type: Boolean,
default: false
},
},
data() {
return {
}
},
methods: {
openSelect() {
this.$emit('openSelect')
}
}
}
</script>
<style lang="scss">
.select-box {
height: 78rpx;
width: 100%;
justify-content: space-between;
.content-box {
width: 100%;
justify-content: flex-end;
.content {
width: 500rpx;
overflow-y: scroll;
.placeholder-style {
color: rgb(192, 196, 204);
}
}
}
}
</style>

View File

@@ -0,0 +1,101 @@
<template>
<u-popup v-model="showApply" :mode="mode" :height="height" @close="close" :width="width"
:custom-style="customStyle">
<slot></slot>
<view class="tree-main">
<ly-tree :props="prop" :node-key="prop.value" :tree-data="treeData" show-node-icon :defaultExpandAll='true'
ref="tree" @node-click="handleNodeClick" :highlight-current="true" />
</view>
</u-popup>
</template>
<script>
import LyTree from './ly-tree.vue'
let _self;
export default {
components: {
LyTree
},
props: {
type: {
type: String,
default: ''
},
statusBarHeight: {
type: Number,
default: 196
},
show: {
type: Boolean,
default: false
},
treeData: Array,
mode: {
type: String,
default: 'top'
},
height: {
type: String,
default: '600rpx'
},
width: {
type: String,
default: '400rpx'
}
},
data() {
return {
showApply: false,
isReady: false,
prop: {
label: 'fullName',
isLeaf: 'isLeaf',
value: "id",
icon: 'avatar'
},
customStyle: {
// #ifdef MP
'margin-top': '160rpx'
// #endif
// #ifndef MP
'margin-top': '80rpx'
// #endif
}
}
},
watch: {
show: {
handler(val) {
this.showApply = val
},
immediate: true,
},
},
created() {
_self = this
this.isReady = true;
},
computed: {
baseURL() {
return this.define.baseURL
}
},
methods: {
handleNodeClick(obj) {
if (obj.data.type != 1) this.$emit('change', obj.data)
},
close() {
this.$emit('close')
}
}
}
</script>
<style>
page {
padding-top: 80rpx;
}
.ly-tree {
/* padding: 20rpx !important; */
}
</style>

View File

@@ -0,0 +1,377 @@
<template>
<view ref="node" name="LyTreeNode" v-show="node.visible" class="ly-tree-node" :class="{
'is-expanded': expanded,
'is-hidden': !node.visible,
'is-checked': !node.disabled && node.checked
}" role="treeitem" @tap.stop="handleClick">
<view class="ly-tree-node__content" :class="{
'is-current': node.isCurrent && highlightCurrent
}" :style="{
'padding-left': (node.level - 1) * indent + 'px'
}">
<view class="">
<text :class="node.data.icon" class="u-m-r-12"></text>
<text class="ly-tree-node__label u-line-1">{{node.label}}</text>
</view>
<view class="" @tap.stop="handleExpandIconClick">
<u-icon :name="iconName" v-if="node.data.hasChildren"></u-icon>
</view>
</view>
<view v-if="!renderAfterExpand || childNodeRendered" v-show="expanded" class="ly-tree-node__children"
role="group">
<ly-tree-node v-for="cNodeId in node.childNodesId" :nodeId="cNodeId"
:render-after-expand="renderAfterExpand" :show-checkbox="showCheckbox" :show-radio="showRadio"
:check-only-leaf="checkOnlyLeaf" :key="getNodeKey(cNodeId)" :indent="indent" :icon-class="iconClass">
</ly-tree-node>
</view>
</view>
</template>
<script>
import {
getNodeKey
} from './tool/util.js';
export default {
name: 'LyTreeNode',
componentName: 'LyTreeNode',
props: {
nodeId: [Number, String],
renderAfterExpand: {
type: Boolean,
default: true
},
checkOnlyLeaf: {
type: Boolean,
default: false
},
showCheckbox: {
type: Boolean,
default: false
},
showRadio: {
type: Boolean,
default: false
},
indent: Number,
iconClass: String
},
data() {
return {
iconName: 'arrow-down',
node: {
indeterminate: false,
checked: false,
expanded: false
},
expanded: false,
childNodeRendered: false,
oldChecked: null,
oldIndeterminate: null,
highlightCurrent: false
};
},
inject: ['tree'],
computed: {
checkboxVisible() {
if (this.checkOnlyLeaf) {
return this.showCheckbox && this.node.isLeaf;
}
return this.showCheckbox;
},
radioVisible() {
if (this.checkOnlyLeaf) {
return this.showRadio && this.node.isLeaf;
}
return this.showRadio;
}
},
watch: {
'node.indeterminate'(val) {
this.handleSelectChange(this.node.checked, val);
},
'node.checked'(val) {
this.handleSelectChange(val, this.node.indeterminate);
},
'node.expanded'(val) {
this.$nextTick(() => this.expanded = val);
if (val) {
this.childNodeRendered = true;
}
}
},
methods: {
getNodeKey(nodeId) {
let node = this.tree.store.root.getChildNodes([nodeId])[0];
return getNodeKey(this.tree.nodeKey, node.data);
},
handleSelectChange(checked, indeterminate) {
if (this.oldChecked !== checked && this.oldIndeterminate !== indeterminate) {
if (this.checkOnlyLeaf && !this.node.isLeaf) return;
if (this.checkboxVisible) {
const allNodes = this.tree.store._getAllNodes();
this.tree.$emit('check-change', {
checked,
indeterminate,
node: this.node,
data: this.node.data,
checkedall: allNodes.every(item => item.checked)
});
} else {
this.tree.$emit('radio-change', {
checked,
node: this.node,
data: this.node.data,
checkedall: false
});
}
}
if (!this.expanded && this.tree.expandOnCheckNode && checked) {
this.handleExpandIconClick();
}
this.oldChecked = checked;
this.indeterminate = indeterminate;
},
handleClick() {
this.tree.store.setCurrentNode(this.node);
this.tree.$emit('current-change', {
node: this.node,
data: this.tree.store.currentNode ? this.tree.store.currentNode.data : null,
currentNode: this.tree.store.currentNode
});
this.tree.currentNode = this.node;
if (this.tree.expandOnClickNode) {
this.handleExpandIconClick();
}
if (this.tree.checkOnClickNode && !this.node.disabled) {
(this.checkboxVisible || this.radioVisible) && this.handleCheckChange(!this.node.checked);
}
this.tree.$emit('node-click', this.node);
},
handleExpandIconClick() {
if (this.node.isLeaf) return;
if (this.expanded) {
this.tree.$emit('node-collapse', this.node);
this.node.collapse();
this.iconName = 'arrow-down'
} else {
this.node.expand();
this.iconName = 'arrow-up'
// this.tree.$emit('node-expand', this.node);
if (this.tree.accordion) {
// uni.$emit(`${this.tree.elId}-tree-node-expand`, this.node);
}
}
},
handleCheckChange(checked) {
if (this.node.disabled) return;
if (this.checkboxVisible) {
this.node.setChecked(checked, !(this.tree.checkStrictly || this.checkOnlyLeaf));
} else {
this.node.setRadioChecked(checked);
}
this.$nextTick(() => {
this.tree.$emit('check', {
node: this.node,
data: this.node.data,
checkedNodes: this.tree.store.getCheckedNodes(),
checkedKeys: this.tree.store.getCheckedKeys(),
halfCheckedNodes: this.tree.store.getHalfCheckedNodes(),
halfCheckedKeys: this.tree.store.getHalfCheckedKeys()
});
});
uni.$emit('updateKey')
},
handleImageError() {
this.node.icon = this.tree.defaultNodeIcon;
}
},
created() {
if (!this.tree) {
throw new Error('Can not find node\'s tree.');
}
this.node = this.tree.store.nodesMap[this.nodeId];
this.highlightCurrent = this.tree.highlightCurrent;
if (this.node.expanded) {
this.expanded = true;
this.childNodeRendered = true;
}
const props = this.tree.props || {};
const childrenKey = props['children'] || 'children';
this.$watch(`node.data.${childrenKey}`, () => {
this.node.updateChildren();
});
if (this.tree.accordion) {
uni.$on(`${this.tree.elId}-tree-node-expand`, node => {
if (this.node.id !== node.id && this.node.level === node.level) {
this.node.collapse();
}
});
}
},
beforeDestroy() {
this.$parent = null;
}
};
</script>
<style>
.ly-tree-node {
white-space: nowrap;
outline: 0
}
.ly-tree-node__content {
display: flex;
align-items: center;
height: 70rpx;
margin-bottom: 20rpx;
justify-content: space-between;
}
.ly-tree-node__label_box {
display: flex;
flex-direction: column;
}
.ly-tree-node__content.is-current {
background-color: #F5F7FA;
}
.ly-tree-node__content>.ly-tree-node__expand-icon {
padding: 12rpx;
}
.ly-tree-node__checkbox {
display: flex;
margin-right: 16rpx;
width: 40rpx;
height: 40rpx;
}
.ly-tree-node__checkbox>image {
width: 40rpx;
height: 40rpx;
}
.ly-tree-node__expand-icon {
color: #C0C4CC;
font-size: 28rpx;
-webkit-transform: rotate(0);
transform: rotate(0);
-webkit-transition: -webkit-transform .3s ease-in-out;
transition: -webkit-transform .3s ease-in-out;
transition: transform .3s ease-in-out;
transition: transform .3s ease-in-out, -webkit-transform .3s ease-in-out
}
.ly-tree-node__expand-icon.expanded {
-webkit-transform: rotate(90deg);
transform: rotate(90deg)
}
.ly-tree-node__expand-icon.is-leaf {
color: transparent;
}
.ly-tree-node__label {
font-size: 28rpx
}
.ly-tree-node__loading-icon {
margin-right: 16rpx;
font-size: 28rpx;
color: #C0C4CC;
-webkit-animation: rotating 2s linear infinite;
animation: rotating 2s linear infinite
}
.ly-tree-node>.ly-tree-node__children {
overflow: hidden;
background-color: transparent
}
.ly-tree-node>.ly-tree-node__children.collapse-transition {
transition: height .3s ease-in-out;
}
.ly-tree-node.is-expanded>.ly-tree-node__children {
display: block
}
.ly-tree-node_collapse {
overflow: hidden;
padding-top: 0;
padding-bottom: 0;
}
/* lyTree-end */
/* iconfont-start */
@font-face {
font-family: "ly-iconfont";
src: url('data:application/x-font-woff2;charset=utf-8;base64,d09GMgABAAAAAAPsAAsAAAAACKwAAAOeAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHEIGVgCDBgqFDIQPATYCJAMMCwgABCAFhG0HQBtfB8gekiSCdAwUAKgCFMA5Hj7H0PeTlABUr57PVyGqugqzSWJnNwWoWJjx/9rUr4TPL1ZSQpU2mycqwoRwIN3p+MkqMqyEW+OtMBLPSUBb8v//XtWMKTavxYIUsT/Wy1qbQzkBDOYEKGB7dVpPyVqgCnJNwvMvhZl10nMCtQbFoPVhY8ZDncJfF4grbqpQ13AqE52hWqgcOFrEQ6hWnW5VfMCD7Pfjn4WoI6nI/K0bl0MNGPBz0qcflVqYnvCA4vNDPUXGPFCIw8HgtsqiOK9SrW2smm6sVITElWlpISMdVBn8wyMJopLfXg+myZ48KCrSkvj9g37U1ItbXYke4APwXxK3N4TuehyBfmM0I3zbNdt7uk3VnjPtzX0rnIl7z7bZvb/thHohsu9QuykKo+Cws4nL7LsPmI3n2qN9B9upZEIKd4hu0NCKi0rt7fNtdl+I1N25hOJMDQK6odS123tROR7Pg8toEhDaF+kR0TYjxW6M58F5+ZNQOxmZHtE2g+IYjxjlNy/yIRQpCmrgq5R4/3jx8PvT8Ha8d3/xiLnt4EGyaDnznzRv8vpyZ+9TFHf/ntX9e59A+b6+fPHd5+dy0wYHVvHOroWbnWe879O9DnL53bN/gUHuwm28b/n8i/V3ry4E3IoXNqS6Rvs0LhJxeNVjoUkM3LKosU+0a6rh45FVvLt+2oz7Zd53b4QOy7/9snDXHbqVu+A+f8r7PnM2H8kXrWm5c8/vLu7LqRee7HW637mz3kHc5U/RCXf25d7G8tkdgEfwIpzpkknGpaMw3ww55q9Mn9OQNyua/wB/49OOWydn4eL/6roCfjx6FMmcxfJStYRKfd3UwoHiML4rF4uMSK+SvYTuNxMHrpl8yd3Q6v32cAeo/KFaowBJlQHIqo3zi3geKtRZhErVlqDWnOGn67QRKkWpwaw1AkKza5A0egFZszf8In4HFTp9h0rNUQm1NqP1lXUmgyuDBVUlNYi2gHA98FnokUreOZaac1xV1JlMMZGKEs+QdCLVrgynPhUcO0pzzYyUjDAReGSYeBl13YCEIrCpLhOWlGE+mWRD35TQAw8UawRKJVEGQrMAwekCPpaMlpTOz49FmeZwqcREX1t3Ikoo4dMTaQmpBfzhRn9R30uZXTKXKUOSmLSKEQIeYhjqKZcrcIzhMLLRrJMSrA35UF4yGMaWGhPHm733dwJq+Z/NkSJHUXemCirjgpuWrHMD1eC+mQUAAAA=') format('woff2');
}
.ly-iconfont {
font-family: "ly-iconfont" !important;
font-size: 30rpx;
font-style: normal;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
.ly-icon-caret-right:before {
content: "\e8ee";
}
.ly-icon-loading:before {
content: "\e657";
}
/* iconfont-end */
/* animate-start */
@keyframes rotating {
0% {
-webkit-transform: rotateZ(0);
transform: rotateZ(0)
}
100% {
-webkit-transform: rotateZ(360deg);
transform: rotateZ(360deg)
}
}
/* animate-end */
</style>

View File

@@ -0,0 +1,625 @@
<template>
<view>
<template v-if="showLoading">
<view class="ly-loader ly-flex-center">
<view class="ly-loader-inner">加载中...</view>
</view>
</template>
<template v-else>
<view v-if="isEmpty || !visible" class="ly-empty">
{{emptyText}}
</view>
<view :key="updateKey" class="ly-tree" :class="{'is-empty': isEmpty || !visible}" role="tree"
name="LyTreeExpand">
<ly-tree-node v-for="nodeId in childNodesId" :nodeId="nodeId" :render-after-expand="renderAfterExpand"
:show-checkbox="showCheckbox" :show-radio="showRadio" :check-only-leaf="checkOnlyLeaf"
:key="getNodeKey(nodeId)" :indent="indent" :icon-class="iconClass" updateKey="hanldeUpdateKey">
</ly-tree-node>
</view>
</template>
</view>
</template>
<script>
import TreeStore from './model/tree-store.js';
import {
getNodeKey
} from './tool/util.js';
import LyTreeNode from './ly-tree-node.vue';
export default {
name: 'LyTree',
componentName: 'LyTree',
components: {
LyTreeNode
},
data() {
return {
updateKey: new Date().getTime(), // 数据更新的时候,重新渲染树
elId: `ly_${Math.ceil(Math.random() * 10e5).toString(36)}`,
visible: true,
store: {
ready: false
},
currentNode: null,
childNodesId: [],
mathKey: 1
};
},
provide() {
return {
tree: this
}
},
props: {
// 展示数据
treeData: Array,
// 自主控制loading加载避免数据还没获取到的空档出现“暂无数据”字样
ready: {
type: Boolean,
default: true
},
// 内容为空的时候展示的文本
emptyText: {
type: String,
default: '暂无数据'
},
// 是否在第一次展开某个树节点后才渲染其子节点
renderAfterExpand: {
type: Boolean,
default: true
},
// 每个树节点用来作为唯一标识的属性,整棵树应该是唯一的
nodeKey: String,
// 在显示复选框的情况下,是否严格的遵循父子不互相关联的做法,默认为 false
checkStrictly: Boolean,
// 是否默认展开所有节点
defaultExpandAll: {
type: Boolean,
default: true
},
// 切换全部展开、全部折叠
toggleExpendAll: Boolean,
// 是否在点击节点的时候展开或者收缩节点, 默认值为 true如果为 false则只有点箭头图标的时候才会展开或者收缩节点
expandOnClickNode: {
type: Boolean,
default: true
},
// 选中的时候展开节点
expandOnCheckNode: {
type: Boolean,
default: true
},
// 是否在点击节点的时候选中节点,默认值为 false即只有在点击复选框时才会选中节点
checkOnClickNode: Boolean,
checkDescendants: {
type: Boolean,
default: false
},
// 展开子节点的时候是否自动展开父节点
autoExpandParent: {
type: Boolean,
default: true
},
// 默认勾选的节点的 key 的数组
defaultCheckedKeys: Array,
// 默认展开的节点的 key 的数组
defaultExpandedKeys: Array,
// 是否展开当前节点的父节点
expandCurrentNodeParent: Boolean,
// 当前选中的节点
currentNodeKey: [String, Number],
// 是否最后一层叶子节点才显示单选/多选框
checkOnlyLeaf: {
type: Boolean,
default: false
},
// 节点是否可被选择
showCheckbox: {
type: Boolean,
default: false
},
// 节点单选
showRadio: {
type: Boolean,
default: false
},
// 配置选项
props: {
type: [Object, Function],
default () {
return {
children: 'children', // 指定子树为节点对象的某个属性值
label: 'label', // 指定节点标签为节点对象的某个属性值
disabled: 'disabled' // 指定节点选择框是否禁用为节点对象的某个属性值
};
}
},
// 是否懒加载子节点,需与 load 方法结合使用
lazy: {
type: Boolean,
default: false
},
// 是否高亮当前选中节点,默认值是 false
highlightCurrent: Boolean,
// 加载子树数据的方法,仅当 lazy 属性为true 时生效
load: Function,
// 对树节点进行筛选时执行的方法,返回 true 表示这个节点可以显示,返回 false 则表示这个节点会被隐藏
filterNodeMethod: Function,
// 搜索时是否展示匹配项的所有子节点
childVisibleForFilterNode: {
type: Boolean,
default: false
},
// 是否每次只打开一个同级树节点展开
accordion: Boolean,
// 相邻级节点间的水平缩进,单位为像素
indent: {
type: Number,
default: 18
},
// 自定义树节点的展开图标
iconClass: String,
// 是否显示节点图标如果配置为true,需要配置props中对应的图标属性名称
showNodeIcon: {
type: Boolean,
default: false
},
// 当节点图标显示出错时,显示的默认图标
defaultNodeIcon: {
type: String,
default: ''
},
// 如果数据量较大建议不要在node节点中添加parent属性会造成性能损耗
isInjectParentInNode: {
type: Boolean,
default: false
}
},
computed: {
isEmpty() {
if (this.store.root) {
const childNodes = this.store.root.getChildNodes(this.childNodesId);
return !childNodes || childNodes.length === 0 || childNodes.every(({
visible
}) => !visible);
}
return true;
},
showLoading() {
//不要删除
const a = this.mathKey
return !(this.store.getReady() && this.ready);
}
},
watch: {
toggleExpendAll(newVal) {
this.store.toggleExpendAll(newVal);
},
defaultCheckedKeys(newVal) {
this.store.setDefaultCheckedKey(newVal);
},
defaultExpandedKeys(newVal) {
this.store.defaultExpandedKeys = newVal;
this.store.setDefaultExpandedKeys(newVal);
},
checkStrictly(newVal) {
this.store.checkStrictly = newVal || this.checkOnlyLeaf;
},
'store.root.childNodesId'(newVal) {
this.childNodesId = newVal;
},
'store.root.visible'(newVal) {
this.visible = newVal;
},
childNodesId() {
this.$nextTick(() => {
this.$emit('ly-tree-render-completed');
});
},
treeData: {
handler(newVal) {
this.updateKey = new Date().getTime();
this.store.setData(newVal);
},
deep: true
}
},
methods: {
/*
* @description 对树节点进行筛选操作
* @method filter
* @param {all} value 在 filter-node-method 中作为第一个参数
* @param {Object} data 搜索指定节点的节点数据不传代表搜索所有节点假如要搜索A节点下面的数据那么nodeData代表treeData中A节点的数据
*/
filter(value, data) {
if (!this.filterNodeMethod) throw new Error('[Tree] filterNodeMethod is required when filter');
this.store.filter(value, data);
this.handleUpdateKey()
},
handleUpdateKey() {
this.updateKey = new Date().getTime();
},
/*
* @description 获取节点的唯一标识符
* @method getNodeKey
* @param {String, Number} nodeId
* @return {String, Number} 匹配到的数据中的某一项数据
*/
getNodeKey(nodeId) {
let node = this.store.root.getChildNodes([nodeId])[0];
return getNodeKey(this.nodeKey, node.data);
},
/*
* @description 获取节点路径
* @method getNodePath
* @param {Object} data 节点数据
* @return {Array} 路径数组
*/
getNodePath(data) {
return this.store.getNodePath(data);
},
/*
* @description 若节点可被选择(即 show-checkbox 为 true则返回目前被选中的节点所组成的数组
* @method getCheckedNodes
* @param {Boolean} leafOnly 是否只是叶子节点默认false
* @param {Boolean} includeHalfChecked 是否包含半选节点默认false
* @return {Array} 目前被选中的节点所组成的数组
*/
getCheckedNodes(leafOnly, includeHalfChecked) {
return this.store.getCheckedNodes(leafOnly, includeHalfChecked);
},
/*
* @description 若节点可被选择(即 show-checkbox 为 true则返回目前被选中的节点的 key 所组成的数组
* @method getCheckedKeys
* @param {Boolean} leafOnly 是否只是叶子节点默认false,若为 true 则仅返回被选中的叶子节点的 keys
* @param {Boolean} includeHalfChecked 是否返回indeterminate为true的节点默认false
* @return {Array} 目前被选中的节点所组成的数组
*/
getCheckedKeys(leafOnly, includeHalfChecked) {
return this.store.getCheckedKeys(leafOnly, includeHalfChecked);
},
/*
* @description 获取当前被选中节点的 data若没有节点被选中则返回 null
* @method getCurrentNode
* @return {Object} 当前被选中节点的 data若没有节点被选中则返回 null
*/
getCurrentNode() {
const currentNode = this.store.getCurrentNode();
return currentNode ? currentNode.data : null;
},
/*
* @description 获取当前被选中节点的 key若没有节点被选中则返回 null
* @method getCurrentKey
* @return {all} 当前被选中节点的 key 若没有节点被选中则返回 null
*/
getCurrentKey() {
const currentNode = this.getCurrentNode();
return currentNode ? currentNode[this.nodeKey] : null;
},
/*
* @description 设置全选/取消全选
* @method setCheckAll
* @param {Boolean} isCheckAll 选中状态,默认为true
*/
setCheckAll(isCheckAll = true) {
if (this.showRadio) throw new Error(
'You set the "show-radio" property, so you cannot select all nodes');
if (!this.showCheckbox) console.warn(
'You have not set the property "show-checkbox". Please check your settings');
this.store.setCheckAll(isCheckAll);
},
/*
* @description 设置目前勾选的节点
* @method setCheckedNodes
* @param {Array} nodes 接收勾选节点数据的数组
* @param {Boolean} leafOnly 是否只是叶子节点, 若为 true 则仅设置叶子节点的选中状态,默认值为 false
*/
setCheckedNodes(nodes, leafOnly) {
this.store.setCheckedNodes(nodes, leafOnly);
},
/*
* @description 通过 keys 设置目前勾选的节点
* @method setCheckedKeys
* @param {Array} keys 勾选节点的 key 的数组
* @param {Boolean} leafOnly 是否只是叶子节点, 若为 true 则仅设置叶子节点的选中状态,默认值为 false
*/
setCheckedKeys(keys, leafOnly) {
if (!this.nodeKey) throw new Error('[Tree] nodeKey is required in setCheckedKeys');
this.store.setCheckedKeys(keys, leafOnly);
this.handleUpdateKey()
},
/*
* @description 通过 key / data 设置某个节点的勾选状态
* @method setChecked
* @param {all} data 勾选节点的 key 或者 data
* @param {Boolean} checked 节点是否选中
* @param {Boolean} deep 是否设置子节点 ,默认为 false
*/
setChecked(data, checked, deep) {
this.store.setChecked(data, checked, deep);
},
/*
* @description 若节点可被选择(即 show-checkbox 为 true则返回目前半选中的节点所组成的数组
* @method getHalfCheckedNodes
* @return {Array} 目前半选中的节点所组成的数组
*/
getHalfCheckedNodes() {
return this.store.getHalfCheckedNodes();
},
/*
* @description 若节点可被选择(即 show-checkbox 为 true则返回目前半选中的节点的 key 所组成的数组
* @method getHalfCheckedKeys
* @return {Array} 目前半选中的节点的 key 所组成的数组
*/
getHalfCheckedKeys() {
return this.store.getHalfCheckedKeys();
},
/*
* @description 通过 node 设置某个节点的当前选中状态
* @method setCurrentNode
* @param {Object} node 待被选节点的 node
*/
setCurrentNode(node) {
if (!this.nodeKey) throw new Error('[Tree] nodeKey is required in setCurrentNode');
this.store.setUserCurrentNode(node);
},
/*
* @description 通过 key 设置某个节点的当前选中状态
* @method setCurrentKey
* @param {all} key 待被选节点的 key若为 null 则取消当前高亮的节点
*/
setCurrentKey(key) {
if (!this.nodeKey) throw new Error('[Tree] nodeKey is required in setCurrentKey');
this.store.setCurrentNodeKey(key);
},
/*
* @description 根据 data 或者 key 拿到 Tree 组件中的 node
* @method getNode
* @param {all} data 要获得 node 的 key 或者 data
*/
getNode(data) {
return this.store.getNode(data);
},
/*
* @description 删除 Tree 中的一个节点
* @method remove
* @param {all} data 要删除的节点的 data 或者 node
*/
remove(data) {
this.store.remove(data);
},
/*
* @description 为 Tree 中的一个节点追加一个子节点
* @method append
* @param {Object} data 要追加的子节点的 data
* @param {Object} parentNode 子节点的 parent 的 data、key 或者 node
*/
append(data, parentNode) {
this.store.append(data, parentNode);
},
/*
* @description 为 Tree 的一个节点的前面增加一个节点
* @method insertBefore
* @param {Object} data 要增加的节点的 data
* @param {all} refNode 要增加的节点的后一个节点的 data、key 或者 node
*/
insertBefore(data, refNode) {
this.store.insertBefore(data, refNode);
},
/*
* @description 为 Tree 的一个节点的后面增加一个节点
* @method insertAfter
* @param {Object} data 要增加的节点的 data
* @param {all} refNode 要增加的节点的前一个节点的 data、key 或者 node
*/
insertAfter(data, refNode) {
this.store.insertAfter(data, refNode);
},
/*
* @description 通过 keys 设置节点子元素
* @method updateKeyChildren
* @param {String, Number} key 节点 key
* @param {Object} data 节点数据的数组
*/
updateKeyChildren(key, data) {
if (!this.nodeKey) throw new Error('[Tree] nodeKey is required in updateKeyChild');
this.store.updateChildren(key, data);
}
},
created() {
this.isTree = true;
let props = this.props;
if (typeof this.props === 'function') props = this.props();
if (typeof props !== 'object') throw new Error('props must be of object type.');
this.store = new TreeStore({
key: this.nodeKey,
data: this.treeData,
lazy: this.lazy,
props: props,
load: this.load,
showCheckbox: this.showCheckbox,
showRadio: this.showRadio,
currentNodeKey: this.currentNodeKey,
checkStrictly: this.checkStrictly || this.checkOnlyLeaf,
checkDescendants: this.checkDescendants,
expandOnCheckNode: this.expandOnCheckNode,
defaultCheckedKeys: this.defaultCheckedKeys,
defaultExpandedKeys: this.defaultExpandedKeys,
expandCurrentNodeParent: this.expandCurrentNodeParent,
autoExpandParent: this.autoExpandParent,
defaultExpandAll: this.defaultExpandAll,
filterNodeMethod: this.filterNodeMethod,
childVisibleForFilterNode: this.childVisibleForFilterNode,
showNodeIcon: this.showNodeIcon,
isInjectParentInNode: this.isInjectParentInNode
});
this.childNodesId = this.store.root.childNodesId;
uni.$on(`updateKey`, () => {
this.handleUpdateKey()
this.mathKey++
});
},
beforeDestroy() {
if (this.accordion) {
uni.$off(`${this.elId}-tree-node-expand`)
}
uni.$off('updateKey')
}
};
</script>
<style>
.ly-tree {
position: relative;
cursor: default;
background: #FFF;
color: #606266;
padding: 30rpx;
}
.ly-tree.is-empty {
background: transparent;
}
/* lyEmpty-start */
.ly-empty {
width: 100%;
display: flex;
justify-content: center;
/* #ifdef MP-WEIXIN */
margin-top: 250rpx;
/* #endif */
/* #ifndef MP-WEIXIN */
margin-top: 100rpx;
/* #endif */
}
/* lyEmpty-end */
/* lyLoader-start */
.ly-loader {
margin-top: 100rpx;
display: flex;
align-items: center;
justify-content: center;
}
.ly-loader-inner,
.ly-loader-inner:before,
.ly-loader-inner:after {
background: #efefef;
animation: load 1s infinite ease-in-out;
width: .5em;
height: 1em;
}
.ly-loader-inner:before,
.ly-loader-inner:after {
position: absolute;
top: 0;
content: '';
}
.ly-loader-inner:before {
left: -1em;
}
.ly-loader-inner {
text-indent: -9999em;
position: relative;
font-size: 22rpx;
animation-delay: 0.16s;
}
.ly-loader-inner:after {
left: 1em;
animation-delay: 0.32s;
}
/* lyLoader-end */
@keyframes load {
0%,
80%,
100% {
box-shadow: 0 0 #efefef;
height: 1em;
}
40% {
box-shadow: 0 -1.5em #efefef;
height: 1.5em;
}
}
</style>

View File

@@ -0,0 +1,538 @@
import {
markNodeData,
objectAssign,
arrayFindIndex,
getChildState,
reInitChecked,
getPropertyFromData,
isNull,
NODE_KEY
} from '../tool/util';
const getStore = function(store) {
let thisStore = store;
return function() {
return thisStore;
}
}
let nodeIdSeed = 0;
export default class Node {
constructor(options) {
this.time = new Date().getTime();
this.id = nodeIdSeed++;
this.text = null;
this.checked = false;
this.indeterminate = false;
this.data = null;
this.expanded = false;
this.parentId = null;
this.visible = true;
this.isCurrent = false;
for (let name in options) {
if (options.hasOwnProperty(name)) {
if (name === 'store') {
this.store = getStore(options[name]);
} else {
this[name] = options[name];
}
}
}
if (!this.store()) {
throw new Error('[Node]store is required!');
}
// internal
this.level = 0;
this.loaded = false;
this.childNodesId = [];
this.loading = false;
this.label = getPropertyFromData(this, 'label');
this.key = this._getKey();
this.disabled = getPropertyFromData(this, 'disabled');
this.nextSibling = null;
this.previousSibling = null;
this.icon = '';
this._handleParentAndLevel();
this._handleProps();
this._handleExpand();
this._handleCurrent();
if (this.store().lazy) {
this.store()._initDefaultCheckedNode(this);
}
this.updateLeafState();
}
_getKey() {
if (!this.data || Array.isArray(this.data)) return null;
if (typeof this.data === 'object') {
const nodeKey = this.store().key;
const key = this.data[nodeKey];
if (typeof key === 'undefined') {
throw new Error(`您配置的node-key为"${nodeKey}",但数据中并未找到对应"${nodeKey}"属性的值请检查node-key的配置是否合理`)
}
return key;
}
throw new Error('不合法的data数据');
}
_handleParentAndLevel() {
if (this.parentId !== null) {
let parent = this.getParent(this.parentId);
if (this.store().isInjectParentInNode) {
this.parent = parent;
}
// 由于这里做了修改默认第一个对象不会被注册到nodesMap中所以找不到parent会报错所以默认parent的level是0
if (!parent) {
parent = {
level: 0
}
} else {
const parentChildNodes = parent.getChildNodes(parent.childNodesId);
const index = parent.childNodesId.indexOf(this.key);
this.nextSibling = index > -1 ? parentChildNodes[index + 1] : null;
this.previousSibling = index > 0 ? parentChildNodes[index - 1] : null;
}
this.level = parent.level + 1;
}
}
_handleProps() {
const props = this.store().props;
if (this.store().showNodeIcon) {
if (props && typeof props.icon !== 'undefined') {
this.icon = getPropertyFromData(this, 'icon');
} else {
console.warn('请配置props属性中的"icon"字段')
}
}
this.store().registerNode(this);
if (props && typeof props.isLeaf !== 'undefined') {
const isLeaf = getPropertyFromData(this, 'isLeaf');
if (typeof isLeaf === 'boolean') {
this.isLeafByUser = isLeaf;
}
}
}
_handleExpand() {
if (this.store().lazy !== true && this.data) {
this.setData(this.data);
if (this.store().defaultExpandAll) {
this.expanded = true;
}
} else if (this.level > 0 && this.store().lazy && this.store().defaultExpandAll) {
this.expand();
}
if (!Array.isArray(this.data)) {
markNodeData(this, this.data);
}
if (!this.data) return;
const defaultExpandedKeys = this.store().defaultExpandedKeys;
const key = this.store().key;
if (key && defaultExpandedKeys && defaultExpandedKeys.indexOf(this.key) !== -1) {
this.expand(null, this.store().autoExpandparent);
}
}
_handleCurrent() {
const key = this.store().key;
if (key && this.store().currentNodeKey !== undefined && this.key === this.store().currentNodeKey) {
this.store().currentNode = this;
this.store().currentNode.isCurrent = true;
}
}
destroyStore() {
getStore(null)
}
setData(data) {
if (!Array.isArray(data)) {
markNodeData(this, data);
}
this.data = data;
this.childNodesId = [];
let children;
if (this.level === 0 && Array.isArray(this.data)) {
children = this.data;
} else {
children = getPropertyFromData(this, 'children') || [];
}
for (let i = 0, j = children.length; i < j; i++) {
this.insertChild({
data: children[i]
});
}
}
contains(target, deep = true) {
const walk = function(parent) {
const children = parent.getChildNodes(parent.childNodesId) || [];
let result = false;
for (let i = 0, j = children.length; i < j; i++) {
const child = children[i];
if (child === target || (deep && walk(child))) {
result = true;
break;
}
}
return result;
};
return walk(this);
}
remove() {
if (this.parentId !== null) {
const parent = this.getParent(this.parentId);
parent.removeChild(this);
}
}
insertChild(child, index, batch) {
if (!child) throw new Error('insertChild error: child is required.');
if (!(child instanceof Node)) {
if (!batch) {
const children = this.getChildren(true);
if (children.indexOf(child.data) === -1) {
if (typeof index === 'undefined' || index < 0) {
children.push(child.data);
} else {
children.splice(index, 0, child.data);
}
}
}
objectAssign(child, {
parentId: isNull(this.key) ? '' : this.key,
store: this.store()
});
child = new Node(child);
}
child.level = this.level + 1;
if (typeof index === 'undefined' || index < 0) {
this.childNodesId.push(child.key);
} else {
this.childNodesId.splice(index, 0, child.key);
}
this.updateLeafState();
}
insertBefore(child, ref) {
let index;
if (ref) {
index = this.childNodesId.indexOf(ref.id);
}
this.insertChild(child, index);
}
insertAfter(child, ref) {
let index;
if (ref) {
index = this.childNodesId.indexOf(ref.id);
if (index !== -1) index += 1;
}
this.insertChild(child, index);
}
removeChild(child) {
const children = this.getChildren() || [];
const dataIndex = children.indexOf(child.data);
if (dataIndex > -1) {
children.splice(dataIndex, 1);
}
const index = this.childNodesId.indexOf(child.key);
if (index > -1) {
this.store() && this.store().deregisterNode(child);
child.parentId = null;
this.childNodesId.splice(index, 1);
}
this.updateLeafState();
}
removeChildByData(data) {
let targetNode = null;
for (let i = 0; i < this.childNodesId.length; i++) {
let node = this.getChildNodes(this.childNodesId);
if (node[i].data === data) {
targetNode = node[i];
break;
}
}
if (targetNode) {
this.removeChild(targetNode);
}
}
// 为了避免APP端parent嵌套结构导致报错这里parent需要从nodesMap中获取
getParent(parentId) {
try {
if (!parentId.toString()) return null;
return this.store().nodesMap[parentId];
} catch (error) {
return null;
}
}
// 为了避免APP端childNodes嵌套结构导致报错这里childNodes需要从nodesMap中获取
getChildNodes(childNodesId) {
let childNodes = [];
if (childNodesId.length === 0) return childNodes;
childNodesId.forEach((key) => {
childNodes.push(this.store().nodesMap[key]);
})
return childNodes;
}
expand(callback, expandparent) {
const done = () => {
if (expandparent) {
let parent = this.getParent(this.parentId);
while (parent && parent.level > 0) {
parent.expanded = true;
parent = this.getParent(parent.parentId);
}
}
this.expanded = true;
if (callback) callback();
};
if (this.shouldLoadData()) {
this.loadData(function(data) {
if (Array.isArray(data)) {
if (this.checked) {
this.setChecked(true, true);
} else if (!this.store().checkStrictly) {
reInitChecked(this);
}
done();
}
});
} else {
done();
}
}
doCreateChildren(array, defaultProps = {}) {
array.forEach((item) => {
this.insertChild(objectAssign({
data: item
}, defaultProps), undefined, true);
});
}
collapse() {
this.expanded = false;
}
shouldLoadData() {
return this.store().lazy === true && this.store().load && !this.loaded;
}
updateLeafState() {
if (this.store().lazy === true && this.loaded !== true && typeof this.isLeafByUser !== 'undefined') {
this.isLeaf = this.isLeafByUser;
return;
}
const childNodesId = this.childNodesId;
if (!this.store().lazy || (this.store().lazy === true && this.loaded === true)) {
this.isLeaf = !childNodesId || childNodesId.length === 0;
return;
}
this.isLeaf = false;
}
setChecked(value, deep, recursion, passValue) {
this.indeterminate = value === 'half';
this.checked = value === true;
if (this.checked && this.store().expandOnCheckNode) {
this.expand(null, true)
}
if (this.store().checkStrictly) return;
if (this.store().showRadio) return;
if (!(this.shouldLoadData() && !this.store().checkDescendants)) {
let childNodes = this.getChildNodes(this.childNodesId);
let {
all,
allWithoutDisable
} = getChildState(childNodes);
if (!this.isLeaf && (!all && allWithoutDisable)) {
this.checked = false;
value = false;
}
const handleDescendants = () => {
if (deep) {
let childNodes = this.getChildNodes(this.childNodesId)
for (let i = 0, j = childNodes.length; i < j; i++) {
const child = childNodes[i];
passValue = passValue || value !== false;
const isCheck = child.disabled ? child.checked : passValue;
child.setChecked(isCheck, deep, true, passValue);
}
const {
half,
all
} = getChildState(childNodes);
if (!all) {
this.checked = all;
this.indeterminate = half;
}
}
};
if (this.shouldLoadData()) {
this.loadData(() => {
handleDescendants();
reInitChecked(this);
}, {
checked: value !== false
});
return;
} else {
handleDescendants();
}
}
if (!this.parentId) return;
let parent = this.getParent(this.parentId);
if (parent && parent.level === 0) return;
if (!recursion) {
reInitChecked(parent);
}
}
setRadioChecked(value) {
const allNodes = this.store()._getAllNodes().sort((a, b) => b.level - a.level);
allNodes.forEach(node => node.setChecked(false, false));
this.checked = value === true;
}
getChildren(forceInit = false) {
if (this.level === 0) return this.data;
const data = this.data;
if (!data) return null;
const props = this.store().props;
let children = 'children';
if (props) {
children = props.children || 'children';
}
if (data[children] === undefined) {
data[children] = null;
}
if (forceInit && !data[children]) {
data[children] = [];
}
return data[children];
}
updateChildren() {
let childNodes = this.getChildNodes(this.childNodesId);
const newData = this.getChildren() || [];
const oldData = childNodes.map((node) => node.data);
const newDataMap = {};
const newNodes = [];
newData.forEach((item, index) => {
const key = item[NODE_KEY];
const isNodeExists = !!key && arrayFindIndex(oldData, data => data[NODE_KEY] === key) >= 0;
if (isNodeExists) {
newDataMap[key] = {
index,
data: item
};
} else {
newNodes.push({
index,
data: item
});
}
});
if (!this.store().lazy) {
oldData.forEach((item) => {
if (!newDataMap[item[NODE_KEY]]) this.removeChildByData(item);
});
}
newNodes.forEach(({
index,
data
}) => {
this.insertChild({
data
}, index);
});
this.updateLeafState();
}
loadData(callback, defaultProps = {}) {
if (this.store().lazy === true &&
this.store().load && !this.loaded &&
(!this.loading || Object.keys(defaultProps).length)
) {
this.loading = true;
const resolve = (children) => {
this.loaded = true;
this.loading = false;
this.childNodesId = [];
this.doCreateChildren(children, defaultProps);
this.updateLeafState();
callback && callback.call(this, children);
};
this.store().load(this, resolve);
} else {
callback && callback.call(this);
}
}
}

View File

@@ -0,0 +1,428 @@
import Node from './node';
import {
getNodeKey,
getPropertyFromData
} from '../tool/util';
export default class TreeStore {
constructor(options) {
this.ready = false;
this.currentNode = null;
this.currentNodeKey = null;
Object.assign(this, options);
if (!this.key) {
throw new Error('[Tree] nodeKey is required');
}
this.nodesMap = {};
this.root = new Node({
data: this.data,
store: this
});
if (this.lazy && this.load) {
const loadFn = this.load;
loadFn(this.root, (data) => {
this.root.doCreateChildren(data);
this._initDefaultCheckedNodes();
this.ready = true;
uni.$emit('updateKey') //加了异步才会展示数据
});
} else {
this._initDefaultCheckedNodes();
this.ready = true;
}
}
getReady() {
return this.ready
}
filter(value, data) {
const filterNodeMethod = this.filterNodeMethod;
const lazy = this.lazy;
const _self = this;
const traverse = function(node) {
const childNodes = node.root ? node.root.getChildNodes(node.root.childNodesId) : node.getChildNodes(
node.childNodesId);
childNodes.forEach((child) => {
if (data && typeof data === 'object') {
let nodePath = _self.getNodePath(child.data);
if (!nodePath.some(pathItem => pathItem[_self.key] === data[_self.key])) {
child.visible = false;
traverse(child);
return;
}
}
if (_self.childVisibleForFilterNode) {
let parent = child.getParent(child.parentId);
child.visible = filterNodeMethod.call(child, value, child.data, child) || (parent &&
parent.visible);
} else {
child.visible = filterNodeMethod.call(child, value, child.data, child);
}
traverse(child);
});
if (!node.visible && childNodes.length) {
let allHidden = true;
allHidden = !childNodes.some(child => child.visible);
if (node.root) {
node.root.visible = allHidden === false;
} else {
node.visible = allHidden === false;
}
}
if (!value) return;
if (node.visible && !node.isLeaf && !lazy) node.expand();
};
traverse(this);
}
setData(newVal) {
const instanceChanged = newVal !== this.root.data;
if (instanceChanged) {
this.root.setData(newVal);
this._initDefaultCheckedNodes();
} else {
this.root.updateChildren();
}
}
getNode(data) {
if (data instanceof Node) return data;
const key = typeof data !== 'object' ? data : getNodeKey(this.key, data);
if (!key) return null;
return this.nodesMap[key] || null;
}
insertBefore(data, refData) {
const refNode = this.getNode(refData);
let parent = refNode.getParent(refNode.parentId);
parent.insertBefore({
data
}, refNode);
}
insertAfter(data, refData) {
const refNode = this.getNode(refData);
let parent = refNode.getParent(refNode.parentId);
parent.insertAfter({
data
}, refNode);
}
remove(data) {
const node = this.getNode(data);
if (node && node.parentId !== null) {
let parent = node.getParent(node.parentId);
if (node === this.currentNode) {
this.currentNode = null;
}
parent.removeChild(node);
}
}
append(data, parentData) {
const parentNode = parentData ? this.getNode(parentData) : this.root;
if (parentNode) {
parentNode.insertChild({
data
});
}
}
_initDefaultCheckedNodes() {
const defaultCheckedKeys = this.defaultCheckedKeys || [];
const nodesMap = this.nodesMap;
let checkedKeyfromData = [];
let totalCheckedKeys = []
for (let key in nodesMap) {
let checked = getPropertyFromData(nodesMap[key], 'checked') || false;
checked && checkedKeyfromData.push(key);
}
totalCheckedKeys = Array.from(new Set([...defaultCheckedKeys, ...checkedKeyfromData]));
totalCheckedKeys.forEach((checkedKey) => {
const node = nodesMap[checkedKey];
if (node) {
node.setChecked(true, !this.checkStrictly);
}
});
}
_initDefaultCheckedNode(node) {
const defaultCheckedKeys = this.defaultCheckedKeys || [];
if (defaultCheckedKeys.indexOf(node.key) !== -1) {
node.setChecked(true, !this.checkStrictly);
}
}
toggleExpendAll(isExpandAll) {
const allNodes = this._getAllNodes();
allNodes.forEach(item => {
const node = this.getNode(item.key);
if (node) isExpandAll ? node.expand() : node.collapse();
});
}
setCheckAll(isCkeckAll) {
const allNodes = this._getAllNodes();
allNodes.forEach(item => {
item.setChecked(isCkeckAll, false);
});
}
setDefaultCheckedKey(newVal) {
if (newVal !== this.defaultCheckedKeys) {
this.defaultCheckedKeys = newVal;
this._initDefaultCheckedNodes();
}
}
registerNode(node) {
const key = this.key;
if (!key || !node || !node.data) return;
const nodeKey = node.key;
if (nodeKey !== undefined) this.nodesMap[node.key] = node;
}
deregisterNode(node) {
const key = this.key;
if (!key || !node || !node.data) return;
let childNodes = node.getChildNodes(node.childNodesId);
childNodes.forEach(child => {
this.deregisterNode(child);
});
delete this.nodesMap[node.key];
}
getNodePath(data) {
if (!this.key) throw new Error('[Tree] nodeKey is required in getNodePath');
const node = this.getNode(data);
if (!node) return [];
const path = [node.data];
let parent = node.getParent(node.parentId);
while (parent && parent !== this.root) {
path.push(parent.data);
parent = parent.getParent(parent.parentId);
}
return path.reverse();
}
getCheckedNodes(leafOnly = false, includeHalfChecked = false) {
const checkedNodes = [];
const traverse = function(node) {
const childNodes = node.root ? node.root.getChildNodes(node.root.childNodesId) : node.getChildNodes(
node.childNodesId);
childNodes.forEach((child) => {
if ((child.checked || (includeHalfChecked && child.indeterminate)) && (!leafOnly || (
leafOnly && child.isLeaf))) {
checkedNodes.push(child.data);
}
traverse(child);
});
};
traverse(this);
return checkedNodes;
}
getCheckedKeys(leafOnly = false, includeHalfChecked = false) {
return this.getCheckedNodes(leafOnly, includeHalfChecked).map((data) => (data || {})[this.key]);
}
getHalfCheckedNodes() {
const nodes = [];
const traverse = function(node) {
const childNodes = node.root ? node.root.getChildNodes(node.root.childNodesId) : node.getChildNodes(
node.childNodesId);
childNodes.forEach((child) => {
if (child.indeterminate) {
nodes.push(child.data);
}
traverse(child);
});
};
traverse(this);
return nodes;
}
getHalfCheckedKeys() {
return this.getHalfCheckedNodes().map((data) => (data || {})[this.key]);
}
_getAllNodes() {
const allNodes = [];
const nodesMap = this.nodesMap;
for (let nodeKey in nodesMap) {
if (nodesMap.hasOwnProperty(nodeKey)) {
allNodes.push(nodesMap[nodeKey]);
}
}
return allNodes;
}
updateChildren(key, data) {
const node = this.nodesMap[key];
if (!node) return;
const childNodes = node.getChildNodes(node.childNodesId);
for (let i = childNodes.length - 1; i >= 0; i--) {
const child = childNodes[i];
this.remove(child.data);
}
for (let i = 0, j = data.length; i < j; i++) {
const child = data[i];
this.append(child, node.data);
}
}
_setCheckedKeys(key, leafOnly = false, checkedKeys) {
const allNodes = this._getAllNodes().sort((a, b) => b.level - a.level);
const cache = Object.create(null);
const keys = Object.keys(checkedKeys);
allNodes.forEach(node => node.setChecked(false, false));
for (let i = 0, j = allNodes.length; i < j; i++) {
const node = allNodes[i];
let nodeKey = node.data[key];
if (typeof nodeKey === 'undefined') continue;
nodeKey = nodeKey.toString();
let checked = keys.indexOf(nodeKey) > -1;
if (!checked) {
if (node.checked && !cache[nodeKey]) {
node.setChecked(false, false);
}
continue;
}
let parent = node.getParent(node.parentId);
while (parent && parent.level > 0) {
cache[parent.data[key]] = true;
parent = parent.getParent(parent.parentId);
}
if (node.isLeaf || this.checkStrictly) {
node.setChecked(true, false);
continue;
}
node.setChecked(true, true);
if (leafOnly) {
node.setChecked(false, false);
const traverse = function(node) {
const childNodes = node.getChildNodes(node.childNodesId);
childNodes.forEach((child) => {
if (!child.isLeaf) {
child.setChecked(false, false);
}
traverse(child);
});
};
traverse(node);
}
}
}
setCheckedNodes(array, leafOnly = false) {
const key = this.key;
const checkedKeys = {};
array.forEach((item) => {
checkedKeys[(item || {})[key]] = true;
});
this._setCheckedKeys(key, leafOnly, checkedKeys);
}
setCheckedKeys(keys, leafOnly = false) {
this.defaultCheckedKeys = keys;
const key = this.key;
const checkedKeys = {};
keys.forEach((key) => {
checkedKeys[key] = true;
});
this._setCheckedKeys(key, leafOnly, checkedKeys);
}
setDefaultExpandedKeys(keys) {
keys = keys || [];
this.defaultExpandedKeys = keys;
keys.forEach((key) => {
const node = this.getNode(key);
if (node) node.expand(null, this.autoExpandParent);
});
}
setChecked(data, checked, deep) {
const node = this.getNode(data);
if (node) {
node.setChecked(!!checked, deep);
}
}
getCurrentNode() {
return this.currentNode;
}
setCurrentNode(currentNode) {
const prevCurrentNode = this.currentNode;
if (prevCurrentNode) {
prevCurrentNode.isCurrent = false;
}
this.currentNode = currentNode;
this.currentNode.isCurrent = true;
this.expandCurrentNodeParent && this.currentNode.expand(null, true)
}
setUserCurrentNode(node) {
const key = node[this.key];
const currNode = this.nodesMap[key];
this.setCurrentNode(currNode);
}
setCurrentNodeKey(key) {
if (key === null || key === undefined) {
this.currentNode && (this.currentNode.isCurrent = false);
this.currentNode = null;
return;
}
const node = this.getNode(key);
if (node) {
this.setCurrentNode(node);
}
}
};

View File

@@ -0,0 +1,115 @@
export const NODE_KEY = '$treeNodeId';
export const markNodeData = function(node, data) {
if (!data || data[NODE_KEY]) return;
Object.defineProperty(data, NODE_KEY, {
value: node.id,
enumerable: false,
configurable: false,
writable: false
});
};
export const getNodeKey = function(key, data) {
if (!data) return null;
if (!key) return data[NODE_KEY];
return data[key];
};
export const objectAssign = function(target) {
for (let i = 1, j = arguments.length; i < j; i++) {
let source = arguments[i] || {};
for (let prop in source) {
if (source.hasOwnProperty(prop)) {
let value = source[prop];
if (value !== undefined) {
target[prop] = value;
}
}
}
}
return target;
};
// TODO: use native Array.find, Array.findIndex when IE support is dropped
export const arrayFindIndex = function(arr, pred) {
for (let i = 0; i !== arr.length; ++i) {
if (pred(arr[i])) {
return i;
}
}
return -1;
};
export const getChildState = function(node) {
let all = true;
let none = true;
let allWithoutDisable = true;
for (let i = 0, j = node.length; i < j; i++) {
const n = node[i];
if (n.checked !== true || n.indeterminate) {
all = false;
if (!n.disabled) {
allWithoutDisable = false;
}
}
if (n.checked !== false || n.indeterminate) {
none = false;
}
}
return {
all,
none,
allWithoutDisable,
half: !all && !none
};
};
export const reInitChecked = function(node) {
if (!node || node.childNodesId.length === 0) return;
let childNodes = node.getChildNodes(node.childNodesId);
const {
all,
none,
half
} = getChildState(childNodes);
if (all) {
node.checked = true;
node.indeterminate = false;
} else if (half) {
node.checked = false;
node.indeterminate = true;
} else if (none) {
node.checked = false;
node.indeterminate = false;
}
let parent = node.getParent(node.parentId);
if (!parent || parent.level === 0) return;
if (!node.store().checkStrictly) {
reInitChecked(parent);
}
};
export const getPropertyFromData = function(node, prop) {
const props = node.store().props;
const data = node.data || {};
const config = props[prop];
if (typeof config === 'function') {
return config(data, node);
} else if (typeof config === 'string') {
return data[config];
} else if (typeof config === 'undefined') {
const dataProp = data[prop];
return dataProp === undefined ? '' : dataProp;
}
};
export const isNull = function(v) {
return v === undefined || v === null || v === '';
}

View File

@@ -0,0 +1,59 @@
<template>
<u-alert-tips class="yunzhupaas-alert" :type="type" :title="title" :show-icon="showIcon" :description="description"
:close-able="closable" :close-text="closeText" @close="show=false" :show="show" :title-style="titleStyle"
:desc-style="descStyle" />
</template>
<script>
export default {
name: 'yunzhupaas-alert',
props: {
type: {
type: String,
default: 'success'
},
title: {
type: String,
default: '这是一个提示'
},
tagIcon: {
type: String,
default: 'icon-ym icon-ym-generator-alert'
},
showIcon: {
type: Boolean,
default: false
},
closable: {
type: Boolean,
default: false
},
description: {
type: String,
default: ''
},
closeText: {
type: String,
default: ''
}
},
data() {
return {
show: true,
titleStyle: {
'word-break': 'break-all',
'line-height': '34rpx'
},
descStyle: {
'word-break': 'break-all',
'line-height': '40rpx',
},
}
}
}
</script>
<style lang="scss">
.yunzhupaas-alert {
width: 100%;
min-height: 72rpx;
}
</style>

View File

@@ -0,0 +1,241 @@
<template>
<u-popup class="yunzhupaas-tree-select-popup" :maskCloseAble="maskCloseAble" mode="right" v-model="showPopup"
:safeAreaInsetBottom="safeAreaInsetBottom" @close="close" :z-index="uZIndex" width="100%">
<view class="yunzhupaas-tree-select-body">
<view class="yunzhupaas-tree-select-title">
<text class="icon-ym icon-ym-report-icon-preview-pagePre backIcon" @tap="close()"></text>
<view class="title">省市区</view>
</view>
<view class="yunzhupaas-tree-selected">
<view class="yunzhupaas-tree-selected-head">
<view>{{$t('component.yunzhupaas.common.selected')}}</view>
<view v-if="multiple" class="clear-btn" @click="setCheckAll">
{{$t('component.yunzhupaas.common.clearAll')}}
</view>
</view>
<view class="yunzhupaas-tree-selected-box">
<scroll-view scroll-y="true" class="select-list">
<u-tag closeable @close="delSelect(index)" v-for="(list,index) in selectList" :key="index"
:text="list" class="u-selectTag" />
</scroll-view>
</view>
</view>
<view class="yunzhupaas-tree-select-tree">
<scroll-view :scroll-y="true" style="height: 100%">
<ly-tree ref="tree" :node-key="realProps.value" :tree-data="options" :show-checkbox="false"
:defaultExpandAll='false' @node-click="handleNodeClick" :props="realProps"
:show-node-icon="true" :show-radio="false" :load="loadNode" lazy />
</scroll-view>
</view>
<!-- 底部按钮 -->
<view class="yunzhupaas-tree-select-actions">
<u-button class="buttom-btn" @click="close()">{{$t('common.cancelText')}}</u-button>
<u-button class="buttom-btn" type="primary"
@click.stop="handleConfirm()">{{$t('common.okText')}}</u-button>
</view>
</view>
</u-popup>
</template>
<script>
const defaultProps = {
label: 'fullName',
value: 'id',
icon: 'icon',
children: 'children'
}
var _self;
import {
getProvinceSelector
} from '@/api/common.js'
export default {
name: "tree-select",
props: {
selectedData: {
type: Array,
default () {
return [];
}
},
ids: {
type: Array,
default () {
return [];
}
},
// 是否显示边框
border: {
type: Boolean,
default: true
},
// 通过双向绑定控制组件的弹出与收起
modelValue: {
type: Boolean,
default: false
},
// "取消"按钮的颜色
cancelColor: {
type: String,
default: '#606266'
},
// "确定"按钮的颜色
confirmColor: {
type: String,
default: '#2979ff'
},
// 弹出的z-index值
zIndex: {
type: [String, Number],
default: 99999
},
safeAreaInsetBottom: {
type: Boolean,
default: false
},
// 是否允许通过点击遮罩关闭Picker
maskCloseAble: {
type: Boolean,
default: true
},
props: {
type: Object,
default: () => ({
label: 'fullName',
value: 'id',
icon: 'icon',
children: 'children',
isLeaf: 'isLeaf'
})
},
multiple: {
type: Boolean,
default: false
},
// 顶部标题
title: {
type: String,
default: ''
},
// 取消按钮的文字
cancelText: {
type: String,
default: '取消'
},
// 确认按钮的文字
confirmText: {
type: String,
default: '确认'
},
level: {
type: Number,
default: 2
}
},
data() {
return {
moving: false,
selectList: [],
selectListId: [],
newListId: [],
options: [],
selectData: []
};
},
watch: {
// 在select弹起的时候重新初始化所有数据
modelValue: {
immediate: true,
handler(val) {
this.showPopup = val
if (val) setTimeout(() => this.init(), 10);
}
},
},
created() {
_self = this
this.init()
},
computed: {
uZIndex() {
// 如果用户有传递z-index值优先使用
return this.zIndex ? this.zIndex : this.$u.zIndex.popup;
},
realProps() {
return {
...defaultProps,
...this.props
}
}
},
methods: {
init() {
this.selectList = JSON.parse(JSON.stringify(this.selectedData))
this.selectListId = !!this.ids ? this.ids : []
},
loadNode(node, resolve) {
let id = node.key === null ? -1 : node.key
let level = node.level
getProvinceSelector(id).then(res => {
const list = res.data.list.map((value, i) => ({
id: value.id,
fullName: value.fullName,
isLeaf: level >= _self.level ? true : value.isLeaf
}));
resolve(list)
})
},
handleNodeClick(obj) {
if (!obj.isLeaf) return
let getNodePath = this.$refs.tree.getNodePath(obj)
let list = []
let listId = []
let selectList = []
for (let i = 0; i < getNodePath.length; i++) {
list.push(getNodePath[i].fullName)
listId.push(getNodePath[i].id)
let obj = {
fullName: getNodePath[i].fullName,
id: getNodePath[i].id
}
selectList.push(obj)
}
if (listId.length !== this.level + 1) return;
if (!this.multiple) {
this.selectList = [];
this.selectListId = [];
this.selectData = [];
}
var isExist = false;
for (var i = 0; i < this.selectList.length; i++) {
if (this.selectList[i] == list.join('/')) {
isExist = true;
break;
}
};
!isExist && this.selectListId.push(listId);
!isExist && this.selectList.push(list.join('/'));
!isExist && this.selectData.push(selectList);
},
delSelect(index) {
this.selectList.splice(index, 1);
if (!this.multiple) {
this.selectListId = [];
this.selectData = []
}
this.selectListId.splice(index, 1);
},
setCheckAll() {
this.selectList = [];
this.selectListId = [];
this.$refs.tree.setCheckAll(false);
},
handleConfirm() {
this.$emit('confirm', this.selectList, this.selectListId, this.selectData);
this.close();
},
close() {
this.$emit('close');
}
}
};
</script>

View File

@@ -0,0 +1,110 @@
<template>
<view class="yunzhupaas-area-select">
<u-input input-align='right' type="select" :select-open="selectShow" v-model="innerValue"
:placeholder="placeholder" @click="openSelect" />
<Tree v-if="selectShow" v-model="selectShow" :multiple="multiple" :props="props" :selectedData="selectedData"
:level='level' :ids='modelValue' @confirm="handleConfirm" @close="handleClose()" />
</view>
</template>
<script>
import Tree from './Tree.vue';
import {
getProvinceSelectorInfoList
} from '@/api/common.js'
export default {
name: 'yunzhupaas-area-select',
components: {
Tree
},
props: {
modelValue: {
default: ''
},
placeholder: {
type: String,
default: '请选择'
},
props: {
type: Object,
default: () => ({
label: 'fullName',
value: 'id',
children: 'children',
isLeaf: 'isLeaf'
})
},
disabled: {
type: Boolean,
default: false
},
multiple: {
type: Boolean,
default: false
},
level: {
type: Number,
default: 2
}
},
watch: {
modelValue: {
handler(val) {
this.setDefault(val)
},
immediate: true
}
},
data() {
return {
selectShow: false,
innerValue: '',
selectedData: []
}
},
methods: {
setDefault(id) {
this.innerValue = ''
this.selectedData = []
if (!Array.isArray(id) || id.length === 0) return
if (!this.multiple) id = [id]
getProvinceSelectorInfoList(id).then(res => {
const list = res.data
let txt = ''
for (let i = 0; i < list.length; i++) {
txt += (i ? ',' : '') + list[i].join('/')
this.selectedData.push(list[i].join('/'))
}
this.innerValue = txt
})
},
openSelect() {
if (this.disabled) return
this.selectShow = true
},
handleClose() {
this.selectShow = false
},
handleConfirm(e, selectId, selectData) {
this.selectedData = e;
let label = '';
let value = [];
this.defaultValue = value
this.innerValue = e.join()
if (!this.multiple) {
this.$emit('update:modelValue', selectId[0])
this.$emit('change', selectId[0], selectData)
} else {
this.$emit('update:modelValue', selectId)
this.$emit('change', selectId, selectData)
}
},
}
}
</script>
<style lang="scss" scoped>
.yunzhupaas-area-select {
width: 100%;
}
</style>

View File

@@ -0,0 +1,212 @@
<template>
<view class="search-popup-v">
<u-popup v-model="showPopup" width="100%" height="100vh" mode="right" :mask="false" @close="close">
<view class="search-popup-b">
<view class="search-popup-h">
<view class="search-popup-h-txt">
<u-icon name="close" @click="showPopup=false" class="search-popup-h-icon" />
</view>
<u-input type="text" v-model="value" placeholder="请输入" @input="onInput" :clearable="clearable" />
</view>
</view>
<view class="search-popup-item" v-if="showList.length>0">
<view v-for="(item, index) in showList" :key="index" @tap="selectThisItem(item)"
class="u-p-l-20 u-p-r-20">{{item[relationField]}}</view>
</view>
<view class="search-notData" v-if="showList.length<1">
<view class="notData-box u-flex-col">
<view class="u-flex-col notData-inner">
<image :src="icon" class="iconImg"></image>
<text class="notData-inner-text">{{$t('common.noData')}}</text>
</view>
</view>
</view>
</u-popup>
</view>
</template>
<script>
import resources from '@/libs/resources.js'
import {
getPopSelect
} from '@/api/common.js'
export default {
props: {
interfaceId: {
type: String,
default: ''
},
clearable: {
type: Boolean,
default: true
},
relationField: {
type: String,
default: 'fullName'
},
total: {
type: [String, Number],
default: 50
},
formData: {
type: Object
},
templateJson: {
type: Array,
default: () => []
},
rowIndex: {
default: null
},
},
data() {
return {
istQuery: {
keyword: '',
pageSize: 1000
},
icon: resources.message.nodata,
showPopup: false,
value: '',
showList: [],
timer: ''
}
},
methods: {
init(val) {
this.showPopup = true
this.value = val
this.getDataInterfaceList()
},
getDataInterfaceList() {
this.showList = []
const paramList = this.getParamList()
let query = {
interfaceId: this.interfaceId,
relationField: this.relationField,
pageSize: 10000,
paramList
}
getPopSelect(this.interfaceId, query).then(res => {
let list = JSON.parse(JSON.stringify(res.data.list)) || []
if (list.length) list = this.unique(list, this.relationField)
this.showList = list.splice(0, this.total)
})
},
unique(arr, attrName) {
const res = new Map();
// 根据对象的某个属性值去重
return arr.filter(o => !res.has(o[attrName]) && res.set(o[attrName], 1));
},
getParamList() {
let templateJson = this.templateJson
for (let i = 0; i < templateJson.length; i++) {
if (templateJson[i].relationField && this.formData && templateJson[i].sourceType == 1) {
if (templateJson[i].relationField.includes('-')) {
let tableVModel = templateJson[i].relationField.split('-')[0]
let childVModel = templateJson[i].relationField.split('-')[1]
templateJson[i].defaultValue = this.formData[tableVModel] && this.formData[tableVModel][this
.rowIndex
] && this.formData[tableVModel][this.rowIndex][childVModel] || ''
} else {
templateJson[i].defaultValue = this.formData[templateJson[i].relationField] || ''
}
}
if (templateJson[i].relationField == '@keyword') templateJson[i].defaultValue = this.value
}
return templateJson
},
onInput(e) {
this.value = e
this.$emit('confirm', this.value);
this.timer && clearTimeout(this.timer);
this.timer = setTimeout(() => {
this.list = [];
this.getDataInterfaceList()
}, 300);
},
close() {
this.showPopup = false
},
selectThisItem(item) {
this.value = item[this.relationField];
this.$emit('confirm', this.value);
this.close()
}
}
}
</script>
<style lang="scss">
.search-popup-v {
.search-popup-b {
height: 158rpx;
.search-popup-h {
padding: 0 20rpx;
border-bottom: 1rpx solid #cbcbcb;
position: fixed;
width: 100%;
background-color: #fff;
z-index: 9;
text-align: center;
.search-popup-h-txt {
height: 86rpx;
width: 100%;
padding: 15rpx 0;
text-align: center;
line-height: 54rpx;
box-sizing: border-box;
font-size: 32rpx;
font-weight: 700;
letter-spacing: 2rpx;
.search-popup-h-icon {
float: right;
margin-top: 12rpx;
}
}
}
}
.search-popup-item {
width: 100%;
height: 100%;
z-index: 9997;
}
.search-notData {
width: 100%;
height: calc(100% - 160rpx);
background-color: #fff;
.notData-box {
width: 100%;
height: 100%;
justify-content: center;
align-items: center;
.notData-inner {
width: 280rpx;
height: 340rpx;
align-items: center;
.iconImg {
width: 100%;
height: 100%;
}
.notData-inner-text {
padding: 30rpx 0;
color: #909399;
}
}
}
}
}
</style>

View File

@@ -0,0 +1,136 @@
<template>
<view class="yunzhupaas-auto-complete">
<u-input input-align='right' type="select" @click="showSearch" v-model="innerValue"
:placeholder="placeholder" />
<SearchForm ref="searchForm" :interfaceId="interfaceId" :relationField="relationField"
:templateJson="templateJson" @confirm="confirm" :total="total || 50" :formData="formData"
:clearable="clearable" :rowIndex="rowIndex" />
</view>
</template>
<script>
import SearchForm from './SearchForm';
export default {
name: 'yunzhupaas-auto-complete',
components: {
SearchForm
},
props: {
modelValue: {
default: ''
},
formData: {
type: Object
},
options: {
type: Array,
default: () => []
},
placeholder: {
type: String,
default: '请输入'
},
clearable: {
type: Boolean,
default: false
},
disabled: {
type: Boolean,
default: false
},
templateJson: {
type: Array,
default: () => []
},
interfaceId: {
type: String,
default: ''
},
relationField: {
type: String,
default: 'fullName'
},
total: {
type: Number,
default: 50
},
rowIndex: {
default: null
}
},
data() {
return {
innerValue: ''
}
},
watch: {
modelValue: {
handler(val) {
this.innerValue = val || ''
},
immediate: true
}
},
methods: {
showSearch() {
if (this.disabled) return
this.$nextTick(() => {
this.$refs.searchForm.init(this.innerValue)
})
},
confirm(e) {
this.innerValue = e
this.$emit('update:modelValue', e);
this.$emit('change', e);
}
}
}
</script>
<style lang="scss">
.yunzhupaas-auto-complete {
width: 100%;
.str-auto-complete-container {
width: 549rpx;
height: 360px;
border-radius: 8rpx;
box-shadow: 0rpx 0rpx 12rpx #dfe3e9;
position: absolute;
z-index: 9997;
background: #fff;
top: 94rpx;
left: 0;
right: 0;
overflow-y: scroll;
.str-auto-complete-mask {
width: 100%;
height: calc(100% - 90rpx);
position: fixed;
left: 0;
top: 0;
bottom: 0;
right: 0;
z-index: 9999;
}
.str-auto-complete-item {
position: relative;
padding: 10rpx;
z-index: 9999
}
}
.auto-complete-b {
width: 549rpx;
height: 360px;
z-index: 999;
position: absolute;
background-color: #fff;
border: 1px solid red;
top: 94rpx;
left: 0;
right: 0;
}
}
</style>

View File

@@ -0,0 +1,116 @@
<template>
<tki-barcode class="yunzhupaas-barcode" v-if="barcode&&showBarCode" ref="barcode" :format="format" :cid="cid"
:val="barcode" :opations="opations" loadMake :key="key" />
</template>
<script>
import tkiBarcode from "./tki-barcode/tki-barcode.vue"
let unique = 0
export default {
name: 'yunzhupaas-barcode',
props: {
dataType: {
type: String,
default: 'static'
},
format: {
type: String,
default: 'code128'
},
lineColor: {
type: String,
default: '#000'
},
background: {
type: String,
default: '#fff'
},
relationField: {
type: String,
default: ''
},
formData: {
type: Object
},
width: {
type: Number,
default: 4
},
height: {
type: Number,
default: 40
},
staticText: {
type: String,
default: ''
}
},
components: {
tkiBarcode
},
data() {
return {
cid: '',
relationText: "",
showBarCode: false,
key: +new Date()
}
},
computed: {
barcode() {
return this.dataType === 'static' ? this.staticText : this.relationText?.toString()
},
opations() {
return {
format: this.format,
width: this.width,
height: this.height,
displayValue: false,
lineColor: this.lineColor,
background: this.background,
}
}
},
created() {
this.cid = this.uuid()
this.showBarCode = true
uni.$on('updateCode', () => {
this.showBarCode = false
this.$nextTick(() => {
this.showBarCode = true
})
})
},
watch: {
formData: {
handler: function(val) {
if (val && this.dataType === 'relation' && this.relationField) {
if (this.relationText != val[this.relationField]) {
this.relationText = val[this.relationField]
setTimeout(() => {
this.key = +new Date()
}, 50)
}
}
},
deep: true,
immediate: true
},
},
methods: {
uuid() {
const time = Date.now()
const random = Math.floor(Math.random() * 1000000000)
unique++
return 'barcode_' + random + unique + String(time)
}
},
}
</script>
<style lang="scss" scoped>
.yunzhupaas-barcode {
width: 100%;
overflow: hidden;
margin-bottom: -20rpx;
}
</style>

View File

@@ -0,0 +1,212 @@
import barcodes from './barcodes/index.js'
let barcode = {};
(function() {
// 初始化
barcode = function(cont, ctxid, options, ctxsize, result) {
let ops = {},
newOptions, encodings, globaContext, ctx, globaCtxid, cbCanvasSize, cbResult;
globaCtxid = ctxid
cbCanvasSize = ctxsize
cbResult = result
newOptions = Object.assign(ops, options);
// 修成margin
fixMargin(newOptions)
// 处理options 数据
if (newOptions.text == '' || !cont) {
return false
}
// 获取ctx
globaContext = cont
ctx = uni.createCanvasContext(globaCtxid, globaContext)
// 获取编码数据
encodings = new barcodes[newOptions.format.toUpperCase()](newOptions.text, newOptions).encode()
let fixencodings = fixEncodings(encodings, newOptions)
// 返回canvas实际大小
cbCanvasSize({
width: fixencodings.width,
height: fixencodings.height
})
// 绘制canvas
setTimeout(() => {
drawCanvas.render(newOptions, fixencodings)
}, 50);
// 绘制canvas
let drawCanvas = {
render(options, encoding) {
this.prepare(options, encoding)
encoding.encodings.forEach((v, i) => {
this.barcode(options, v)
this.text(options, v)
this.move(v)
});
this.draw(options, encoding)
},
barcode(options, encoding) {
let binary = encoding.data;
let yFrom;
if (options.textPosition == "top") {
yFrom = options.marginTop + options.fontSize + options.textMargin;
} else {
yFrom = options.marginTop;
}
// 绘制条码
ctx.fillStyle = options.lineColor;
for (let b = 0; b < binary.length; b++) {
let x = b * options.width + encoding.barcodePadding;
let height = options.height
if (encoding.options) {
if (encoding.options.height != undefined) {
height = encoding.options.height
}
}
if (binary[b] === "1") {
ctx.fillRect(x, yFrom, options.width, height);
} else if (binary[b]) {
ctx.fillRect(x, yFrom, options.width, height * binary[b]);
}
}
},
text(options, encoding) {
if (options.displayValue) {
let x, y, align, size;
if (options.textPosition == "top") {
y = options.marginTop + options.fontSize;
} else {
y = options.height + options.textMargin + options.marginTop + options.fontSize;
}
if (encoding.options) {
if (encoding.options.textAlign != undefined) {
align = encoding.options.textAlign
}
if (encoding.options.fontSize != undefined) {
size = encoding.options.fontSize
}
} else {
align = options.textAlign
size = options.fontSize
}
ctx.setFontSize(size)
if (align == "left" || encoding.barcodePadding > 0) {
x = 0;
ctx.setTextAlign('left')
} else if (align == "right") {
x = encoding.width - 1;
ctx.setTextAlign('right')
} else {
x = encoding.width / 2;
ctx.setTextAlign('center');
}
ctx.fillStyle = options.fontColor;
if (encoding.text != undefined) {
ctx.fillText(encoding.text, x, y);
}
}
},
move(encoding) {
ctx.translate(encoding.width, 0);
},
prepare(options, encoding) {
// 绘制背景
if (options.background) {
ctx.fillStyle = options.background;
ctx.fillRect(0, 0, encoding.width, encoding.height);
}
ctx.translate(options.marginLeft, 0);
},
draw(options, encoding) {
ctx.draw(false, () => {
this.toImgs(options, encoding)
})
},
toImgs(options, encoding) {
setTimeout(() => {
try {
uni.canvasToTempFilePath({
width: encoding.width,
height: encoding.height,
destWidth: encoding.width,
destHeight: encoding.height,
canvasId: globaCtxid,
fileType: 'png',
success: function(res) {
cbResult(res.tempFilePath)
},
fail: function(res) {
cbResult(res)
},
complete: function() {
uni.hideLoading();
},
}, globaContext);
} catch (e) {
//TODO handle the exception
}
}, options.text.length + 100);
}
}
// 混入canvas数据
function fixEncodings(encoding, options) {
let encodingArr = [],
width = options.marginLeft + options.marginRight,
height;
if (!Array.isArray(encoding)) {
encodingArr[0] = JSON.parse(JSON.stringify(encoding))
} else {
encodingArr = [...encoding]
}
encodingArr.forEach((v, i) => {
// 获取文本宽度
let textWidth = ctx.measureText(encodingArr[i].text ? encodingArr[i].text : '').width;
// 获取条形码宽度
let barcodeWidth = encodingArr[i].data.length * options.width;
// 获取内边距
let barcodePadding = 0;
if (options.displayValue && barcodeWidth < textWidth) {
if (options.textAlign == "center") {
barcodePadding = Math.floor((textWidth - barcodeWidth) / 2);
} else if (options.textAlign == "left") {
barcodePadding = 0;
} else if (options.textAlign == "right") {
barcodePadding = Math.floor(textWidth - barcodeWidth);
}
}
// 混入encodingArr[i]
encodingArr[i].barcodePadding = barcodePadding
encodingArr[i].width = Math.ceil(Math.max(textWidth, barcodeWidth))
width += encodingArr[i].width
if (encodingArr[i].options) {
if (encodingArr[i].options.height != undefined) {
encodingArr[i].height = encodingArr[i].options.height + (options.displayValue &&
(encodingArr[i].text ? encodingArr[i].text : '').length > 0 ? options
.fontSize + options.textMargin : 0) + options.marginTop + options
.marginBottom;
} else {
encodingArr[i].height = height = options.height + (options.displayValue && (
encodingArr[i].text ? encodingArr[i].text : '').length > 0 ? options
.fontSize + options.textMargin : 0) + options.marginTop + options
.marginBottom;
}
} else {
encodingArr[i].height = height = options.height + (options.displayValue && (
encodingArr[i].text ? encodingArr[i].text : '').length > 0 ? options
.fontSize + options.textMargin : 0) + options.marginTop + options
.marginBottom;
}
});
return {
encodings: encodingArr,
width,
height
};
}
// 修正Margin
function fixMargin(options) {
options.marginTop = options.marginTop == undefined ? options.margin : options.marginTop;
options.marginBottom = options.marginBottom == undefined ? options.margin : options.marginBottom;
options.marginRight = options.marginRight == undefined ? options.margin : options.marginRight;
options.marginLeft = options.marginLeft == undefined ? options.margin : options.marginLeft;
}
};
})()
export default barcode

View File

@@ -0,0 +1,19 @@
"use strict";
function _classCallCheck(instance, Constructor) {
if (!(instance instanceof Constructor)) {
throw new TypeError("Cannot call a class as a function");
}
}
var Barcode = function Barcode(data, options) {
_classCallCheck(this, Barcode);
this.data = data;
this.text = options.text || data;
this.options = options;
};
export default Barcode

View File

@@ -0,0 +1,208 @@
'use strict';
var _createClass = function() {
function defineProperties(target, props) {
for (var i = 0; i < props.length; i++) {
var descriptor = props[i];
descriptor.enumerable = descriptor.enumerable || false;
descriptor.configurable = true;
if ("value" in descriptor) descriptor.writable = true;
Object.defineProperty(target, descriptor.key, descriptor);
}
}
return function(Constructor, protoProps, staticProps) {
if (protoProps) defineProperties(Constructor.prototype, protoProps);
if (staticProps) defineProperties(Constructor, staticProps);
return Constructor;
};
}();
import _Barcode3 from '../Barcode.js'
import _constants from './constants'
function _interopRequireDefault(obj) {
return obj && obj.__esModule ? obj : {
default: obj
};
}
function _classCallCheck(instance, Constructor) {
if (!(instance instanceof Constructor)) {
throw new TypeError("Cannot call a class as a function");
}
}
function _possibleConstructorReturn(self, call) {
if (!self) {
throw new ReferenceError("this hasn't been initialised - super() hasn't been called");
}
return call && (typeof call === "object" || typeof call === "function") ? call : self;
}
function _inherits(subClass, superClass) {
if (typeof superClass !== "function" && superClass !== null) {
throw new TypeError("Super expression must either be null or a function, not " + typeof superClass);
}
subClass.prototype = Object.create(superClass && superClass.prototype, {
constructor: {
value: subClass,
enumerable: false,
writable: true,
configurable: true
}
});
if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ =
superClass;
}
// This is the master class,
// it does require the start code to be included in the string
var CODE128 = function(_Barcode) {
_inherits(CODE128, _Barcode);
function CODE128(data, options) {
_classCallCheck(this, CODE128);
// Get array of ascii codes from data
var _this = _possibleConstructorReturn(this, (CODE128.__proto__ || Object.getPrototypeOf(CODE128)).call(
this, data.substring(1), options));
_this.bytes = data.split('').map(function(char) {
return char.charCodeAt(0);
});
return _this;
}
_createClass(CODE128, [{
key: 'valid',
value: function valid() {
// ASCII value ranges 0-127, 200-211
return (/^[\x00-\x7F\xC8-\xD3]+$/.test(this.data));
}
// The public encoding function
}, {
key: 'encode',
value: function encode() {
var bytes = this.bytes;
// Remove the start code from the bytes and set its index
var startIndex = bytes.shift() - 105;
// Get start set by index
var startSet = _constants.SET_BY_CODE[startIndex];
if (startSet === undefined) {
throw new RangeError('The encoding does not start with a start character.');
}
if (this.shouldEncodeAsEan128() === true) {
bytes.unshift(_constants.FNC1);
}
// Start encode with the right type
var encodingResult = CODE128.next(bytes, 1, startSet);
return {
text: this.text === this.data ? this.text.replace(/[^\x20-\x7E]/g, '') : this.text,
data:
// Add the start bits
CODE128.getBar(startIndex) +
// Add the encoded bits
encodingResult.result +
// Add the checksum
CODE128.getBar((encodingResult.checksum + startIndex) % _constants.MODULO) +
// Add the end bits
CODE128.getBar(_constants.STOP)
};
}
// GS1-128/EAN-128
}, {
key: 'shouldEncodeAsEan128',
value: function shouldEncodeAsEan128() {
var isEAN128 = this.options.ean128 || false;
if (typeof isEAN128 === 'string') {
isEAN128 = isEAN128.toLowerCase() === 'true';
}
return isEAN128;
}
// Get a bar symbol by index
}], [{
key: 'getBar',
value: function getBar(index) {
return _constants.BARS[index] ? _constants.BARS[index].toString() : '';
}
// Correct an index by a set and shift it from the bytes array
}, {
key: 'correctIndex',
value: function correctIndex(bytes, set) {
if (set === _constants.SET_A) {
var charCode = bytes.shift();
return charCode < 32 ? charCode + 64 : charCode - 32;
} else if (set === _constants.SET_B) {
return bytes.shift() - 32;
} else {
return (bytes.shift() - 48) * 10 + bytes.shift() - 48;
}
}
}, {
key: 'next',
value: function next(bytes, pos, set) {
if (!bytes.length) {
return {
result: '',
checksum: 0
};
}
var nextCode = void 0,
index = void 0;
// Special characters
if (bytes[0] >= 200) {
index = bytes.shift() - 105;
var nextSet = _constants.SWAP[index];
// Swap to other set
if (nextSet !== undefined) {
nextCode = CODE128.next(bytes, pos + 1, nextSet);
}
// Continue on current set but encode a special character
else {
// Shift
if ((set === _constants.SET_A || set === _constants.SET_B) && index ===
_constants.SHIFT) {
// Convert the next character so that is encoded correctly
bytes[0] = set === _constants.SET_A ? bytes[0] > 95 ? bytes[0] - 96 : bytes[
0] : bytes[0] < 32 ? bytes[0] + 96 : bytes[0];
}
nextCode = CODE128.next(bytes, pos + 1, set);
}
}
// Continue encoding
else {
index = CODE128.correctIndex(bytes, set);
nextCode = CODE128.next(bytes, pos + 1, set);
}
// Get the correct binary encoding and calculate the weight
var enc = CODE128.getBar(index);
var weight = index * pos;
return {
result: enc + nextCode.result,
checksum: weight + nextCode.checksum
};
}
}]);
return CODE128;
}(_Barcode3);
export default CODE128;

View File

@@ -0,0 +1,80 @@
'use strict';
var _createClass = function() {
function defineProperties(target, props) {
for (var i = 0; i < props.length; i++) {
var descriptor = props[i];
descriptor.enumerable = descriptor.enumerable || false;
descriptor.configurable = true;
if ("value" in descriptor) descriptor.writable = true;
Object.defineProperty(target, descriptor.key, descriptor);
}
}
return function(Constructor, protoProps, staticProps) {
if (protoProps) defineProperties(Constructor.prototype, protoProps);
if (staticProps) defineProperties(Constructor, staticProps);
return Constructor;
};
}();
import _CODE3 from './CODE128'
import _constants from './constants'
function _interopRequireDefault(obj) {
return obj && obj.__esModule ? obj : {
default: obj
};
}
function _classCallCheck(instance, Constructor) {
if (!(instance instanceof Constructor)) {
throw new TypeError("Cannot call a class as a function");
}
}
function _possibleConstructorReturn(self, call) {
if (!self) {
throw new ReferenceError("this hasn't been initialised - super() hasn't been called");
}
return call && (typeof call === "object" || typeof call === "function") ? call : self;
}
function _inherits(subClass, superClass) {
if (typeof superClass !== "function" && superClass !== null) {
throw new TypeError("Super expression must either be null or a function, not " + typeof superClass);
}
subClass.prototype = Object.create(superClass && superClass.prototype, {
constructor: {
value: subClass,
enumerable: false,
writable: true,
configurable: true
}
});
if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ =
superClass;
}
var CODE128A = function(_CODE) {
_inherits(CODE128A, _CODE);
function CODE128A(string, options) {
_classCallCheck(this, CODE128A);
return _possibleConstructorReturn(this, (CODE128A.__proto__ || Object.getPrototypeOf(CODE128A)).call(this,
_constants.A_START_CHAR + string, options));
}
_createClass(CODE128A, [{
key: 'valid',
value: function valid() {
return new RegExp('^' + _constants.A_CHARS + '+$').test(this.data);
}
}]);
return CODE128A;
}(_CODE3);
export default CODE128A;

View File

@@ -0,0 +1,79 @@
'use strict';
var _createClass = function() {
function defineProperties(target, props) {
for (var i = 0; i < props.length; i++) {
var descriptor = props[i];
descriptor.enumerable = descriptor.enumerable || false;
descriptor.configurable = true;
if ("value" in descriptor) descriptor.writable = true;
Object.defineProperty(target, descriptor.key, descriptor);
}
}
return function(Constructor, protoProps, staticProps) {
if (protoProps) defineProperties(Constructor.prototype, protoProps);
if (staticProps) defineProperties(Constructor, staticProps);
return Constructor;
};
}();
import _CODE3 from './CODE128'
import _constants from './constants'
function _interopRequireDefault(obj) {
return obj && obj.__esModule ? obj : {
default: obj
};
}
function _classCallCheck(instance, Constructor) {
if (!(instance instanceof Constructor)) {
throw new TypeError("Cannot call a class as a function");
}
}
function _possibleConstructorReturn(self, call) {
if (!self) {
throw new ReferenceError("this hasn't been initialised - super() hasn't been called");
}
return call && (typeof call === "object" || typeof call === "function") ? call : self;
}
function _inherits(subClass, superClass) {
if (typeof superClass !== "function" && superClass !== null) {
throw new TypeError("Super expression must either be null or a function, not " + typeof superClass);
}
subClass.prototype = Object.create(superClass && superClass.prototype, {
constructor: {
value: subClass,
enumerable: false,
writable: true,
configurable: true
}
});
if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ =
superClass;
}
var CODE128B = function(_CODE) {
_inherits(CODE128B, _CODE);
function CODE128B(string, options) {
_classCallCheck(this, CODE128B);
return _possibleConstructorReturn(this, (CODE128B.__proto__ || Object.getPrototypeOf(CODE128B)).call(this,
_constants.B_START_CHAR + string, options));
}
_createClass(CODE128B, [{
key: 'valid',
value: function valid() {
return new RegExp('^' + _constants.B_CHARS + '+$').test(this.data);
}
}]);
return CODE128B;
}(_CODE3);
export default CODE128B;

View File

@@ -0,0 +1,79 @@
'use strict';
var _createClass = function() {
function defineProperties(target, props) {
for (var i = 0; i < props.length; i++) {
var descriptor = props[i];
descriptor.enumerable = descriptor.enumerable || false;
descriptor.configurable = true;
if ("value" in descriptor) descriptor.writable = true;
Object.defineProperty(target, descriptor.key, descriptor);
}
}
return function(Constructor, protoProps, staticProps) {
if (protoProps) defineProperties(Constructor.prototype, protoProps);
if (staticProps) defineProperties(Constructor, staticProps);
return Constructor;
};
}();
import _CODE3 from './CODE128'
import _constants from './constants'
function _interopRequireDefault(obj) {
return obj && obj.__esModule ? obj : {
default: obj
};
}
function _classCallCheck(instance, Constructor) {
if (!(instance instanceof Constructor)) {
throw new TypeError("Cannot call a class as a function");
}
}
function _possibleConstructorReturn(self, call) {
if (!self) {
throw new ReferenceError("this hasn't been initialised - super() hasn't been called");
}
return call && (typeof call === "object" || typeof call === "function") ? call : self;
}
function _inherits(subClass, superClass) {
if (typeof superClass !== "function" && superClass !== null) {
throw new TypeError("Super expression must either be null or a function, not " + typeof superClass);
}
subClass.prototype = Object.create(superClass && superClass.prototype, {
constructor: {
value: subClass,
enumerable: false,
writable: true,
configurable: true
}
});
if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ =
superClass;
}
var CODE128C = function(_CODE) {
_inherits(CODE128C, _CODE);
function CODE128C(string, options) {
_classCallCheck(this, CODE128C);
return _possibleConstructorReturn(this, (CODE128C.__proto__ || Object.getPrototypeOf(CODE128C)).call(this,
_constants.C_START_CHAR + string, options));
}
_createClass(CODE128C, [{
key: 'valid',
value: function valid() {
return new RegExp('^' + _constants.C_CHARS + '+$').test(this.data);
}
}]);
return CODE128C;
}(_CODE3);
export default CODE128C;

View File

@@ -0,0 +1,63 @@
'use strict';
import _CODE3 from './CODE128'
import _auto2 from './auto'
function _interopRequireDefault(obj) {
return obj && obj.__esModule ? obj : {
default: obj
};
}
function _classCallCheck(instance, Constructor) {
if (!(instance instanceof Constructor)) {
throw new TypeError("Cannot call a class as a function");
}
}
function _possibleConstructorReturn(self, call) {
if (!self) {
throw new ReferenceError("this hasn't been initialised - super() hasn't been called");
}
return call && (typeof call === "object" || typeof call === "function") ? call : self;
}
function _inherits(subClass, superClass) {
if (typeof superClass !== "function" && superClass !== null) {
throw new TypeError("Super expression must either be null or a function, not " + typeof superClass);
}
subClass.prototype = Object.create(superClass && superClass.prototype, {
constructor: {
value: subClass,
enumerable: false,
writable: true,
configurable: true
}
});
if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ =
superClass;
}
var CODE128AUTO = function(_CODE) {
_inherits(CODE128AUTO, _CODE);
function CODE128AUTO(data, options) {
_classCallCheck(this, CODE128AUTO);
// ASCII value ranges 0-127, 200-211
if (/^[\x00-\x7F\xC8-\xD3]+$/.test(data)) {
var _this = _possibleConstructorReturn(this, (CODE128AUTO.__proto__ || Object.getPrototypeOf(
CODE128AUTO)).call(this, (0, _auto2)(data), options));
} else {
var _this = _possibleConstructorReturn(this, (CODE128AUTO.__proto__ || Object.getPrototypeOf(
CODE128AUTO)).call(this, data, options));
}
return _possibleConstructorReturn(_this);
}
return CODE128AUTO;
}(_CODE3);
export default CODE128AUTO;

View File

@@ -0,0 +1,71 @@
'use strict';
import _constants from './constants'
// Match Set functions
var matchSetALength = function matchSetALength(string) {
return string.match(new RegExp('^' + _constants.A_CHARS + '*'))[0].length;
};
var matchSetBLength = function matchSetBLength(string) {
return string.match(new RegExp('^' + _constants.B_CHARS + '*'))[0].length;
};
var matchSetC = function matchSetC(string) {
return string.match(new RegExp('^' + _constants.C_CHARS + '*'))[0];
};
// CODE128A or CODE128B
function autoSelectFromAB(string, isA) {
var ranges = isA ? _constants.A_CHARS : _constants.B_CHARS;
var untilC = string.match(new RegExp('^(' + ranges + '+?)(([0-9]{2}){2,})([^0-9]|$)'));
if (untilC) {
return untilC[1] + String.fromCharCode(204) + autoSelectFromC(string.substring(untilC[1].length));
}
var chars = string.match(new RegExp('^' + ranges + '+'))[0];
if (chars.length === string.length) {
return string;
}
return chars + String.fromCharCode(isA ? 205 : 206) + autoSelectFromAB(string.substring(chars.length), !isA);
}
// CODE128C
function autoSelectFromC(string) {
var cMatch = matchSetC(string);
var length = cMatch.length;
if (length === string.length) {
return string;
}
string = string.substring(length);
// Select A/B depending on the longest match
var isA = matchSetALength(string) >= matchSetBLength(string);
return cMatch + String.fromCharCode(isA ? 206 : 205) + autoSelectFromAB(string, isA);
}
// Detect Code Set (A, B or C) and format the string
function auto(string) {
var newString = void 0;
var cLength = matchSetC(string).length;
// Select 128C if the string start with enough digits
if (cLength >= 2) {
newString = _constants.C_START_CHAR + autoSelectFromC(string);
} else {
// Select A/B depending on the longest match
var isA = matchSetALength(string) > matchSetBLength(string);
newString = (isA ? _constants.A_START_CHAR : _constants.B_START_CHAR) + autoSelectFromAB(string, isA);
}
return newString.replace(/[\xCD\xCE]([^])[\xCD\xCE]/, // Any sequence between 205 and 206 characters
function(match, char) {
return String.fromCharCode(203) + char;
});
};
export default auto

View File

@@ -0,0 +1,99 @@
"use strict";
var _SET_BY_CODE;
function _defineProperty(obj, key, value) {
if (key in obj) {
Object.defineProperty(obj, key, {
value: value,
enumerable: true,
configurable: true,
writable: true
});
} else {
obj[key] = value;
}
return obj;
}
// constants for internal usage
var SET_A = 0;
var SET_B = 1;
var SET_C = 2;
// Special characters
var SHIFT = 98;
var START_A = 103;
var START_B = 104;
var START_C = 105;
var MODULO = 103;
var STOP = 106;
var FNC1 = 207;
// Get set by start code
var SET_BY_CODE = (_SET_BY_CODE = {}, _defineProperty(_SET_BY_CODE, START_A, SET_A),
_defineProperty(_SET_BY_CODE, START_B, SET_B), _defineProperty(_SET_BY_CODE, START_C, SET_C), _SET_BY_CODE);
// Get next set by code
var SWAP = {
101: SET_A,
100: SET_B,
99: SET_C
};
var A_START_CHAR = String.fromCharCode(208); // START_A + 105
var B_START_CHAR = String.fromCharCode(209); // START_B + 105
var C_START_CHAR = String.fromCharCode(210); // START_C + 105
// 128A (Code Set A)
// ASCII characters 00 to 95 (09, AZ and control codes), special characters, and FNC 14
var A_CHARS = "[\x00-\x5F\xC8-\xCF]";
// 128B (Code Set B)
// ASCII characters 32 to 127 (09, AZ, az), special characters, and FNC 14
var B_CHARS = "[\x20-\x7F\xC8-\xCF]";
// 128C (Code Set C)
// 0099 (encodes two digits with a single code point) and FNC1
var C_CHARS = "(\xCF*[0-9]{2}\xCF*)";
// CODE128 includes 107 symbols:
// 103 data symbols, 3 start symbols (A, B and C), and 1 stop symbol (the last one)
// Each symbol consist of three black bars (1) and three white spaces (0).
var BARS = [11011001100, 11001101100, 11001100110, 10010011000, 10010001100, 10001001100, 10011001000,
10011000100, 10001100100, 11001001000, 11001000100, 11000100100, 10110011100, 10011011100, 10011001110,
10111001100, 10011101100, 10011100110, 11001110010, 11001011100, 11001001110, 11011100100, 11001110100,
11101101110, 11101001100, 11100101100, 11100100110, 11101100100, 11100110100, 11100110010, 11011011000,
11011000110, 11000110110, 10100011000, 10001011000, 10001000110, 10110001000, 10001101000, 10001100010,
11010001000, 11000101000, 11000100010, 10110111000, 10110001110, 10001101110, 10111011000, 10111000110,
10001110110, 11101110110, 11010001110, 11000101110, 11011101000, 11011100010, 11011101110, 11101011000,
11101000110, 11100010110, 11101101000, 11101100010, 11100011010, 11101111010, 11001000010, 11110001010,
10100110000, 10100001100, 10010110000, 10010000110, 10000101100, 10000100110, 10110010000, 10110000100,
10011010000, 10011000010, 10000110100, 10000110010, 11000010010, 11001010000, 11110111010, 11000010100,
10001111010, 10100111100, 10010111100, 10010011110, 10111100100, 10011110100, 10011110010, 11110100100,
11110010100, 11110010010, 11011011110, 11011110110, 11110110110, 10101111000, 10100011110, 10001011110,
10111101000, 10111100010, 11110101000, 11110100010, 10111011110, 10111101110, 11101011110, 11110101110,
11010000100, 11010010000, 11010011100, 1100011101011
];
export default {
SET_A,
SET_B,
SET_C,
SHIFT,
START_A,
START_B,
START_C,
MODULO,
STOP,
FNC1,
SET_BY_CODE,
SWAP,
A_START_CHAR,
B_START_CHAR,
C_START_CHAR,
A_CHARS,
B_CHARS,
C_CHARS,
BARS
}

View File

@@ -0,0 +1,17 @@
'use strict';
import CODE128 from './CODE128_AUTO.js'
import CODE128A from './CODE128A.js'
import CODE128B from './CODE128B.js'
import CODE128C from './CODE128C.js'
export default {
CODE128,
CODE128A,
CODE128B,
CODE128C,
};

View File

@@ -0,0 +1,141 @@
"use strict";
var _createClass = function() {
function defineProperties(target, props) {
for (var i = 0; i < props.length; i++) {
var descriptor = props[i];
descriptor.enumerable = descriptor.enumerable || false;
descriptor.configurable = true;
if ("value" in descriptor) descriptor.writable = true;
Object.defineProperty(target, descriptor.key, descriptor);
}
}
return function(Constructor, protoProps, staticProps) {
if (protoProps) defineProperties(Constructor.prototype, protoProps);
if (staticProps) defineProperties(Constructor, staticProps);
return Constructor;
};
}();
import _Barcode3 from '../Barcode.js'
function _classCallCheck(instance, Constructor) {
if (!(instance instanceof Constructor)) {
throw new TypeError("Cannot call a class as a function");
}
}
function _possibleConstructorReturn(self, call) {
if (!self) {
throw new ReferenceError("this hasn't been initialised - super() hasn't been called");
}
return call && (typeof call === "object" || typeof call === "function") ? call : self;
}
function _inherits(subClass, superClass) {
if (typeof superClass !== "function" && superClass !== null) {
throw new TypeError("Super expression must either be null or a function, not " + typeof superClass);
}
subClass.prototype = Object.create(superClass && superClass.prototype, {
constructor: {
value: subClass,
enumerable: false,
writable: true,
configurable: true
}
});
if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ =
superClass;
} // Encoding documentation:
// https://en.wikipedia.org/wiki/Code_39#Encoding
var CODE39 = function(_Barcode) {
_inherits(CODE39, _Barcode);
function CODE39(data, options) {
_classCallCheck(this, CODE39);
data = data.toUpperCase();
// Calculate mod43 checksum if enabled
if (options.mod43) {
data += getCharacter(mod43checksum(data));
}
return _possibleConstructorReturn(this, (CODE39.__proto__ || Object.getPrototypeOf(CODE39)).call(this, data,
options));
}
_createClass(CODE39, [{
key: "encode",
value: function encode() {
// First character is always a *
var result = getEncoding("*");
// Take every character and add the binary representation to the result
for (var i = 0; i < this.data.length; i++) {
result += getEncoding(this.data[i]) + "0";
}
// Last character is always a *
result += getEncoding("*");
return {
data: result,
text: this.text
};
}
}, {
key: "valid",
value: function valid() {
return this.data.search(/^[0-9A-Z\-\.\ \$\/\+\%]+$/) !== -1;
}
}]);
return CODE39;
}(_Barcode3);
// All characters. The position in the array is the (checksum) value
var characters = ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "A", "B", "C", "D", "E", "F", "G", "H", "I", "J",
"K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", "-", ".", " ", "$", "/", "+",
"%", "*"
];
// The decimal representation of the characters, is converted to the
// corresponding binary with the getEncoding function
var encodings = [20957, 29783, 23639, 30485, 20951, 29813, 23669, 20855, 29789, 23645, 29975, 23831, 30533, 22295,
30149, 24005, 21623, 29981, 23837, 22301, 30023, 23879, 30545, 22343, 30161, 24017, 21959, 30065, 23921, 22385,
29015, 18263, 29141, 17879, 29045, 18293, 17783, 29021, 18269, 17477, 17489, 17681, 20753, 35770
];
// Get the binary representation of a character by converting the encodings
// from decimal to binary
function getEncoding(character) {
return getBinary(characterValue(character));
}
function getBinary(characterValue) {
return encodings[characterValue].toString(2);
}
function getCharacter(characterValue) {
return characters[characterValue];
}
function characterValue(character) {
return characters.indexOf(character);
}
function mod43checksum(data) {
var checksum = 0;
for (var i = 0; i < data.length; i++) {
checksum += characterValue(data[i]);
}
checksum = checksum % 43;
return checksum;
}
export default CODE39;

View File

@@ -0,0 +1,151 @@
'use strict';
var _createClass = function() {
function defineProperties(target, props) {
for (var i = 0; i < props.length; i++) {
var descriptor = props[i];
descriptor.enumerable = descriptor.enumerable || false;
descriptor.configurable = true;
if ("value" in descriptor) descriptor.writable = true;
Object.defineProperty(target, descriptor.key, descriptor);
}
}
return function(Constructor, protoProps, staticProps) {
if (protoProps) defineProperties(Constructor.prototype, protoProps);
if (staticProps) defineProperties(Constructor, staticProps);
return Constructor;
};
}();
import _constants from './constants'
import _encoder2 from './encoder'
import _Barcode3 from '../Barcode.js'
function _interopRequireDefault(obj) {
return obj && obj.__esModule ? obj : {
default: obj
};
}
function _classCallCheck(instance, Constructor) {
if (!(instance instanceof Constructor)) {
throw new TypeError("Cannot call a class as a function");
}
}
function _possibleConstructorReturn(self, call) {
if (!self) {
throw new ReferenceError("this hasn't been initialised - super() hasn't been called");
}
return call && (typeof call === "object" || typeof call === "function") ? call : self;
}
function _inherits(subClass, superClass) {
if (typeof superClass !== "function" && superClass !== null) {
throw new TypeError("Super expression must either be null or a function, not " + typeof superClass);
}
subClass.prototype = Object.create(superClass && superClass.prototype, {
constructor: {
value: subClass,
enumerable: false,
writable: true,
configurable: true
}
});
if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ =
superClass;
}
// Base class for EAN8 & EAN13
var EAN = function(_Barcode) {
_inherits(EAN, _Barcode);
function EAN(data, options) {
_classCallCheck(this, EAN);
// Make sure the font is not bigger than the space between the guard bars
var _this = _possibleConstructorReturn(this, (EAN.__proto__ || Object.getPrototypeOf(EAN)).call(this, data,
options));
_this.fontSize = !options.flat && options.fontSize > options.width * 10 ? options.width * 10 : options
.fontSize;
// Make the guard bars go down half the way of the text
_this.guardHeight = options.height + _this.fontSize / 2 + options.textMargin;
return _this;
}
_createClass(EAN, [{
key: 'encode',
value: function encode() {
return this.options.flat ? this.encodeFlat() : this.encodeGuarded();
}
}, {
key: 'leftText',
value: function leftText(from, to) {
return this.text.substr(from, to);
}
}, {
key: 'leftEncode',
value: function leftEncode(data, structure) {
return (0, _encoder2)(data, structure);
}
}, {
key: 'rightText',
value: function rightText(from, to) {
return this.text.substr(from, to);
}
}, {
key: 'rightEncode',
value: function rightEncode(data, structure) {
return (0, _encoder2)(data, structure);
}
}, {
key: 'encodeGuarded',
value: function encodeGuarded() {
var textOptions = {
fontSize: this.fontSize
};
var guardOptions = {
height: this.guardHeight
};
return [{
data: _constants.SIDE_BIN,
options: guardOptions
}, {
data: this.leftEncode(),
text: this.leftText(),
options: textOptions
}, {
data: _constants.MIDDLE_BIN,
options: guardOptions
}, {
data: this.rightEncode(),
text: this.rightText(),
options: textOptions
}, {
data: _constants.SIDE_BIN,
options: guardOptions
}];
}
}, {
key: 'encodeFlat',
value: function encodeFlat() {
var data = [_constants.SIDE_BIN, this.leftEncode(), _constants.MIDDLE_BIN, this
.rightEncode(), _constants.SIDE_BIN
];
return {
data: data.join(''),
text: this.text
};
}
}]);
return EAN;
}(_Barcode3);
export default EAN;

View File

@@ -0,0 +1,186 @@
'use strict';
var _createClass = function() {
function defineProperties(target, props) {
for (var i = 0; i < props.length; i++) {
var descriptor = props[i];
descriptor.enumerable = descriptor.enumerable || false;
descriptor.configurable = true;
if ("value" in descriptor) descriptor.writable = true;
Object.defineProperty(target, descriptor.key, descriptor);
}
}
return function(Constructor, protoProps, staticProps) {
if (protoProps) defineProperties(Constructor.prototype, protoProps);
if (staticProps) defineProperties(Constructor, staticProps);
return Constructor;
};
}();
var _get = function get(object, property, receiver) {
if (object === null) object = Function.prototype;
var desc = Object.getOwnPropertyDescriptor(object, property);
if (desc === undefined) {
var parent = Object.getPrototypeOf(object);
if (parent === null) {
return undefined;
} else {
return get(parent, property, receiver);
}
} else if ("value" in desc) {
return desc.value;
} else {
var getter = desc.get;
if (getter === undefined) {
return undefined;
}
return getter.call(receiver);
}
};
import _constants from './constants'
import _EAN3 from './EAN'
function _interopRequireDefault(obj) {
return obj && obj.__esModule ? obj : {
default: obj
};
}
function _classCallCheck(instance, Constructor) {
if (!(instance instanceof Constructor)) {
throw new TypeError("Cannot call a class as a function");
}
}
function _possibleConstructorReturn(self, call) {
if (!self) {
throw new ReferenceError("this hasn't been initialised - super() hasn't been called");
}
return call && (typeof call === "object" || typeof call === "function") ? call : self;
}
function _inherits(subClass, superClass) {
if (typeof superClass !== "function" && superClass !== null) {
throw new TypeError("Super expression must either be null or a function, not " + typeof superClass);
}
subClass.prototype = Object.create(superClass && superClass.prototype, {
constructor: {
value: subClass,
enumerable: false,
writable: true,
configurable: true
}
});
if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ =
superClass;
} // Encoding documentation:
// https://en.wikipedia.org/wiki/International_Article_Number_(EAN)#Binary_encoding_of_data_digits_into_EAN-13_barcode
// Calculate the checksum digit
// https://en.wikipedia.org/wiki/International_Article_Number_(EAN)#Calculation_of_checksum_digit
var checksum = function checksum(number) {
var res = number.substr(0, 12).split('').map(function(n) {
return +n;
}).reduce(function(sum, a, idx) {
return idx % 2 ? sum + a * 3 : sum + a;
}, 0);
return (10 - res % 10) % 10;
};
var EAN13 = function(_EAN) {
_inherits(EAN13, _EAN);
function EAN13(data, options) {
_classCallCheck(this, EAN13);
// Add checksum if it does not exist
if (data.search(/^[0-9]{12}$/) !== -1) {
data += checksum(data);
}
// Adds a last character to the end of the barcode
var _this = _possibleConstructorReturn(this, (EAN13.__proto__ || Object.getPrototypeOf(EAN13)).call(this,
data, options));
_this.lastChar = options.lastChar;
return _this;
}
_createClass(EAN13, [{
key: 'valid',
value: function valid() {
return this.data.search(/^[0-9]{13}$/) !== -1 && +this.data[12] === checksum(this.data);
}
}, {
key: 'leftText',
value: function leftText() {
return _get(EAN13.prototype.__proto__ || Object.getPrototypeOf(EAN13.prototype),
'leftText', this).call(this, 1, 6);
}
}, {
key: 'leftEncode',
value: function leftEncode() {
var data = this.data.substr(1, 6);
var structure = _constants.EAN13_STRUCTURE[this.data[0]];
return _get(EAN13.prototype.__proto__ || Object.getPrototypeOf(EAN13.prototype),
'leftEncode', this).call(this, data, structure);
}
}, {
key: 'rightText',
value: function rightText() {
return _get(EAN13.prototype.__proto__ || Object.getPrototypeOf(EAN13.prototype),
'rightText', this).call(this, 7, 6);
}
}, {
key: 'rightEncode',
value: function rightEncode() {
var data = this.data.substr(7, 6);
return _get(EAN13.prototype.__proto__ || Object.getPrototypeOf(EAN13.prototype),
'rightEncode', this).call(this, data, 'RRRRRR');
}
// The "standard" way of printing EAN13 barcodes with guard bars
}, {
key: 'encodeGuarded',
value: function encodeGuarded() {
var data = _get(EAN13.prototype.__proto__ || Object.getPrototypeOf(EAN13.prototype),
'encodeGuarded', this).call(this);
// Extend data with left digit & last character
if (this.options.displayValue) {
data.unshift({
data: '000000000000',
text: this.text.substr(0, 1),
options: {
textAlign: 'left',
fontSize: this.fontSize
}
});
if (this.options.lastChar) {
data.push({
data: '00'
});
data.push({
data: '00000',
text: this.options.lastChar,
options: {
fontSize: this.fontSize
}
});
}
}
return data;
}
}]);
return EAN13;
}(_EAN3);
export default EAN13;

View File

@@ -0,0 +1,93 @@
'use strict';
var _createClass = function() {
function defineProperties(target, props) {
for (var i = 0; i < props.length; i++) {
var descriptor = props[i];
descriptor.enumerable = descriptor.enumerable || false;
descriptor.configurable = true;
if ("value" in descriptor) descriptor.writable = true;
Object.defineProperty(target, descriptor.key, descriptor);
}
}
return function(Constructor, protoProps, staticProps) {
if (protoProps) defineProperties(Constructor.prototype, protoProps);
if (staticProps) defineProperties(Constructor, staticProps);
return Constructor;
};
}();
import _constants from './constants'
import _encoder2 from './encoder'
import _Barcode3 from '../Barcode.js'
function _interopRequireDefault(obj) {
return obj && obj.__esModule ? obj : {
default: obj
};
}
function _classCallCheck(instance, Constructor) {
if (!(instance instanceof Constructor)) {
throw new TypeError("Cannot call a class as a function");
}
}
function _possibleConstructorReturn(self, call) {
if (!self) {
throw new ReferenceError("this hasn't been initialised - super() hasn't been called");
}
return call && (typeof call === "object" || typeof call === "function") ? call : self;
}
function _inherits(subClass, superClass) {
if (typeof superClass !== "function" && superClass !== null) {
throw new TypeError("Super expression must either be null or a function, not " + typeof superClass);
}
subClass.prototype = Object.create(superClass && superClass.prototype, {
constructor: {
value: subClass,
enumerable: false,
writable: true,
configurable: true
}
});
if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ =
superClass;
} // Encoding documentation:
// https://en.wikipedia.org/wiki/EAN_2#Encoding
var EAN2 = function(_Barcode) {
_inherits(EAN2, _Barcode);
function EAN2(data, options) {
_classCallCheck(this, EAN2);
return _possibleConstructorReturn(this, (EAN2.__proto__ || Object.getPrototypeOf(EAN2)).call(this, data,
options));
}
_createClass(EAN2, [{
key: 'valid',
value: function valid() {
return this.data.search(/^[0-9]{2}$/) !== -1;
}
}, {
key: 'encode',
value: function encode() {
// Choose the structure based on the number mod 4
var structure = _constants.EAN2_STRUCTURE[parseInt(this.data) % 4];
return {
// Start bits + Encode the two digits with 01 in between
data: '1011' + (0, _encoder2)(this.data, structure, '01'),
text: this.text
};
}
}]);
return EAN2;
}(_Barcode3);
export default EAN2;

View File

@@ -0,0 +1,100 @@
'use strict';
var _createClass = function() {
function defineProperties(target, props) {
for (var i = 0; i < props.length; i++) {
var descriptor = props[i];
descriptor.enumerable = descriptor.enumerable || false;
descriptor.configurable = true;
if ("value" in descriptor) descriptor.writable = true;
Object.defineProperty(target, descriptor.key, descriptor);
}
}
return function(Constructor, protoProps, staticProps) {
if (protoProps) defineProperties(Constructor.prototype, protoProps);
if (staticProps) defineProperties(Constructor, staticProps);
return Constructor;
};
}();
import _constants from './constants'
import _encoder2 from './encoder'
import _Barcode3 from '../Barcode.js'
function _interopRequireDefault(obj) {
return obj && obj.__esModule ? obj : {
default: obj
};
}
function _classCallCheck(instance, Constructor) {
if (!(instance instanceof Constructor)) {
throw new TypeError("Cannot call a class as a function");
}
}
function _possibleConstructorReturn(self, call) {
if (!self) {
throw new ReferenceError("this hasn't been initialised - super() hasn't been called");
}
return call && (typeof call === "object" || typeof call === "function") ? call : self;
}
function _inherits(subClass, superClass) {
if (typeof superClass !== "function" && superClass !== null) {
throw new TypeError("Super expression must either be null or a function, not " + typeof superClass);
}
subClass.prototype = Object.create(superClass && superClass.prototype, {
constructor: {
value: subClass,
enumerable: false,
writable: true,
configurable: true
}
});
if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ =
superClass;
} // Encoding documentation:
// https://en.wikipedia.org/wiki/EAN_5#Encoding
var checksum = function checksum(data) {
var result = data.split('').map(function(n) {
return +n;
}).reduce(function(sum, a, idx) {
return idx % 2 ? sum + a * 9 : sum + a * 3;
}, 0);
return result % 10;
};
var EAN5 = function(_Barcode) {
_inherits(EAN5, _Barcode);
function EAN5(data, options) {
_classCallCheck(this, EAN5);
return _possibleConstructorReturn(this, (EAN5.__proto__ || Object.getPrototypeOf(EAN5)).call(this, data,
options));
}
_createClass(EAN5, [{
key: 'valid',
value: function valid() {
return this.data.search(/^[0-9]{5}$/) !== -1;
}
}, {
key: 'encode',
value: function encode() {
var structure = _constants.EAN5_STRUCTURE[checksum(this.data)];
return {
data: '1011' + (0, _encoder2)(this.data, structure, '01'),
text: this.text
};
}
}]);
return EAN5;
}(_Barcode3);
export default EAN5;

View File

@@ -0,0 +1,142 @@
'use strict';
var _createClass = function() {
function defineProperties(target, props) {
for (var i = 0; i < props.length; i++) {
var descriptor = props[i];
descriptor.enumerable = descriptor.enumerable || false;
descriptor.configurable = true;
if ("value" in descriptor) descriptor.writable = true;
Object.defineProperty(target, descriptor.key, descriptor);
}
}
return function(Constructor, protoProps, staticProps) {
if (protoProps) defineProperties(Constructor.prototype, protoProps);
if (staticProps) defineProperties(Constructor, staticProps);
return Constructor;
};
}();
var _get = function get(object, property, receiver) {
if (object === null) object = Function.prototype;
var desc = Object.getOwnPropertyDescriptor(object, property);
if (desc === undefined) {
var parent = Object.getPrototypeOf(object);
if (parent === null) {
return undefined;
} else {
return get(parent, property, receiver);
}
} else if ("value" in desc) {
return desc.value;
} else {
var getter = desc.get;
if (getter === undefined) {
return undefined;
}
return getter.call(receiver);
}
};
import _EAN3 from './EAN'
function _interopRequireDefault(obj) {
return obj && obj.__esModule ? obj : {
default: obj
};
}
function _classCallCheck(instance, Constructor) {
if (!(instance instanceof Constructor)) {
throw new TypeError("Cannot call a class as a function");
}
}
function _possibleConstructorReturn(self, call) {
if (!self) {
throw new ReferenceError("this hasn't been initialised - super() hasn't been called");
}
return call && (typeof call === "object" || typeof call === "function") ? call : self;
}
function _inherits(subClass, superClass) {
if (typeof superClass !== "function" && superClass !== null) {
throw new TypeError("Super expression must either be null or a function, not " + typeof superClass);
}
subClass.prototype = Object.create(superClass && superClass.prototype, {
constructor: {
value: subClass,
enumerable: false,
writable: true,
configurable: true
}
});
if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ =
superClass;
} // Encoding documentation:
// http://www.barcodeisland.com/ean8.phtml
// Calculate the checksum digit
var checksum = function checksum(number) {
var res = number.substr(0, 7).split('').map(function(n) {
return +n;
}).reduce(function(sum, a, idx) {
return idx % 2 ? sum + a : sum + a * 3;
}, 0);
return (10 - res % 10) % 10;
};
var EAN8 = function(_EAN) {
_inherits(EAN8, _EAN);
function EAN8(data, options) {
_classCallCheck(this, EAN8);
// Add checksum if it does not exist
if (data.search(/^[0-9]{7}$/) !== -1) {
data += checksum(data);
}
return _possibleConstructorReturn(this, (EAN8.__proto__ || Object.getPrototypeOf(EAN8)).call(this, data,
options));
}
_createClass(EAN8, [{
key: 'valid',
value: function valid() {
return this.data.search(/^[0-9]{8}$/) !== -1 && +this.data[7] === checksum(this.data);
}
}, {
key: 'leftText',
value: function leftText() {
return _get(EAN8.prototype.__proto__ || Object.getPrototypeOf(EAN8.prototype),
'leftText', this).call(this, 0, 4);
}
}, {
key: 'leftEncode',
value: function leftEncode() {
var data = this.data.substr(0, 4);
return _get(EAN8.prototype.__proto__ || Object.getPrototypeOf(EAN8.prototype),
'leftEncode', this).call(this, data, 'LLLL');
}
}, {
key: 'rightText',
value: function rightText() {
return _get(EAN8.prototype.__proto__ || Object.getPrototypeOf(EAN8.prototype),
'rightText', this).call(this, 4, 4);
}
}, {
key: 'rightEncode',
value: function rightEncode() {
var data = this.data.substr(4, 4);
return _get(EAN8.prototype.__proto__ || Object.getPrototypeOf(EAN8.prototype),
'rightEncode', this).call(this, data, 'RRRR');
}
}]);
return EAN8;
}(_EAN3);
export default EAN8;

View File

@@ -0,0 +1,210 @@
"use strict";
var _createClass = function() {
function defineProperties(target, props) {
for (var i = 0; i < props.length; i++) {
var descriptor = props[i];
descriptor.enumerable = descriptor.enumerable || false;
descriptor.configurable = true;
if ("value" in descriptor) descriptor.writable = true;
Object.defineProperty(target, descriptor.key, descriptor);
}
}
return function(Constructor, protoProps, staticProps) {
if (protoProps) defineProperties(Constructor.prototype, protoProps);
if (staticProps) defineProperties(Constructor, staticProps);
return Constructor;
};
}();
import _encoder2 from './encoder'
import _Barcode3 from '../Barcode.js'
function _classCallCheck(instance, Constructor) {
if (!(instance instanceof Constructor)) {
throw new TypeError("Cannot call a class as a function");
}
}
function _possibleConstructorReturn(self, call) {
if (!self) {
throw new ReferenceError("this hasn't been initialised - super() hasn't been called");
}
return call && (typeof call === "object" || typeof call === "function") ? call : self;
}
function _inherits(subClass, superClass) {
if (typeof superClass !== "function" && superClass !== null) {
throw new TypeError("Super expression must either be null or a function, not " + typeof superClass);
}
subClass.prototype = Object.create(superClass && superClass.prototype, {
constructor: {
value: subClass,
enumerable: false,
writable: true,
configurable: true
}
});
if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ =
superClass;
} // Encoding documentation:
// https://en.wikipedia.org/wiki/Universal_Product_Code#Encoding
var UPC = function(_Barcode) {
function UPC(data, options) {
_classCallCheck(this, UPC);
// Add checksum if it does not exist
if (data.search(/^[0-9]{11}$/) !== -1) {
data += checksum(data);
}
var _this = _possibleConstructorReturn(this, (UPC.__proto__ || Object.getPrototypeOf(UPC)).call(this, data,
options));
_this.displayValue = options.displayValue;
// Make sure the font is not bigger than the space between the guard bars
if (options.fontSize > options.width * 10) {
_this.fontSize = options.width * 10;
} else {
_this.fontSize = options.fontSize;
}
// Make the guard bars go down half the way of the text
_this.guardHeight = options.height + _this.fontSize / 2 + options.textMargin;
return _this;
}
_createClass(UPC, [{
key: "valid",
value: function valid() {
return this.data.search(/^[0-9]{12}$/) !== -1 && this.data[11] == checksum(this.data);
}
}, {
key: "encode",
value: function encode() {
if (this.options.flat) {
return this.flatEncoding();
} else {
return this.guardedEncoding();
}
}
}, {
key: "flatEncoding",
value: function flatEncoding() {
var result = "";
result += "101";
result += (0, _encoder2)(this.data.substr(0, 6), "LLLLLL");
result += "01010";
result += (0, _encoder2)(this.data.substr(6, 6), "RRRRRR");
result += "101";
return {
data: result,
text: this.text
};
}
}, {
key: "guardedEncoding",
value: function guardedEncoding() {
var result = [];
// Add the first digit
if (this.displayValue) {
result.push({
data: "00000000",
text: this.text.substr(0, 1),
options: {
textAlign: "left",
fontSize: this.fontSize
}
});
}
// Add the guard bars
result.push({
data: "101" + (0, _encoder2)(this.data[0], "L"),
options: {
height: this.guardHeight
}
});
// Add the left side
result.push({
data: (0, _encoder2)(this.data.substr(1, 5), "LLLLL"),
text: this.text.substr(1, 5),
options: {
fontSize: this.fontSize
}
});
// Add the middle bits
result.push({
data: "01010",
options: {
height: this.guardHeight
}
});
// Add the right side
result.push({
data: (0, _encoder2)(this.data.substr(6, 5), "RRRRR"),
text: this.text.substr(6, 5),
options: {
fontSize: this.fontSize
}
});
// Add the end bits
result.push({
data: (0, _encoder2)(this.data[11], "R") + "101",
options: {
height: this.guardHeight
}
});
// Add the last digit
if (this.displayValue) {
result.push({
data: "00000000",
text: this.text.substr(11, 1),
options: {
textAlign: "right",
fontSize: this.fontSize
}
});
}
return result;
}
}]);
return UPC;
}(_Barcode3);
// Calulate the checksum digit
// https://en.wikipedia.org/wiki/International_Article_Number_(EAN)#Calculation_of_checksum_digit
function checksum(number) {
var result = 0;
var i;
for (i = 1; i < 11; i += 2) {
result += parseInt(number[i]);
}
for (i = 0; i < 11; i += 2) {
result += parseInt(number[i]) * 3;
}
return (10 - result % 10) % 10;
}
export default {
UPC,
checksum
};

View File

@@ -0,0 +1,245 @@
'use strict';
var _createClass = function() {
function defineProperties(target, props) {
for (var i = 0; i < props.length; i++) {
var descriptor = props[i];
descriptor.enumerable = descriptor.enumerable || false;
descriptor.configurable = true;
if ("value" in descriptor) descriptor.writable = true;
Object.defineProperty(target, descriptor.key, descriptor);
}
}
return function(Constructor, protoProps, staticProps) {
if (protoProps) defineProperties(Constructor.prototype, protoProps);
if (staticProps) defineProperties(Constructor, staticProps);
return Constructor;
};
}();
import _encoder2 from './encoder'
import _Barcode3 from '../Barcode.js'
import _UPC from './UPC.js'
function _interopRequireDefault(obj) {
return obj && obj.__esModule ? obj : {
default: obj
};
}
function _classCallCheck(instance, Constructor) {
if (!(instance instanceof Constructor)) {
throw new TypeError("Cannot call a class as a function");
}
}
function _possibleConstructorReturn(self, call) {
if (!self) {
throw new ReferenceError("this hasn't been initialised - super() hasn't been called");
}
return call && (typeof call === "object" || typeof call === "function") ? call : self;
}
function _inherits(subClass, superClass) {
if (typeof superClass !== "function" && superClass !== null) {
throw new TypeError("Super expression must either be null or a function, not " + typeof superClass);
}
subClass.prototype = Object.create(superClass && superClass.prototype, {
constructor: {
value: subClass,
enumerable: false,
writable: true,
configurable: true
}
});
if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ =
superClass;
} // Encoding documentation:
// https://en.wikipedia.org/wiki/Universal_Product_Code#Encoding
//
// UPC-E documentation:
// https://en.wikipedia.org/wiki/Universal_Product_Code#UPC-E
var EXPANSIONS = ["XX00000XXX", "XX10000XXX", "XX20000XXX", "XXX00000XX", "XXXX00000X", "XXXXX00005", "XXXXX00006",
"XXXXX00007", "XXXXX00008", "XXXXX00009"
];
var PARITIES = [
["EEEOOO", "OOOEEE"],
["EEOEOO", "OOEOEE"],
["EEOOEO", "OOEEOE"],
["EEOOOE", "OOEEEO"],
["EOEEOO", "OEOOEE"],
["EOOEEO", "OEEOOE"],
["EOOOEE", "OEEEOO"],
["EOEOEO", "OEOEOE"],
["EOEOOE", "OEOEEO"],
["EOOEOE", "OEEOEO"]
];
var UPCE = function(_Barcode) {
_inherits(UPCE, _Barcode);
function UPCE(data, options) {
_classCallCheck(this, UPCE);
var _this = _possibleConstructorReturn(this, (UPCE.__proto__ || Object.getPrototypeOf(UPCE)).call(this,
data, options));
// Code may be 6 or 8 digits;
// A 7 digit code is ambiguous as to whether the extra digit
// is a UPC-A check or number system digit.
_this.isValid = false;
if (data.search(/^[0-9]{6}$/) !== -1) {
_this.middleDigits = data;
_this.upcA = expandToUPCA(data, "0");
_this.text = options.text || '' + _this.upcA[0] + data + _this.upcA[_this.upcA.length - 1];
_this.isValid = true;
} else if (data.search(/^[01][0-9]{7}$/) !== -1) {
_this.middleDigits = data.substring(1, data.length - 1);
_this.upcA = expandToUPCA(_this.middleDigits, data[0]);
if (_this.upcA[_this.upcA.length - 1] === data[data.length - 1]) {
_this.isValid = true;
} else {
// checksum mismatch
return _possibleConstructorReturn(_this);
}
} else {
return _possibleConstructorReturn(_this);
}
_this.displayValue = options.displayValue;
// Make sure the font is not bigger than the space between the guard bars
if (options.fontSize > options.width * 10) {
_this.fontSize = options.width * 10;
} else {
_this.fontSize = options.fontSize;
}
// Make the guard bars go down half the way of the text
_this.guardHeight = options.height + _this.fontSize / 2 + options.textMargin;
return _this;
}
_createClass(UPCE, [{
key: 'valid',
value: function valid() {
return this.isValid;
}
}, {
key: 'encode',
value: function encode() {
if (this.options.flat) {
return this.flatEncoding();
} else {
return this.guardedEncoding();
}
}
}, {
key: 'flatEncoding',
value: function flatEncoding() {
var result = "";
result += "101";
result += this.encodeMiddleDigits();
result += "010101";
return {
data: result,
text: this.text
};
}
}, {
key: 'guardedEncoding',
value: function guardedEncoding() {
var result = [];
// Add the UPC-A number system digit beneath the quiet zone
if (this.displayValue) {
result.push({
data: "00000000",
text: this.text[0],
options: {
textAlign: "left",
fontSize: this.fontSize
}
});
}
// Add the guard bars
result.push({
data: "101",
options: {
height: this.guardHeight
}
});
// Add the 6 UPC-E digits
result.push({
data: this.encodeMiddleDigits(),
text: this.text.substring(1, 7),
options: {
fontSize: this.fontSize
}
});
// Add the end bits
result.push({
data: "010101",
options: {
height: this.guardHeight
}
});
// Add the UPC-A check digit beneath the quiet zone
if (this.displayValue) {
result.push({
data: "00000000",
text: this.text[7],
options: {
textAlign: "right",
fontSize: this.fontSize
}
});
}
return result;
}
}, {
key: 'encodeMiddleDigits',
value: function encodeMiddleDigits() {
var numberSystem = this.upcA[0];
var checkDigit = this.upcA[this.upcA.length - 1];
var parity = PARITIES[parseInt(checkDigit)][parseInt(numberSystem)];
return (0, _encoder2)(this.middleDigits, parity);
}
}]);
return UPCE;
}(_Barcode3);
function expandToUPCA(middleDigits, numberSystem) {
var lastUpcE = parseInt(middleDigits[middleDigits.length - 1]);
var expansion = EXPANSIONS[lastUpcE];
var result = "";
var digitIndex = 0;
for (var i = 0; i < expansion.length; i++) {
var c = expansion[i];
if (c === 'X') {
result += middleDigits[digitIndex++];
} else {
result += c;
}
}
result = '' + numberSystem + result;
return '' + result + (0, _UPC.checksum)(result);
}
export default UPCE;

View File

@@ -0,0 +1,48 @@
'use strict';
// Standard start end and middle bits
var SIDE_BIN = '101';
var MIDDLE_BIN = '01010';
var BINARIES = {
'L': [ // The L (left) type of encoding
'0001101', '0011001', '0010011', '0111101', '0100011', '0110001', '0101111', '0111011', '0110111',
'0001011'
],
'G': [ // The G type of encoding
'0100111', '0110011', '0011011', '0100001', '0011101', '0111001', '0000101', '0010001', '0001001',
'0010111'
],
'R': [ // The R (right) type of encoding
'1110010', '1100110', '1101100', '1000010', '1011100', '1001110', '1010000', '1000100', '1001000',
'1110100'
],
'O': [ // The O (odd) encoding for UPC-E
'0001101', '0011001', '0010011', '0111101', '0100011', '0110001', '0101111', '0111011', '0110111',
'0001011'
],
'E': [ // The E (even) encoding for UPC-E
'0100111', '0110011', '0011011', '0100001', '0011101', '0111001', '0000101', '0010001', '0001001',
'0010111'
]
};
// Define the EAN-2 structure
var EAN2_STRUCTURE = ['LL', 'LG', 'GL', 'GG'];
// Define the EAN-5 structure
var EAN5_STRUCTURE = ['GGLLL', 'GLGLL', 'GLLGL', 'GLLLG', 'LGGLL', 'LLGGL', 'LLLGG', 'LGLGL', 'LGLLG', 'LLGLG'];
// Define the EAN-13 structure
var EAN13_STRUCTURE = ['LLLLLL', 'LLGLGG', 'LLGGLG', 'LLGGGL', 'LGLLGG', 'LGGLLG', 'LGGGLL', 'LGLGLG', 'LGLGGL',
'LGGLGL'
];
export default {
SIDE_BIN,
MIDDLE_BIN,
BINARIES,
EAN2_STRUCTURE,
EAN5_STRUCTURE,
EAN13_STRUCTURE
}

View File

@@ -0,0 +1,23 @@
'use strict';
import _constants from './constants'
// Encode data string
var encode = function encode(data, structure, separator) {
var encoded = data.split('').map(function(val, idx) {
return _constants.BINARIES[structure[idx]];
}).map(function(val, idx) {
return val ? val[data[idx]] : '';
});
if (separator) {
var last = data.length - 1;
encoded = encoded.map(function(val, idx) {
return idx < last ? val + separator : val;
});
}
return encoded.join('');
};
export default encode

View File

@@ -0,0 +1,22 @@
'use strict';
import EAN13 from './EAN13'
import EAN8 from './EAN8.js'
import EAN5 from './EAN5.js'
import EAN2 from './EAN2.js'
import UPC from './UPC.js'
import UPCE from './UPCE.js'
export default {
EAN13,
EAN8,
EAN5,
EAN2,
UPC: UPC.UPC,
UPCE
}

View File

@@ -0,0 +1,100 @@
'use strict';
var _createClass = function() {
function defineProperties(target, props) {
for (var i = 0; i < props.length; i++) {
var descriptor = props[i];
descriptor.enumerable = descriptor.enumerable || false;
descriptor.configurable = true;
if ("value" in descriptor) descriptor.writable = true;
Object.defineProperty(target, descriptor.key, descriptor);
}
}
return function(Constructor, protoProps, staticProps) {
if (protoProps) defineProperties(Constructor.prototype, protoProps);
if (staticProps) defineProperties(Constructor, staticProps);
return Constructor;
};
}();
import _constants from './constants'
import _Barcode3 from '../Barcode'
function _classCallCheck(instance, Constructor) {
if (!(instance instanceof Constructor)) {
throw new TypeError("Cannot call a class as a function");
}
}
function _possibleConstructorReturn(self, call) {
if (!self) {
throw new ReferenceError("this hasn't been initialised - super() hasn't been called");
}
return call && (typeof call === "object" || typeof call === "function") ? call : self;
}
function _inherits(subClass, superClass) {
if (typeof superClass !== "function" && superClass !== null) {
throw new TypeError("Super expression must either be null or a function, not " + typeof superClass);
}
subClass.prototype = Object.create(superClass && superClass.prototype, {
constructor: {
value: subClass,
enumerable: false,
writable: true,
configurable: true
}
});
if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ =
superClass;
}
var ITF = function(_Barcode) {
_inherits(ITF, _Barcode);
function ITF() {
_classCallCheck(this, ITF);
return _possibleConstructorReturn(this, (ITF.__proto__ || Object.getPrototypeOf(ITF)).apply(this,
arguments));
}
_createClass(ITF, [{
key: 'valid',
value: function valid() {
return this.data.search(/^([0-9]{2})+$/) !== -1;
}
}, {
key: 'encode',
value: function encode() {
var _this2 = this;
// Calculate all the digit pairs
var encoded = this.data.match(/.{2}/g).map(function(pair) {
return _this2.encodePair(pair);
}).join('');
return {
data: _constants.START_BIN + encoded + _constants.END_BIN,
text: this.text
};
}
// Calculate the data of a number pair
}, {
key: 'encodePair',
value: function encodePair(pair) {
var second = _constants.BINARIES[pair[1]];
return _constants.BINARIES[pair[0]].split('').map(function(first, idx) {
return (first === '1' ? '111' : '1') + (second[idx] === '1' ? '000' : '0');
}).join('');
}
}]);
return ITF;
}(_Barcode3);
export default ITF;

View File

@@ -0,0 +1,93 @@
'use strict';
var _createClass = function() {
function defineProperties(target, props) {
for (var i = 0; i < props.length; i++) {
var descriptor = props[i];
descriptor.enumerable = descriptor.enumerable || false;
descriptor.configurable = true;
if ("value" in descriptor) descriptor.writable = true;
Object.defineProperty(target, descriptor.key, descriptor);
}
}
return function(Constructor, protoProps, staticProps) {
if (protoProps) defineProperties(Constructor.prototype, protoProps);
if (staticProps) defineProperties(Constructor, staticProps);
return Constructor;
};
}();
import _ITF3 from './ITF'
function _interopRequireDefault(obj) {
return obj && obj.__esModule ? obj : {
default: obj
};
}
function _classCallCheck(instance, Constructor) {
if (!(instance instanceof Constructor)) {
throw new TypeError("Cannot call a class as a function");
}
}
function _possibleConstructorReturn(self, call) {
if (!self) {
throw new ReferenceError("this hasn't been initialised - super() hasn't been called");
}
return call && (typeof call === "object" || typeof call === "function") ? call : self;
}
function _inherits(subClass, superClass) {
if (typeof superClass !== "function" && superClass !== null) {
throw new TypeError("Super expression must either be null or a function, not " + typeof superClass);
}
subClass.prototype = Object.create(superClass && superClass.prototype, {
constructor: {
value: subClass,
enumerable: false,
writable: true,
configurable: true
}
});
if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ =
superClass;
}
// Calculate the checksum digit
var checksum = function checksum(data) {
var res = data.substr(0, 13).split('').map(function(num) {
return parseInt(num, 10);
}).reduce(function(sum, n, idx) {
return sum + n * (3 - idx % 2 * 2);
}, 0);
return Math.ceil(res / 10) * 10 - res;
};
var ITF14 = function(_ITF) {
_inherits(ITF14, _ITF);
function ITF14(data, options) {
_classCallCheck(this, ITF14);
// Add checksum if it does not exist
if (data.search(/^[0-9]{13}$/) !== -1) {
data += checksum(data);
}
return _possibleConstructorReturn(this, (ITF14.__proto__ || Object.getPrototypeOf(ITF14)).call(this, data,
options));
}
_createClass(ITF14, [{
key: 'valid',
value: function valid() {
return this.data.search(/^[0-9]{14}$/) !== -1 && +this.data[13] === checksum(this.data);
}
}]);
return ITF14;
}(_ITF3);
export default ITF14;

View File

@@ -0,0 +1,11 @@
'use strict';
var START_BIN = '1010';
var END_BIN = '11101';
var BINARIES = ['00110', '10001', '01001', '11000', '00101', '10100', '01100', '00011', '10010', '01010'];
export default {
START_BIN,
END_BIN,
BINARIES
}

View File

@@ -0,0 +1,9 @@
'use strict';
import ITF from './ITF'
import ITF14 from './ITF14'
export default {
ITF,
ITF14
}

View File

@@ -0,0 +1,111 @@
"use strict";
var _createClass = function() {
function defineProperties(target, props) {
for (var i = 0; i < props.length; i++) {
var descriptor = props[i];
descriptor.enumerable = descriptor.enumerable || false;
descriptor.configurable = true;
if ("value" in descriptor) descriptor.writable = true;
Object.defineProperty(target, descriptor.key, descriptor);
}
}
return function(Constructor, protoProps, staticProps) {
if (protoProps) defineProperties(Constructor.prototype, protoProps);
if (staticProps) defineProperties(Constructor, staticProps);
return Constructor;
};
}();
import _Barcode3 from '../Barcode.js'
function _interopRequireDefault(obj) {
return obj && obj.__esModule ? obj : {
default: obj
};
}
function _classCallCheck(instance, Constructor) {
if (!(instance instanceof Constructor)) {
throw new TypeError("Cannot call a class as a function");
}
}
function _possibleConstructorReturn(self, call) {
if (!self) {
throw new ReferenceError("this hasn't been initialised - super() hasn't been called");
}
return call && (typeof call === "object" || typeof call === "function") ? call : self;
}
function _inherits(subClass, superClass) {
if (typeof superClass !== "function" && superClass !== null) {
throw new TypeError("Super expression must either be null or a function, not " + typeof superClass);
}
subClass.prototype = Object.create(superClass && superClass.prototype, {
constructor: {
value: subClass,
enumerable: false,
writable: true,
configurable: true
}
});
if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ =
superClass;
} // Encoding documentation
// https://en.wikipedia.org/wiki/MSI_Barcode#Character_set_and_binary_lookup
var MSI = function(_Barcode) {
_inherits(MSI, _Barcode);
function MSI(data, options) {
_classCallCheck(this, MSI);
return _possibleConstructorReturn(this, (MSI.__proto__ || Object.getPrototypeOf(MSI)).call(this, data,
options));
}
_createClass(MSI, [{
key: "encode",
value: function encode() {
// Start bits
var ret = "110";
for (var i = 0; i < this.data.length; i++) {
// Convert the character to binary (always 4 binary digits)
var digit = parseInt(this.data[i]);
var bin = digit.toString(2);
bin = addYunzhupaases(bin, 4 - bin.length);
// Add 100 for every yunzhupaas and 110 for every 1
for (var b = 0; b < bin.length; b++) {
ret += bin[b] == "0" ? "100" : "110";
}
}
// End bits
ret += "1001";
return {
data: ret,
text: this.text
};
}
}, {
key: "valid",
value: function valid() {
return this.data.search(/^[0-9]+$/) !== -1;
}
}]);
return MSI;
}(_Barcode3);
function addYunzhupaases(number, n) {
for (var i = 0; i < n; i++) {
number = "0" + number;
}
return number;
}
export default MSI;

View File

@@ -0,0 +1,49 @@
'use strict';
import _MSI3 from './MSI.js'
import _checksums from './checksums.js'
function _classCallCheck(instance, Constructor) {
if (!(instance instanceof Constructor)) {
throw new TypeError("Cannot call a class as a function");
}
}
function _possibleConstructorReturn(self, call) {
if (!self) {
throw new ReferenceError("this hasn't been initialised - super() hasn't been called");
}
return call && (typeof call === "object" || typeof call === "function") ? call : self;
}
function _inherits(subClass, superClass) {
if (typeof superClass !== "function" && superClass !== null) {
throw new TypeError("Super expression must either be null or a function, not " + typeof superClass);
}
subClass.prototype = Object.create(superClass && superClass.prototype, {
constructor: {
value: subClass,
enumerable: false,
writable: true,
configurable: true
}
});
if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ =
superClass;
}
var MSI10 = function(_MSI) {
_inherits(MSI10, _MSI);
function MSI10(data, options) {
_classCallCheck(this, MSI10);
return _possibleConstructorReturn(this, (MSI10.__proto__ || Object.getPrototypeOf(MSI10)).call(this, data +
(0, _checksums.mod10)(data), options));
}
return MSI10;
}(_MSI3);
export default MSI10;

View File

@@ -0,0 +1,51 @@
'use strict';
import _MSI3 from './MSI.js'
import _checksums from './checksums.js'
function _classCallCheck(instance, Constructor) {
if (!(instance instanceof Constructor)) {
throw new TypeError("Cannot call a class as a function");
}
}
function _possibleConstructorReturn(self, call) {
if (!self) {
throw new ReferenceError("this hasn't been initialised - super() hasn't been called");
}
return call && (typeof call === "object" || typeof call === "function") ? call : self;
}
function _inherits(subClass, superClass) {
if (typeof superClass !== "function" && superClass !== null) {
throw new TypeError("Super expression must either be null or a function, not " + typeof superClass);
}
subClass.prototype = Object.create(superClass && superClass.prototype, {
constructor: {
value: subClass,
enumerable: false,
writable: true,
configurable: true
}
});
if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ =
superClass;
}
var MSI1010 = function(_MSI) {
_inherits(MSI1010, _MSI);
function MSI1010(data, options) {
_classCallCheck(this, MSI1010);
data += (0, _checksums.mod10)(data);
data += (0, _checksums.mod10)(data);
return _possibleConstructorReturn(this, (MSI1010.__proto__ || Object.getPrototypeOf(MSI1010)).call(this,
data, options));
}
return MSI1010;
}(_MSI3);
export default MSI1010;

View File

@@ -0,0 +1,50 @@
'use strict';
import _MSI3 from './MSI.js'
import _checksums from './checksums.js'
function _classCallCheck(instance, Constructor) {
if (!(instance instanceof Constructor)) {
throw new TypeError("Cannot call a class as a function");
}
}
function _possibleConstructorReturn(self, call) {
if (!self) {
throw new ReferenceError("this hasn't been initialised - super() hasn't been called");
}
return call && (typeof call === "object" || typeof call === "function") ? call : self;
}
function _inherits(subClass, superClass) {
if (typeof superClass !== "function" && superClass !== null) {
throw new TypeError("Super expression must either be null or a function, not " + typeof superClass);
}
subClass.prototype = Object.create(superClass && superClass.prototype, {
constructor: {
value: subClass,
enumerable: false,
writable: true,
configurable: true
}
});
if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ =
superClass;
}
var MSI11 = function(_MSI) {
_inherits(MSI11, _MSI);
function MSI11(data, options) {
_classCallCheck(this, MSI11);
return _possibleConstructorReturn(this, (MSI11.__proto__ || Object.getPrototypeOf(MSI11)).call(this, data +
(0, _checksums.mod11)(data), options));
}
return MSI11;
}(_MSI3);
export default MSI11;

View File

@@ -0,0 +1,51 @@
'use strict';
import _MSI3 from './MSI.js'
import _checksums from './checksums.js'
function _classCallCheck(instance, Constructor) {
if (!(instance instanceof Constructor)) {
throw new TypeError("Cannot call a class as a function");
}
}
function _possibleConstructorReturn(self, call) {
if (!self) {
throw new ReferenceError("this hasn't been initialised - super() hasn't been called");
}
return call && (typeof call === "object" || typeof call === "function") ? call : self;
}
function _inherits(subClass, superClass) {
if (typeof superClass !== "function" && superClass !== null) {
throw new TypeError("Super expression must either be null or a function, not " + typeof superClass);
}
subClass.prototype = Object.create(superClass && superClass.prototype, {
constructor: {
value: subClass,
enumerable: false,
writable: true,
configurable: true
}
});
if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ =
superClass;
}
var MSI1110 = function(_MSI) {
_inherits(MSI1110, _MSI);
function MSI1110(data, options) {
_classCallCheck(this, MSI1110);
data += (0, _checksums.mod11)(data);
data += (0, _checksums.mod10)(data);
return _possibleConstructorReturn(this, (MSI1110.__proto__ || Object.getPrototypeOf(MSI1110)).call(this,
data, options));
}
return MSI1110;
}(_MSI3);
export default MSI1110;

View File

@@ -0,0 +1,29 @@
"use strict";
function mod10(number) {
var sum = 0;
for (var i = 0; i < number.length; i++) {
var n = parseInt(number[i]);
if ((i + number.length) % 2 === 0) {
sum += n;
} else {
sum += n * 2 % 10 + Math.floor(n * 2 / 10);
}
}
return (10 - sum % 10) % 10;
}
function mod11(number) {
var sum = 0;
var weights = [2, 3, 4, 5, 6, 7];
for (var i = 0; i < number.length; i++) {
var n = parseInt(number[number.length - 1 - i]);
sum += weights[i % weights.length] * n;
}
return (11 - sum % 11) % 11;
}
export default {
mod10,
mod11
}

View File

@@ -0,0 +1,19 @@
'use strict';
import MSI from './MSI.js'
import MSI10 from './MSI10.js'
import MSI11 from './MSI11.js'
import MSI1010 from './MSI1010.js'
import MSI1110 from './MSI1110.js'
export default {
MSI,
MSI10,
MSI11,
MSI1010,
MSI1110
}

View File

@@ -0,0 +1,129 @@
"use strict";
var _createClass = function() {
function defineProperties(target, props) {
for (var i = 0; i < props.length; i++) {
var descriptor = props[i];
descriptor.enumerable = descriptor.enumerable || false;
descriptor.configurable = true;
if ("value" in descriptor) descriptor.writable = true;
Object.defineProperty(target, descriptor.key, descriptor);
}
}
return function(Constructor, protoProps, staticProps) {
if (protoProps) defineProperties(Constructor.prototype, protoProps);
if (staticProps) defineProperties(Constructor, staticProps);
return Constructor;
};
}();
import _Barcode3 from '../Barcode.js'
function _interopRequireDefault(obj) {
return obj && obj.__esModule ? obj : {
default: obj
};
}
function _classCallCheck(instance, Constructor) {
if (!(instance instanceof Constructor)) {
throw new TypeError("Cannot call a class as a function");
}
}
function _possibleConstructorReturn(self, call) {
if (!self) {
throw new ReferenceError("this hasn't been initialised - super() hasn't been called");
}
return call && (typeof call === "object" || typeof call === "function") ? call : self;
}
function _inherits(subClass, superClass) {
if (typeof superClass !== "function" && superClass !== null) {
throw new TypeError("Super expression must either be null or a function, not " + typeof superClass);
}
subClass.prototype = Object.create(superClass && superClass.prototype, {
constructor: {
value: subClass,
enumerable: false,
writable: true,
configurable: true
}
});
if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ =
superClass;
} // Encoding specification:
// http://www.barcodeisland.com/codabar.phtml
var codabar = function(_Barcode) {
_inherits(codabar, _Barcode);
function codabar(data, options) {
_classCallCheck(this, codabar);
if (data.search(/^[0-9\-\$\:\.\+\/]+$/) === 0) {
data = "A" + data + "A";
}
var _this = _possibleConstructorReturn(this, (codabar.__proto__ || Object.getPrototypeOf(codabar)).call(
this, data.toUpperCase(), options));
_this.text = _this.options.text || _this.text.replace(/[A-D]/g, '');
return _this;
}
_createClass(codabar, [{
key: "valid",
value: function valid() {
return this.data.search(/^[A-D][0-9\-\$\:\.\+\/]+[A-D]$/) !== -1;
}
}, {
key: "encode",
value: function encode() {
var result = [];
var encodings = this.getEncodings();
for (var i = 0; i < this.data.length; i++) {
result.push(encodings[this.data.charAt(i)]);
// for all characters except the last, append a narrow-space ("0")
if (i !== this.data.length - 1) {
result.push("0");
}
}
return {
text: this.text,
data: result.join('')
};
}
}, {
key: "getEncodings",
value: function getEncodings() {
return {
"0": "101010011",
"1": "101011001",
"2": "101001011",
"3": "110010101",
"4": "101101001",
"5": "110101001",
"6": "100101011",
"7": "100101101",
"8": "100110101",
"9": "110100101",
"-": "101001101",
"$": "101100101",
":": "1101011011",
"/": "1101101011",
".": "1101101101",
"+": "101100110011",
"A": "1011001001",
"B": "1001001011",
"C": "1010010011",
"D": "1010011001"
};
}
}]);
return codabar;
}(_Barcode3);
export default codabar;

View File

@@ -0,0 +1,37 @@
'use strict';
import _CODE from './CODE39/'
import _CODE2 from './CODE128/'
import _EAN_UPC from './EAN_UPC/'
import _ITF from './ITF/'
import _MSI from './MSI/'
import _pharmacode from './pharmacode/'
import _codabar from './codabar'
export default {
CODE128: _CODE2.CODE128,
CODE128A: _CODE2.CODE128A,
CODE128B: _CODE2.CODE128B,
CODE128C: _CODE2.CODE128C,
EAN13: _EAN_UPC.EAN13,
EAN8: _EAN_UPC.EAN8,
EAN5: _EAN_UPC.EAN5,
EAN2: _EAN_UPC.EAN2,
UPC: _EAN_UPC.UPCE,
UPCE: _EAN_UPC.UPCE,
ITF14: _ITF.ITF14,
ITF: _ITF.ITF,
MSI: _MSI.MSI,
MSI10: _MSI.MSI10,
MSI11: _MSI.MSI11,
MSI1010: _MSI.MSI1010,
MSI1110: _MSI.MSI1110,
PHARMACODE: _pharmacode,
CODABAR: _codabar,
CODE39: _CODE,
}

View File

@@ -0,0 +1,103 @@
"use strict";
var _createClass = function() {
function defineProperties(target, props) {
for (var i = 0; i < props.length; i++) {
var descriptor = props[i];
descriptor.enumerable = descriptor.enumerable || false;
descriptor.configurable = true;
if ("value" in descriptor) descriptor.writable = true;
Object.defineProperty(target, descriptor.key, descriptor);
}
}
return function(Constructor, protoProps, staticProps) {
if (protoProps) defineProperties(Constructor.prototype, protoProps);
if (staticProps) defineProperties(Constructor, staticProps);
return Constructor;
};
}();
import _Barcode3 from '../Barcode.js'
function _classCallCheck(instance, Constructor) {
if (!(instance instanceof Constructor)) {
throw new TypeError("Cannot call a class as a function");
}
}
function _possibleConstructorReturn(self, call) {
if (!self) {
throw new ReferenceError("this hasn't been initialised - super() hasn't been called");
}
return call && (typeof call === "object" || typeof call === "function") ? call : self;
}
function _inherits(subClass, superClass) {
if (typeof superClass !== "function" && superClass !== null) {
throw new TypeError("Super expression must either be null or a function, not " + typeof superClass);
}
subClass.prototype = Object.create(superClass && superClass.prototype, {
constructor: {
value: subClass,
enumerable: false,
writable: true,
configurable: true
}
});
if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ =
superClass;
} // Encoding documentation
// http://www.gomaro.ch/ftproot/Laetus_PHARMA-CODE.pdf
var pharmacode = function(_Barcode) {
_inherits(pharmacode, _Barcode);
function pharmacode(data, options) {
_classCallCheck(this, pharmacode);
var _this = _possibleConstructorReturn(this, (pharmacode.__proto__ || Object.getPrototypeOf(pharmacode))
.call(this, data, options));
_this.number = parseInt(data, 10);
return _this;
}
_createClass(pharmacode, [{
key: "encode",
value: function encode() {
var z = this.number;
var result = "";
// http://i.imgur.com/RMm4UDJ.png
// (source: http://www.gomaro.ch/ftproot/Laetus_PHARMA-CODE.pdf, page: 34)
while (!isNaN(z) && z != 0) {
if (z % 2 === 0) {
// Even
result = "11100" + result;
z = (z - 2) / 2;
} else {
// Odd
result = "100" + result;
z = (z - 1) / 2;
}
}
// Remove the two last yunzhupaases
result = result.slice(0, -2);
return {
data: result,
text: this.text
};
}
}, {
key: "valid",
value: function valid() {
return this.number >= 3 && this.number <= 131070;
}
}]);
return pharmacode;
}(_Barcode3);
export default pharmacode;

View File

@@ -0,0 +1,203 @@
<template xlang="wxml" minapp="mpvue">
<view class="tki-barcode">
<!-- #ifndef MP-ALIPAY -->
<canvas class="tki-barcode-canvas" :canvas-id="cid"
:style="{width:canvasWidth+'px',height:canvasHeight+'px'}" />
<!-- #endif -->
<!-- #ifdef MP-ALIPAY -->
<canvas :id="cid" :width="canvasWidth" :height="canvasHeight" class="tki-barcode-canvas" />
<!-- #endif -->
<image v-show="show" :src="result" :style="{width:canvasWidth+'px',height:canvasHeight+'px'}" />
</view>
</template>
<script>
// const barcode = require('./barcode.js');
import barCode from "./barcode.js"
const opations = {
// format: "CODE128",//选择要使用的条形码类型 微信支持的条码类型有 code128\code39\ena13\ean8\upc\itf14\
width: 4, //设置条之间的宽度
height: 120, //高度
displayValue: true, //是否在条形码下方显示文字
// text: "1234567890",//覆盖显示的文本
textAlign: "center", //设置文本的水平对齐方式
textPosition: "bottom", //设置文本的垂直位置
textMargin: 0, //设置条形码和文本之间的间距
fontSize: 24, //设置文本的大小
fontColor: "#000000", //设置文本的颜色
lineColor: "#000000", //设置条形码的颜色
background: "#FFFFFF", //设置条形码的背景色
margin: 0, //设置条形码周围的空白边距
marginTop: undefined, //设置条形码周围的上边距
marginBottom: undefined, //设置条形码周围的下边距
marginLeft: undefined, //设置条形码周围的左边距
marginRight: undefined, //设置条形码周围的右边距
}
export default {
name: "tkiBarcode",
props: {
show: {
type: Boolean,
default: true
},
cid: {
type: String,
default: 'tki-barcode-canvas'
},
unit: {
type: String,
default: 'upx'
},
val: {
type: String,
default: ''
},
format: {
type: String,
default: 'CODE128'
},
opations: {
type: Object,
default: function() {
return {}
}
},
onval: {
type: Boolean,
default: false
},
loadMake: {
type: Boolean,
default: true
},
},
data() {
return {
result: '',
canvasWidth: 0,
canvasHeight: 0,
defaultOpations: Object.assign({}, opations)
}
},
onUnload: function() {},
methods: {
_makeCode() {
let that = this
// 合并参数
Object.assign(this.defaultOpations, this.opations)
if (that.unit == "upx") {
if (that.defaultOpations.width) {
that.defaultOpations.width = uni.upx2px(that.defaultOpations.width)
}
if (that.defaultOpations.height) {
that.defaultOpations.height = uni.upx2px(that.defaultOpations.height)
}
if (that.defaultOpations.fontSize) {
that.defaultOpations.fontSize = uni.upx2px(that.defaultOpations.fontSize)
}
}
if (that._empty(that.defaultOpations.text)) {
that.defaultOpations.text = that.val
}
if (that._empty(that.defaultOpations.format)) {
that.defaultOpations.format = that.format
}
new barCode(that, that.cid, that.defaultOpations,
function(res) { // 生成条形码款高回调
that.canvasWidth = res.width
that.canvasHeight = res.height
},
function(res) { // 生成条形码的回调
// 返回值
that._result(res)
// 重置默认参数
that.defaultOpations = opations
},
);
},
_clearCode() {
this._result('')
},
_saveCode() {
let that = this;
if (this.result != "") {
uni.saveImageToPhotosAlbum({
filePath: that.result,
success: function() {
uni.showToast({
title: '条形码保存成功',
icon: 'success',
duration: 2000
});
}
});
}
},
_result(res) {
this.result = res;
this.$emit('result', res)
},
_empty(v) {
let tp = typeof v,
rt = false;
if (tp == "number" && String(v) == "") {
rt = true
} else if (tp == "undefined") {
rt = true
} else if (tp == "object") {
if (JSON.stringify(v) == "{}" || JSON.stringify(v) == "[]" || v == null) rt = true
} else if (tp == "string") {
if (v == "" || v == "undefined" || v == "null" || v == "{}" || v == "[]") rt = true
} else if (tp == "function") {
rt = false
}
return rt
}
},
watch: {
val(n, o) {
if (this.onval) {
if (n != o && !this._empty(n)) {
setTimeout(() => {
this._makeCode()
}, 0);
}
}
},
opations: {
handler(n, o) {
if (this.onval) {
if (!this._empty(n)) {
setTimeout(() => {
this._makeCode()
}, 0);
}
}
},
deep: true
}
},
mounted: function() {
if (this.loadMake) {
if (!this._empty(this.val)) {
setTimeout(() => {
this._makeCode()
}, 0);
}
}
},
}
</script>
<style>
.tki-barcode {
text-align: right;
position: relative;
}
.tki-barcode-canvas {
position: fixed !important;
top: -99999upx;
left: -99999upx;
z-index: -99999;
}
</style>

View File

@@ -0,0 +1,60 @@
<template>
<view :class="'yunzhupaas-button yunzhupaas-button-'+align">
<u-button :custom-style="customStyle" :type="realType" :disabled="disabled"
@click="onClick">{{buttonText}}</u-button>
</view>
</template>
<script>
export default {
name: 'yunzhupaas-button',
props: {
align: {
default: 'left'
},
buttonText: {
default: ''
},
disabled: {
type: Boolean,
default: false
},
type: {
default: ''
}
},
computed: {
realType() {
return !this.type ? 'default' : this.type === 'danger' ? 'error' : this.type
}
},
data() {
return {
customStyle: {
display: 'inline-block'
}
}
},
methods: {
onClick(event) {
this.$emit('click', event)
}
}
}
</script>
<style lang="scss" scoped>
.yunzhupaas-button {
width: 100%;
&.yunzhupaas-button-left {
text-align: left;
}
&.yunzhupaas-button-center {
text-align: center;
}
&.yunzhupaas-button-right {
text-align: right;
}
}
</style>

View File

@@ -0,0 +1,253 @@
<template>
<view class="yunzhupaas-calculation yunzhupaas-calculation-right">
<u-input input-align='right' v-model="innerValue" disabled placeholder='0.00' />
<view class="tips" v-if="isAmountChinese">{{rmbText}}</view>
</view>
</template>
<script>
/**
* 中缀转后缀(逆波兰 Reverse Polish Notation
* @param {Array} exps - 中缀表达式数组
*/
const toRPN = exps => {
const s1 = [] // 符号栈
const s2 = [] // 输出栈
const getTopVal = (stack) => stack.length > 0 ? stack[stack.length - 1] : null
const levelCompare = (c1, c2) => {
const getIndex = c => ['+-', '×÷', '()'].findIndex(t => t.includes(c))
return getIndex(c1) - getIndex(c2)
}
exps.forEach(t => {
if (typeof t === 'string' && Number.isNaN(Number(t))) { // 是符号
if (t === '(') {
s1.push(t)
} else if (t === ')') {
let popVal
do {
popVal = s1.pop()
popVal !== '(' && s2.push(popVal)
} while (s1.length && popVal !== '(')
} else {
let topVal = getTopVal(s1)
if (!topVal) { // s1 为空 直接push
s1.push(t)
} else {
while (topVal && topVal !== '(' && levelCompare(topVal, t) >= 0) { // 优先级 >= t 弹出到s2
s2.push(s1.pop())
topVal = getTopVal(s1)
}
s1.push(t)
}
}
return
}
s2.push(t) // 数字直接入栈
})
while (s1.length) {
s2.push(s1.pop())
}
return s2
}
const calcRPN = rpnExps => {
rpnExps = rpnExps.concat()
const calc = (x, y, type) => {
let a1 = Number(x),
a2 = Number(y)
switch (type) {
case '+':
return a1 + a2;
case '-':
return a1 - a2;
case '×':
return a1 * a2;
case '÷':
return a1 / a2;
}
}
for (let i = 2; i < rpnExps.length; i++) {
if ('+-×÷'.includes(rpnExps[i])) {
let val = calc(rpnExps[i - 2], rpnExps[i - 1], rpnExps[i])
rpnExps.splice(i - 2, 3, val)
i = i - 2
}
}
return rpnExps[0]
}
const mergeNumberOfExps = expressions => {
const res = []
const isNumChar = n => /^[\d|\.]$/.test(n)
for (let i = 0; i < expressions.length; i++) {
if (i > 0 && isNumChar(expressions[i - 1]) && isNumChar(expressions[i])) {
res[res.length - 1] += expressions[i]
continue
}
res.push(expressions[i])
}
return res
}
export default {
name: 'yunzhupaas-calculation',
props: {
modelValue: {
type: [String, Number],
default: ''
},
thousands: {
type: Boolean,
default: false
},
precision: {
default: 0
},
isAmountChinese: {
type: Boolean,
default: false
},
expression: {
type: Array,
default: []
},
config: {
type: Object,
default: {}
},
formData: {
type: Object,
default: {}
},
rowIndex: {
type: [String, Number],
default: ''
},
roundType: {
type: [String, Number],
default: 1
}
},
data() {
return {
innerValue: '',
RPN_EXP: toRPN(mergeNumberOfExps(this.expression)),
rmbText: '',
subValue: 0
}
},
watch: {
formData: {
handler(val, oldVal) {
setTimeout(() => {
this.execRPN()
}, 0)
},
deep: true,
immediate: true
},
modelValue: {
handler(val, oldVal) {
this.innerValue = val
},
deep: true,
immediate: true
},
},
methods: {
getRoundValue(val) {
const precision = this.precision || 0;
let truncatedNumber
if (this.roundType == 2) {
if (precision === 0) Math.trunc(val);
const factor = Math.pow(10, precision);
truncatedNumber = Math.trunc(val * factor) / factor;
return truncatedNumber
}
if (this.roundType == 3) return Math.ceil(val)
if (this.roundType == 4) return Math.floor(val);
return val.toFixed(precision)
},
/**
* 计算表达式
*/
execRPN() {
const temp = this.RPN_EXP.map(t => typeof t === 'object' ? this.getFormVal(t.__vModel__) : t)
this.setValue(temp)
this.subValue = JSON.parse(JSON.stringify(this.innerValue))
if (isNaN(this.innerValue)) this.innerValue = 0
this.rmbText = this.yunzhupaas.getAmountChinese(Number(this.subValue) || 0)
this.$emit('update:modelValue', this.subValue)
if (this.thousands) this.innerValue = this.numFormat(this.innerValue)
},
setValue(temp) {
let result = calcRPN(temp);
if (isNaN(result) || !isFinite(result)) {
this.innerValue = 0;
} else {
let num = Number(result);
if (this.roundType == 2) {
this.innerValue = num;
} else {
this.innerValue = Number(num.toFixed(this.precision ||
0));
}
}
this.innerValue = this.getRoundValue(parseFloat(this.innerValue));
},
/**
* 千分符
*/
numFormat(num) {
num = num.toString().split("."); // 分隔小数点
let arr = num[0].split("").reverse(); // 转换成字符数组并且倒序排列
let res = [];
for (let i = 0, len = arr.length; i < len; i++) {
if (i % 3 === 0 && i !== 0) res.push(","); // 添加分隔符
res.push(arr[i]);
}
res.reverse(); // 再次倒序成为正确的顺序
if (num[1]) { // 如果有小数的话添加小数部分
res = res.join("").concat("." + num[1]);
} else {
res = res.join("");
}
return res
},
/**
* 获取指定组件的值
*/
getFormVal(vModel) {
try {
if (vModel.indexOf('.') > -1) {
let [tableVModel, cmpVModel] = vModel.split('.');
if (typeof this.rowIndex === 'number') {
if (!Array.isArray(this.formData[tableVModel]) || this.formData[tableVModel].length < this
.rowIndex + 1) return 0;
return this.formData[tableVModel][this.rowIndex][cmpVModel] || 0;
} else {
if (!this.formData[tableVModel].length) return 0;
return this.formData[tableVModel].reduce((sum, c) => (c[cmpVModel] ? Number(c[cmpVModel]) :
0) + sum, 0);
}
}
return this.formData[vModel] || 0
} catch (error) {
console.warn('计算公式出错, 可能包含无效的组件值', error)
return 0
}
},
}
}
</script>
<style lang="scss" scoped>
.yunzhupaas-calculation {
width: 100%;
&.yunzhupaas-calculation-right {
text-align: right;
}
.tips {
color: #999999;
line-height: 40rpx;
}
}
</style>

View File

@@ -0,0 +1,277 @@
<template>
<u-popup class="yunzhupaas-tree-select-popup" width="100%" v-model="showPopup" length="auto" mode="right" :popup="false"
:safeAreaInsetBottom="safeAreaInsetBottom" :maskCloseAble="maskCloseAble" :z-index="uZIndex" @close="close">
<view class="yunzhupaas-tree-select-body">
<view class="yunzhupaas-tree-select-title">
<text class="icon-ym icon-ym-report-icon-preview-pagePre backIcon" @tap="close"></text>
<view class="title">级联选择</view>
</view>
<view class="yunzhupaas-tree-select-search" v-if="filterable">
<u-search :placeholder="$t('app.apply.pleaseKeyword')" v-model="filterText" height="72"
:show-action="false" bg-color="#f0f2f6" shape="square">
</u-search>
</view>
<view class="yunzhupaas-tree-selected">
<view class="yunzhupaas-tree-selected-head">
<view>{{$t('component.yunzhupaas.common.selected')}}</view>
<view v-if="multiple" class="clear-btn" @click="setCheckAll">
{{$t('component.yunzhupaas.common.clearAll')}}
</view>
</view>
<view class="yunzhupaas-tree-selected-box">
<scroll-view scroll-y="true" class="select-list">
<u-tag closeable @close="delSelect(index)" v-for="(list,index) in selectListText" :key="index"
:text="list" class="u-selectTag" />
</scroll-view>
</view>
</view>
<view class="yunzhupaas-tree-select-tree">
<scroll-view :scroll-y="true" style="height: 100%">
<ly-tree ref="tree" :tree-data="options" check-on-click-node default-expand-all
:node-key="realProps.value" highlight-current :props="realProps" @node-click="handleNodeClick"
:filter-node-method="filterNode" />
</scroll-view>
</view>
<!-- 底部按钮 -->
<view class="yunzhupaas-tree-select-actions">
<u-button class="buttom-btn" @click="close()">{{$t('common.cancelText')}}</u-button>
<u-button class="buttom-btn" type="primary"
@click.stop="handleConfirm">{{$t('common.okText')}}</u-button>
</view>
</view>
</u-popup>
</template>
<script>
/**
* tree-select 树形选择器
* @property {Boolean} v-model 布尔值变量,用于控制选择器的弹出与收起
* @property {Boolean} safe-area-inset-bottom 是否开启底部安全区适配(默认false)
* @property {String} cancel-color 取消按钮的颜色(默认#606266
* @property {String} confirm-color 确认按钮的颜色(默认#2979ff)
* @property {String} confirm-text 确认按钮的文字
* @property {String} cancel-text 取消按钮的文字
* @property {Boolean} mask-close-able 是否允许通过点击遮罩关闭Picker(默认true)
* @property {String Number} z-index 弹出时的z-index值(默认10075)
* @event {Function} confirm 点击确定按钮,返回当前选择的值
*/
const defaultProps = {
label: 'fullName',
value: 'id',
icon: 'icon',
children: 'children'
}
import {
getProvinceSelector
} from '@/api/common.js'
let _self;
export default {
name: "tree-select",
props: {
selectList: {
type: Array,
default () {
return [];
}
},
selectedId: {
type: Array,
default () {
return [];
}
},
selectData: {
type: Array,
default () {
return [];
}
},
options: {
type: Array,
default: () => []
},
// 是否显示边框
border: {
type: Boolean,
default: true
},
filterable: {
type: Boolean,
default: false
},
showAllLevels: {
type: Boolean,
default: true
},
clearable: {
type: Boolean,
default: false
},
// 通过双向绑定控制组件的弹出与收起
modelValue: {
type: Boolean,
default: false
},
// "取消"按钮的颜色
cancelColor: {
type: String,
default: '#606266'
},
// "确定"按钮的颜色
confirmColor: {
type: String,
default: '#2979ff'
},
// 弹出的z-index值
zIndex: {
type: [String, Number],
default: 0
},
safeAreaInsetBottom: {
type: Boolean,
default: false
},
// 是否允许通过点击遮罩关闭Picker
maskCloseAble: {
type: Boolean,
default: true
},
props: {
type: Object,
default: () => ({
label: 'fullName',
value: 'id',
icon: 'icon',
children: 'children',
isLeaf: 'isLeaf'
})
},
multiple: {
type: Boolean,
default: false
},
// 顶部标题
title: {
type: String,
default: ''
},
// 取消按钮的文字
cancelText: {
type: String,
default: '取消'
},
// 确认按钮的文字
confirmText: {
type: String,
default: '确认'
},
level: {
type: Number,
default: 0
}
},
data() {
return {
moving: false,
selectListText: [],
selectListId: [],
selectListData: [],
newListId: [],
filterText: '',
showPopup: false
};
},
watch: {
// 在select弹起的时候重新初始化所有数据
modelValue: {
immediate: true,
handler(val) {
this.showPopup = val
if (val) setTimeout(() => this.init(), 10);
}
},
filterText(val) {
this.$refs.tree.filter(val);
}
},
created() {
_self = this
this.init()
},
computed: {
uZIndex() {
// 如果用户有传递z-index值优先使用
return this.zIndex ? this.zIndex : this.$u.zIndex.popup;
},
realProps() {
return {
...defaultProps,
...this.props
}
}
},
methods: {
init() {
this.selectListText = this.$u.deepClone(this.selectList)
this.selectListId = this.$u.deepClone(this.selectedId)
this.selectListData = this.$u.deepClone(this.selectData)
},
filterNode(value, options) {
if (!value) return true;
return options[this.props.label].indexOf(value) !== -1;
},
handleNodeClick(obj) {
if (!obj.parentId && !obj.isLeaf) return
let allPath = this.$refs.tree.getNodePath(obj)
let list = []
let listId = []
let currentNode = obj.data
if (!this.multiple) {
this.selectListText = [];
this.selectListId = [];
this.selectListData = [];
}
let txt = ''
let ids = ''
for (let i = 0; i < allPath.length; i++) {
listId.push(allPath[i][this.props.value])
ids += (i ? ',' : '') + allPath[i][this.props.value]
txt += (i ? '/' : '') + allPath[i][this.props.label]
}
if (this.showAllLevels) {
this.selectListText.push(txt)
} else {
this.selectListText.push(currentNode[this.props.label])
}
this.selectListText = [...new Set(this.selectListText)]
var isExist = false;
for (var i = 0; i < this.selectListId.length; i++) {
if (this.selectListId[i].join(',') === ids) {
isExist = true;
break;
}
};
!isExist && this.selectListId.push(listId);
this.selectListData = allPath
},
delSelect(index) {
this.selectListText.splice(index, 1);
this.selectListId.splice(index, 1);
this.selectListData.splice(index, 1);
},
setCheckAll() {
this.selectListText = [];
this.selectListId = [];
this.selectListData = [];
this.$refs.tree.setCheckAll(false);
},
handleConfirm() {
this.$emit('confirm', this.selectListText, this.selectListId, this.selectListData);
this.close();
},
close() {
this.$emit('close', false);
}
}
};
</script>

View File

@@ -0,0 +1,150 @@
<template>
<view class="yunzhupaas-cascader">
<selectBox v-model="innerValue" :placeholder="placeholder" @openSelect="openSelect" :select-open="selectShow">
</selectBox>
<Tree v-if="selectShow" v-model="selectShow" :multiple="multiple" :props="props" :selectList="selectList"
:options="options" :selectedId="!multiple ? [modelValue] : modelValue" :filterable='filterable'
:selectData="selectData" :clearable="clearable" :showAllLevels="showAllLevels" @close="handleClose"
@confirm="handleConfirm" />
</view>
</template>
<script>
import selectBox from '@/components/selectBox'
import Tree from './Tree';
export default {
name: 'yunzhupaas-cascader',
components: {
Tree,
selectBox
},
props: {
modelValue: {
default: ''
},
placeholder: {
type: String,
default: '请选择'
},
options: {
type: Array,
default: () => []
},
props: {
type: Object,
default: () => ({
label: 'fullName',
value: 'id',
children: 'children'
})
},
disabled: {
type: Boolean,
default: false
},
multiple: {
type: Boolean,
default: false
},
showAllLevels: {
type: Boolean,
default: true
},
filterable: {
type: Boolean,
default: false
},
clearable: {
type: Boolean,
default: false
},
},
watch: {
modelValue: {
handler(val) {
this.setDefault(this.modelValue)
},
immediate: true
},
options: {
handler(val) {
this.setDefault(this.modelValue)
},
deep: true
}
},
data() {
return {
selectShow: false,
innerValue: '',
selectList: [],
selectData: [],
allList: []
}
},
methods: {
async setDefault(value) {
this.innerValue = ''
this.selectData = []
this.selectList = []
if (!value || !value?.length) return
this.allList = await this.treeToArray(value)
if (!this.multiple) value = [value]
let txt = []
for (let i = 0; i < value.length; i++) {
let val = uni.$u.deepClone(value[i])
for (let j = 0; j < val.length; j++) {
inner: for (let k = 0; k < this.allList.length; k++) {
if (val[j] === this.allList[k][this.props.value]) {
val[j] = this.allList[k][this.props.label];
this.selectData.push(this.allList[k])
break;
}
}
}
txt.push(val)
}
this.selectList = txt.map(o => this.showAllLevels ? o.join('/') : o[o.length - 1])
this.innerValue = this.selectList.join()
},
async treeToArray() {
let options = uni.$u.deepClone(this.options)
let list = []
const loop = (options) => {
for (let i = 0; i < options.length; i++) {
const item = options[i]
list.push(item)
if (item[this.props.children] && Array.isArray(item[this.props.children])) {
loop(item[this.props.children])
}
}
}
loop(options)
return list
},
openSelect() {
if (this.disabled) return
this.selectShow = true
},
handleConfirm(e, selectId, selectData) {
this.selectList = e;
this.innerValue = e.join()
if (!this.multiple) {
this.$emit('update:modelValue', selectId[0])
this.$emit('change', selectId[0], selectData[0])
} else {
this.$emit('update:modelValue', selectId)
this.$emit('change', selectId, selectData)
}
},
handleClose() {
this.selectShow = false
}
}
}
</script>
<style lang="scss" scoped>
.yunzhupaas-cascader {
width: 100%;
}
</style>

View File

@@ -0,0 +1,84 @@
<template>
<u-checkbox-group class="yunzhupaas-checkbox" :disabled="disabled" :wrap="direction == 'horizontal' ? false : true"
@change="onChange">
<u-checkbox v-model="item.checked" v-for="(item, index) in optionList" :key="index" :name="item[props.value]">
{{item[props.label]}}
</u-checkbox>
</u-checkbox-group>
</template>
<script>
export default {
name: 'yunzhupaas-checkbox',
inheritAttrs: false,
props: {
modelValue: {
type: Array,
default: () => []
},
direction: {
type: String,
default: "horizontal"
},
options: {
type: Array,
default: () => []
},
props: {
type: Object,
default: () => ({
label: 'fullName',
value: 'id'
})
},
disabled: {
type: Boolean,
default: false
}
},
data() {
return {
optionList: []
}
},
watch: {
modelValue: {
handler(val) {
if (!val || !val?.length) return this.setColumnData()
this.setDefault()
},
immediate: true,
},
options: {
handler(val) {
this.setColumnData()
},
immediate: true,
}
},
methods: {
setDefault() {
if (!this.modelValue || !this.modelValue?.length) return
outer: for (let i = 0; i < this.modelValue.length; i++) {
inner: for (let j = 0; j < this.optionList.length; j++) {
if (this.modelValue[i] === this.optionList[j][this.props.value]) {
this.optionList[j].checked = true
break inner
}
}
}
},
setColumnData() {
this.optionList = this.options.map(o => ({
...o,
checked: false
}))
this.setDefault()
},
onChange(value) {
const selectData = this.optionList.filter(o => o.checked) || []
this.$emit('update:modelValue', value)
this.$emit('change', value, selectData)
},
}
}
</script>

View File

@@ -0,0 +1,124 @@
<template>
<view class="yunzhupaas-color-picker">
<view class="color-box" @click="open">
<view class="colorVal" :style="{backgroundColor:bgColor}">
<uni-icons type="bottom" size="10" color='#c7c7c7'></uni-icons>
</view>
</view>
<t-color-picker ref="colorPicker" :color="innerValue" @confirm="confirm" :colorFormat='colorFormat' />
</view>
</template>
<script>
import tColorPicker from './t-color-picker.vue'
import conversion from '@/libs/color-typeConversion.js'
export default {
name: 'yunzhupaas-color-picker',
components: {
tColorPicker
},
props: {
modelValue: {
default: ''
},
colorFormat: {
type: String,
default: 'hex'
},
disabled: {
type: Boolean,
default: false
},
},
data() {
return {
bgColor: "#fff",
hsvObj: {},
hsvList: ['h', 's', 'v'],
innerValue: ''
};
},
watch: {
modelValue: {
handler(val) {
this.innerValue = val
this.setDafault()
},
immediate: true
}
},
methods: {
open(item) {
if (this.disabled) return
this.$refs.colorPicker.open();
},
confirm(e) {
this.bgColor = e.colorVal
this.$emit('update:modelValue', this.bgColor)
this.$emit('change', this.bgColor)
},
setDafault() {
if (!this.innerValue) return this.bgColor = '#fff'
this.$nextTick(() => {
if (this.colorFormat === 'hsv') {
let color = ""
var result = this.innerValue.match(/\(([^)]*)\)/)
result[1].split(',').forEach((o, i) => {
this.$set(this[this.colorFormat + 'Obj'], this[this.colorFormat + 'List'][i],
o)
})
color = conversion.hsv2rgb(this[this.colorFormat + 'Obj'].h, this[this.colorFormat + 'Obj']
.s,
this[this.colorFormat + 'Obj'].v)
this.bgColor = `rgb(${color.r},${color.g},${color.b})`
} else {
this.bgColor = this.innerValue
}
})
}
}
};
</script>
<style lang="scss">
.yunzhupaas-color-picker {
flex: 1;
display: flex;
flex-direction: row;
align-items: center;
justify-content: flex-end;
.color-box {
width: 70rpx;
height: 70rpx;
border: 1px solid #e6e6e6;
background-color: #fff;
border-radius: 10rpx;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
.colorVal {
width: 48rpx;
height: 48rpx;
border: 1px solid #999;
border-radius: 6rpx;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
background-color: #fff;
.colorVal-inner {
width: 100%;
height: 100%;
color: #c7c7c7;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
text-align: center;
}
}
}
}
</style>

View File

@@ -0,0 +1,633 @@
<template>
<view v-show="show" class="t-wrapper" @touchmove.stop.prevent="moveHandle">
<view class="t-mask" :class="{active:active}" @click.stop="close"></view>
<view class="t-box" :class="{active:active}">
<view class="t-header">
<view class="t-header-button" @click="close">取消</view>
<view class="t-header-button" @click="confirm">确认</view>
</view>
<view class="t-color__box"
:style="{ background: 'rgb(' + bgcolor.r + ',' + bgcolor.g + ',' + bgcolor.b + ')'}">
<view class="t-background boxs" @touchstart="touchstart($event, 0)" @touchmove="touchmove($event, 0)"
@touchend="touchend($event, 0)">
<view class="t-color-mask"></view>
<view class="t-pointer" :style="{ top: site[0].top - 8 + 'px', left: site[0].left - 8 + 'px' }">
</view>
</view>
</view>
<view class="t-control__box">
<view class="t-control__color" v-if="colorFormat == 'rgba'">
<view class="t-control__color-content"
:style="{ background: 'rgba(' + rgba.r + ',' + rgba.g + ',' + rgba.b + ',' + rgba.a + ')' }">
</view>
</view>
<view class="t-control-box__item">
<view class="t-controller boxs" @touchstart="touchstart($event, 1)"
@touchmove="touchmove($event, 1)" @touchend="touchend($event, 1)">
<view class="t-hue">
<view class="t-circle" :style="{ left: site[1].left - 12 + 'px' }"></view>
</view>
</view>
<view class="t-controller boxs" @touchstart="touchstart($event, 2)"
@touchmove="touchmove($event, 2)" @touchend="touchend($event, 2)" v-if="colorFormat == 'rgba'">
<view class="t-transparency">
<view class="t-circle" :style="{ left: site[2].left - 12 + 'px' }"></view>
</view>
</view>
</view>
</view>
<view class="t-result__box">
<view class="t-result__item">
<view class="t-result__box-input">{{colorVal}}</view>
</view>
<!-- <template v-else>
<view class="t-result__item">
<view class="t-result__box-input">{{rgba.r}}</view>
<view class="t-result__box-text">R</view>
</view>
<view class="t-result__item">
<view class="t-result__box-input">{{rgba.g}}</view>
<view class="t-result__box-text">G</view>
</view>
<view class="t-result__item">
<view class="t-result__box-input">{{rgba.b}}</view>
<view class="t-result__box-text">B</view>
</view>
<view class="t-result__item" v-if="colorFormat === 'rgba'">
<view class="t-result__box-input">{{rgba.a}}</view>
<view class="t-result__box-text">A</view>
</view>
</template> -->
</view>
<view class="t-alternative" v-if="isCommonColor">
<view class="t-alternative__item" v-for="(item,index) in conversion.colorList" :key="index">
<view class="t-alternative__item-content"
:style="{ background: 'rgba(' + item.r + ',' + item.g + ',' + item.b + ',' + item.a + ')' }"
@click="selectColor(item)">
</view>
</view>
</view>
</view>
</view>
</template>
<script>
import conversion from '@/libs/color-typeConversion.js'
export default {
props: {
color: {
default: ''
},
colorFormat: {
default: 'hex'
},
isCommonColor: {
type: Boolean,
default: false
}
},
data() {
return {
show: false,
active: false,
// rgba 颜色
rgba: {
r: 0,
g: 0,
b: 0,
a: 1
},
// hsb 颜色
hsb: {
h: 0,
s: 0,
b: 0
},
site: [{
top: 0,
left: 0
}, {
left: 0
}, {
left: 0
}],
index: 0,
bgcolor: {
r: 255,
g: 0,
b: 0,
a: 1
},
hex: '#000000',
hsvList: ['h', 's', 'v'],
hsvObj: {},
hslList: ['h', 's', 'l'],
hslObj: {},
colorVal: '#000000',
hsv: '',
rgbObj: {},
rgbList: ['r', 'g', 'b'],
rgbaList: ['r', 'g', 'b', 'a'],
rgbaObj: {},
hsl: '',
conversion: conversion
};
},
created() {
},
methods: {
open() {
this.show = true;
this.$nextTick(() => {
this.init();
setTimeout(() => {
this.active = true;
setTimeout(() => {
this.getSelectorQuery();
}, 350)
}, 50)
})
},
init() {
if (!this.color) return
if (this.colorFormat == 'rgb' || this.colorFormat == 'rgba' || this.colorFormat == 'hsv' || this
.colorFormat == 'hsl') {
//将字符串括号中的值取出
var result = this.color.match(/\(([^)]*)\)/)
result[1].split(',').forEach((o, i) => {
this.$set(this[this.colorFormat + 'Obj'], this[this.colorFormat + 'List'][i], o)
})
if (this.colorFormat == 'rgb' || this.colorFormat == 'rgba') {
this.rgba = this[this.colorFormat + 'Obj']
this.hsb = conversion.rgbToHex(this.rgba);
this.setValue(this.rgba)
}
if (this.colorFormat == 'hsv') {
this.rgba = conversion.hsv2rgb(this[this.colorFormat + 'Obj'].h, this[this.colorFormat + 'Obj'].s,
this[
this.colorFormat + 'Obj'].v)
this.hsb = conversion.rgbToHex(this.rgba);
this.setValue(this.rgba)
}
if (this.colorFormat == 'hsl') {
this.rgba = conversion.hsl2rgb(parseInt(this.hslObj.h), parseInt(this.hslObj.s), parseInt(this
.hslObj
.l))
this.hsb = conversion.rgbToHex(this.rgba);
this.setValue(this.rgba)
}
} else {
this.rgba = conversion.hex2rgba(this.color)
this.hsb = conversion.rgbToHex(this.rgba);
this.setValue(this.rgba)
}
},
moveHandle() {},
close() {
this.active = false;
this.$nextTick(() => {
setTimeout(() => {
this.show = false;
}, 500)
})
},
confirm() {
this.$emit('confirm', {
rgba: this.rgba,
hex: this.hex,
colorVal: this.colorVal,
hsv: this.hsv,
hsl: this.hsl
})
this.close();
},
// 常用颜色选择
selectColor(item) {
this.setColorBySelect(item)
},
touchstart(e, index) {
const {
clientX,
clientY
} = e.touches[0];
this.pageX = clientX;
this.pageY = clientY;
this.setPosition(clientX, clientY, index);
},
touchmove(e, index) {
const {
clientX,
clientY
} = e.touches[0];
this.moveX = clientX;
this.moveY = clientY;
this.setPosition(clientX, clientY, index);
},
touchend(e, index) {},
/**
* 设置位置
*/
setPosition(x, y, index) {
this.index = index;
const {
top,
left,
width,
height
} = this.position[index];
// 设置最大最小值
this.site[index].left = Math.max(0, Math.min(parseInt(x - left), width));
if (index === 0) {
this.site[index].top = Math.max(0, Math.min(parseInt(y - top), height));
// 设置颜色
this.hsb.s = parseInt((100 * this.site[index].left) / width);
this.hsb.b = parseInt(100 - (100 * this.site[index].top) / height);
this.setColor();
this.setValue(this.rgba);
} else {
this.setControl(index, this.site[index].left);
}
},
/**
* 设置 rgb 颜色
*/
setColor() {
const rgb = conversion.HSBToRGB(this.hsb);
this.rgba.r = rgb.r;
this.rgba.g = rgb.g;
this.rgba.b = rgb.b;
},
/**
* 设置二进制颜色
* @param {Object} rgb
*/
setValue(rgb) {
let hsv = conversion.rgb2hsv(rgb.r, rgb.g, rgb.b)
let hsl = conversion.rgb2hsl(rgb.r, rgb.g, rgb.b)
this.hsv = 'hsv(' + hsv.h + ',' + hsv.s + ',' + hsv.v + ')'
this.hex = '#' + conversion.rgbToHex(rgb);
this.hsl = 'hsl(' + hsl.h + ',' + hsl.s + ',' + hsl.l + ')'
if (this.colorFormat == 'hsv') {
for (let key in hsv) {
if (key != 'h') {
hsv[key] += '%'
}
}
this.colorVal = 'hsv(' + hsv.h + ',' + hsv.s + ',' + hsv.v + ')'
} else if (this.colorFormat == 'hsl') {
this.colorVal = 'hsl(' + hsl.h + ',' + hsl.s + ',' + hsl.l + ')'
} else if (this.colorFormat == 'rgba') {
this.colorVal = this.colorFormat + '(' + rgb.r + ',' + rgb.g + ',' + rgb.b + ',' + rgb.a + ')'
} else if (this.colorFormat == 'rgb') {
this.colorVal = this.colorFormat + '(' + rgb.r + ',' + rgb.g + ',' + rgb.b + ')'
} else {
this.colorVal = '#' + conversion.rgbToHex(rgb);
}
},
setControl(index, x) {
const {
top,
left,
width,
height
} = this.position[index];
if (index === 1) {
this.hsb.h = parseInt((360 * x) / width);
this.bgcolor = conversion.HSBToRGB({
h: this.hsb.h,
s: 100,
b: 100
});
this.setColor()
} else {
this.rgba.a = (x / width).toFixed(1);
}
this.setValue(this.rgba);
},
setColorBySelect(getrgb) {
const {
r,
g,
b,
a
} = getrgb;
let rgb = {}
rgb = {
r: r ? parseInt(r) : 0,
g: g ? parseInt(g) : 0,
b: b ? parseInt(b) : 0,
a: a ? a : 0,
};
this.rgba = rgb;
this.hsb = conversion.rgbToHsb(rgb);
this.changeViewByHsb();
},
changeViewByHsb() {
const [a, b, c] = this.position;
this.site[0].left = parseInt(this.hsb.s * a.width / 100);
this.site[0].top = parseInt((100 - this.hsb.b) * a.height / 100);
this.setColor(this.hsb.h);
this.setValue(this.rgba);
this.bgcolor = conversion.HSBToRGB({
h: this.hsb.h,
s: 100,
b: 100
});
this.site[1].left = this.hsb.h / 360 * b.width;
if (this.colorFormat == 'rgba') {
this.site[2].left = this.rgba.a * c.width;
}
},
getSelectorQuery() {
const views = uni.createSelectorQuery().in(this);
views.selectAll('.boxs').boundingClientRect(data => {
if (!data || data.length === 0) {
this.getSelectorQuery()
return
}
this.position = data;
// this.site[0].top = data[0].height;
// this.site[0].left = 0;
// this.site[1].left = data[1].width;
// this.site[2].left = data[2].width;
this.setColorBySelect(this.rgba);
})
.exec();
}
}
};
</script>
<style>
.t-wrapper {
position: fixed;
top: 0;
bottom: 0;
left: 0;
width: 100%;
box-sizing: border-box;
z-index: 9999;
}
.t-box {
width: 100%;
position: absolute;
bottom: 0;
padding: 30rpx 0;
padding-top: 0;
background: #fff;
transition: all 0.3s;
transform: translateY(100%);
}
.t-box.active {
transform: translateY(0%);
}
.t-header {
display: flex;
justify-content: space-between;
width: 100%;
height: 100rpx;
border-bottom: 1px #eee solid;
box-shadow: 1px 0 2px rgba(0, 0, 0, 0.1);
background: #fff;
}
.t-header-button {
display: flex;
align-items: center;
width: 150rpx;
height: 100rpx;
font-size: 30rpx;
color: #666;
padding-left: 20rpx;
}
.t-header-button:last-child {
justify-content: flex-end;
padding-right: 20rpx;
}
.t-mask {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: rgba(0, 0, 0, 0.6);
z-index: -1;
transition: all 0.3s;
opacity: 0;
}
.t-mask.active {
opacity: 1;
}
.t-color__box {
position: relative;
height: 400rpx;
background: rgb(255, 0, 0);
overflow: hidden;
box-sizing: border-box;
margin: 0 20rpx;
margin-top: 20rpx;
box-sizing: border-box;
}
.t-background {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: linear-gradient(to right, #fff, rgba(255, 255, 255, 0));
}
.t-color-mask {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
width: 100%;
height: 400rpx;
background: linear-gradient(to top, #000, rgba(0, 0, 0, 0));
}
.t-pointer {
position: absolute;
bottom: -8px;
left: -8px;
z-index: 2;
width: 15px;
height: 15px;
border: 1px #fff solid;
border-radius: 50%;
}
.t-show-color {
width: 100rpx;
height: 50rpx;
}
.t-control__box {
margin-top: 50rpx;
width: 100%;
display: flex;
padding-left: 20rpx;
box-sizing: border-box;
}
.t-control__color {
flex-shrink: 0;
width: 100rpx;
height: 100rpx;
border-radius: 50%;
background-color: #fff;
background-image: linear-gradient(45deg, #eee 25%, transparent 25%, transparent 75%, #eee 75%, #eee),
linear-gradient(45deg, #eee 25%, transparent 25%, transparent 75%, #eee 75%, #eee);
background-size: 36rpx 36rpx;
background-position: 0 0, 18rpx 18rpx;
border: 1px #eee solid;
overflow: hidden;
}
.t-control__color-content {
width: 100%;
height: 100%;
}
.t-control-box__item {
display: flex;
flex-direction: column;
justify-content: space-between;
width: 100%;
padding: 0 30rpx;
}
.t-controller {
position: relative;
width: 100%;
height: 16px;
background-color: #fff;
background-image: linear-gradient(45deg, #eee 25%, transparent 25%, transparent 75%, #eee 75%, #eee),
linear-gradient(45deg, #eee 25%, transparent 25%, transparent 75%, #eee 75%, #eee);
background-size: 32rpx 32rpx;
background-position: 0 0, 16rpx 16rpx;
}
.t-hue {
width: 100%;
height: 100%;
background: linear-gradient(to right, #f00 0%, #ff0 17%, #0f0 33%, #0ff 50%, #00f 67%, #f0f 83%, #f00 100%);
}
.t-transparency {
width: 100%;
height: 100%;
background: linear-gradient(to right, rgba(0, 0, 0, 0) 0%, rgb(0, 0, 0));
}
.t-circle {
position: absolute;
/* right: -10px; */
top: -2px;
width: 20px;
height: 20px;
box-sizing: border-box;
border-radius: 50%;
background: #fff;
box-shadow: 0 0 2px 1px rgba(0, 0, 0, 0.1);
}
.t-result__box {
margin-top: 20rpx;
padding: 10rpx;
width: 100%;
display: flex;
box-sizing: border-box;
}
.t-result__item {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
padding: 10rpx;
width: 100%;
box-sizing: border-box;
}
.t-result__box-input {
padding: 10rpx 0;
width: 100%;
font-size: 28rpx;
box-shadow: 0 0 1px 1px rgba(0, 0, 0, 0.1);
color: #999;
text-align: center;
background: #fff;
}
.t-result__box-text {
margin-top: 10rpx;
font-size: 28rpx;
line-height: 2;
}
.t-select {
flex-shrink: 0;
width: 150rpx;
padding: 0 30rpx;
}
.t-select .t-result__box-input {
border-radius: 10rpx;
border: none;
color: #999;
box-shadow: 1px 1px 2px 1px rgba(0, 0, 0, 0.1);
background: #fff;
}
.t-select .t-result__box-input:active {
box-shadow: 0px 0px 1px 0px rgba(0, 0, 0, 0.1);
}
.t-alternative {
display: flex;
flex-wrap: wrap;
/* justify-content: space-between; */
width: 100%;
padding-right: 10rpx;
box-sizing: border-box;
}
.t-alternative__item {
margin-left: 12rpx;
margin-top: 10rpx;
width: 50rpx;
height: 50rpx;
border-radius: 10rpx;
background-color: #fff;
background-image: linear-gradient(45deg, #eee 25%, transparent 25%, transparent 75%, #eee 75%, #eee),
linear-gradient(45deg, #eee 25%, transparent 25%, transparent 75%, #eee 75%, #eee);
background-size: 36rpx 36rpx;
background-position: 0 0, 18rpx 18rpx;
border: 1px #eee solid;
overflow: hidden;
}
.t-alternative__item-content {
width: 50rpx;
height: 50rpx;
background: rgba(255, 0, 0, 0.5);
}
.t-alternative__item:active {
transition: all 0.3s;
transform: scale(1.1);
}
</style>

View File

@@ -0,0 +1,633 @@
<template>
<view>
<u-popup :maskCloseAble="maskCloseAble" mode="bottom" :popup="false" v-model="showPopup" length="auto"
:safeAreaInsetBottom="safeAreaInsetBottom" @close="close" :z-index="uZIndex">
<view class="u-datetime-picker">
<view class="u-picker-header">
<view class="u-btn-picker u-btn-picker--tips" :style="{ color: cancelColor }"
hover-class="u-opacity" :hover-stay-time="150" @tap="close()">{{cancelText}}</view>
<view class="u-picker__title">{{ title }}</view>
<view class="u-btn-picker u-btn-picker--primary"
:style="{ color: moving ? cancelColor : confirmColor }" hover-class="u-opacity"
:hover-stay-time="150" @tap.stop="getResult('confirm')">
{{confirmText}}
</view>
</view>
<view class="u-picker-body">
<picker-view :value="valueArr" @change="change" class="u-picker-view" @pickstart="pickstart"
@pickend="pickend" v-if="valueArr.length">
<picker-view-column v-if="!reset && params.year">
<view class="u-column-item" v-for="(item, index) in years" :key="index">
{{ item }}
<text class="u-text" v-if="showTimeTag"></text>
</view>
</picker-view-column>
<picker-view-column v-if="!reset && params.month">
<view class="u-column-item" v-for="(item, index) in months" :key="index">
{{ formatNumber(item) }}
<text class="u-text" v-if="showTimeTag"></text>
</view>
</picker-view-column>
<picker-view-column v-if="!reset && params.day">
<view class="u-column-item" v-for="(item, index) in days" :key="index">
{{ formatNumber(item) }}
<text class="u-text" v-if="showTimeTag"></text>
</view>
</picker-view-column>
<picker-view-column v-if="!reset && params.hour">
<view class="u-column-item" v-for="(item, index) in hours" :key="index">
{{ formatNumber(item) }}
<text class="u-text" v-if="showTimeTag"></text>
</view>
</picker-view-column>
<picker-view-column v-if="!reset && params.minute">
<view class="u-column-item" v-for="(item, index) in minutes" :key="index">
{{ formatNumber(item) }}
<text class="u-text" v-if="showTimeTag"></text>
</view>
</picker-view-column>
<picker-view-column v-if="!reset && params.second">
<view class="u-column-item" v-for="(item, index) in seconds" :key="index">
{{ formatNumber(item) }}
<text class="u-text" v-if="showTimeTag"></text>
</view>
</picker-view-column>
</picker-view>
</view>
</view>
</u-popup>
</view>
</template>
<script>
export default {
name: 'u-picker',
props: {
params: {
type: Object,
default () {
return {
year: true,
month: true,
day: true,
hour: false,
minute: false,
second: false,
timestamp: true,
};
}
},
// 当mode=selector或者mode=multiSelector时提供的数组
range: {
type: Array,
default () {
return [];
}
},
// 当mode=selector或者mode=multiSelector时提供的默认选中的下标
defaultSelector: {
type: Array,
default () {
return [0];
}
},
// 当 range 是一个 ArrayObject 时,通过 range-key 来指定 Object 中 key 的值作为选择器显示内容
rangeKey: {
type: String,
default: ''
},
// 模式选择region-地区类型time-时间类型selector-单列模式multiSelector-多列模式
mode: {
type: String,
default: 'time'
},
// 年份开始时间
startDate: {
type: String,
default: '1899-01-01 00:00:00'
},
// 年份结束时间
endDate: {
type: String,
default: '2250-12-31 23:59:59'
},
// "取消"按钮的颜色
cancelColor: {
type: String,
default: '#606266'
},
// "确定"按钮的颜色
confirmColor: {
type: String,
default: '#2979ff'
},
// 默认显示的时间
defaultTime: {
type: String,
default: ''
},
// 时间模式时,是否显示后面的年月日中文提示
showTimeTag: {
type: Boolean,
default: true
},
safeAreaInsetBottom: {
type: Boolean,
default: false
},
// 是否允许通过点击遮罩关闭Picker
maskCloseAble: {
type: Boolean,
default: false
},
// 通过双向绑定控制组件的弹出与收起
modelValue: {
type: Boolean,
default: false
},
// 弹出的z-index值
zIndex: {
type: [String, Number],
default: 0
},
// 顶部标题
title: {
type: String,
default: ''
},
// 取消按钮的文字
cancelText: {
type: String,
default: '取消'
},
// 确认按钮的文字
confirmText: {
type: String,
default: '确认'
},
format: {
type: String,
default: 'yyyy-MM-dd HH:mm:ss'
}
},
data() {
return {
years: [],
months: [],
days: [],
hours: [],
minutes: [],
seconds: [],
year: 0,
month: 0,
day: 0,
hour: 0,
minute: 0,
second: 0,
reset: false,
valueArr: [],
moving: false, // 列是否还在滑动中,微信小程序如果在滑动中就点确定,结果可能不准确
showPopup: false
};
},
mounted() {
this.init();
},
computed: {
propsChange() {
// 引用这几个变量,是为了监听其变化
return `${this.mode}-${this.defaultTime}-${this.startYear}-${this.endYear}-${this.defaultRegion}-${this.areaCode}`;
},
yearAndMonth() {
return `${this.year}-${this.month}`;
},
uZIndex() {
// 如果用户有传递z-index值优先使用
return this.zIndex ? this.zIndex : this.$u.zIndex.popup;
}
},
watch: {
propsChange() {
this.reset = true;
setTimeout(() => this.init(), 10);
},
// watch监听月份的变化实时变更日的天数因为不同月份天数不一样
// 一个月可能有3031天甚至闰年2月的29天平年2月28天
yearAndMonth(val) {
if (this.params.year) this.setDays();
},
// 微信和QQ小程序由于一些奇怪的原因(故同时对所有平台均初始化一遍),需要重新初始化才能显示正确的值
modelValue: {
handler(val) {
if (val) {
this.showPopup = val
this.reset = true;
setTimeout(() => this.init(), 10);
}
},
immediate: true
}
},
methods: {
// 标识滑动开始,只有微信小程序才有这样的事件
pickstart() {
// #ifdef MP-WEIXIN
this.moving = true;
// #endif
},
// 标识滑动结束
pickend() {
// #ifdef MP-WEIXIN
this.moving = false;
// #endif
},
getIndex: function(arr, val) {
let index = arr.indexOf(val);
// 如果index为-1(即找不到index值)~(-1)=-(-1)-1=0导致条件不成立
return ~index ? index : 0;
},
//日期时间处理
initTimeValue() {
// 格式化时间在IE浏览器(uni不存在此情况),无法识别日期间的"-"间隔符号
let fdate = this.defaultTime.replace(/\-/g, '/');
fdate = fdate && fdate.indexOf('/') == -1 ? `1899/01/01 ${fdate}` : fdate;
let time = null;
if (fdate) time = new Date(fdate);
else time = new Date();
// 获取年日月时分秒
this.year = time.getFullYear();
this.month = Number(time.getMonth()) + 1;
this.day = time.getDate();
this.hour = time.getHours();
this.minute = time.getMinutes();
this.second = time.getSeconds();
},
init() {
this.valueArr = [];
this.reset = false;
this.initTimeValue();
if (this.params.year) {
this.valueArr.push(0);
this.setYears();
}
if (this.params.month) {
this.valueArr.push(0);
this.setMonths();
}
if (this.params.day) {
this.valueArr.push(0);
this.setDays();
}
if (this.params.hour) {
this.valueArr.push(0);
this.setHours();
}
if (this.params.minute) {
this.valueArr.push(0);
this.setMinutes();
}
if (this.params.second) {
this.valueArr.push(0);
this.setSeconds();
}
},
// 设置picker的某一列值
setYears() {
// 获取年份集合
this.generateArray('year');
if (this.years[0] > this.year) this.year = this.years[0]
if (this.years[this.years.length - 1] < this.year) this.year = this.years[this.years.length - 1]
// 设置this.valueArr某一项的值是为了让picker预选中某一个值
this.valueArr.splice(this.valueArr.length - 1, 1, this.getIndex(this.years, this.year));
},
setMonths() {
this.generateArray('month');
if (this.months[0] > this.month) this.month = this.months[0]
if (this.months[this.months.length - 1] < this.month) this.month = this.months[this.months.length - 1]
this.valueArr.splice(this.valueArr.length - 1, 1, this.getIndex(this.months, this.month));
},
setDays() {
let totalDays = new Date(this.year, this.month, 0).getDate();
this.generateArray('day');
let index = 0;
// 这里不能使用类似setMonths()中的this.valueArr.splice(this.valueArr.length - 1, xxx)做法
// 因为this.month和this.year变化时会触发watch中的this.setDays()导致this.valueArr.length计算有误
if (this.params.year && this.params.month) index = 2;
else if (this.params.month) index = 1;
else if (this.params.year) index = 1;
else index = 0;
// 当月份变化时,会导致日期的天数也会变化,如果原来选的天数大于变化后的天数,则重置为变化后的最大值
// 比如原来选中3月31日调整为2月后日期变为最大29这时如果day值继续为31显然不合理于是将其置为29(picker-column从1开始)
// if (this.day > this.days.length) this.day = this.days.length;
if (this.days[0] > this.day) this.day = this.days[0]
if (this.days[this.days.length - 1] < this.day) this.day = this.days[this.days.length - 1]
this.valueArr.splice(index, 1, this.getIndex(this.days, this.day));
},
setHours() {
this.generateArray('hour');
if (this.hours[0] > this.hour) this.hour = this.hours[0]
if (this.hours[this.hours.length - 1] < this.hour) this.hour = this.hours[this.hours.length - 1]
this.valueArr.splice(this.valueArr.length - 1, 1, this.getIndex(this.hours, this.hour));
},
setMinutes() {
this.generateArray('minute');
if (this.minutes[0] > this.minute) this.minute = this.minutes[0]
if (this.minutes[this.minutes.length - 1] < this.minute) this.minute = this.minutes[this.minutes.length -
1]
this.valueArr.splice(this.valueArr.length - 1, 1, this.getIndex(this.minutes, this.minute));
},
setSeconds() {
this.generateArray('second');
if (this.seconds[0] > this.second) this.second = this.seconds[0]
if (this.seconds[this.seconds.length - 1] < this.second) this.second = this.seconds[this.seconds.length -
1]
this.valueArr.splice(this.valueArr.length - 1, 1, this.getIndex(this.seconds, this.second));
},
generateArray(type) {
let startArr = this.startDate.split(" "); //开始日期时间
let endArr = this.endDate.split(" "); //结束日期时间
if (!this.month) this.month = this.months[this.months.length - 1]
let totalDays = new Date(this.year, this.month, 0).getDate(); //当月天数
//开始年月日时分秒
let startDateArr = startArr[0] ? startArr[0].split("-") : []; //开始日期
let startTimeArr = startArr[1] ? startArr[1].split(":") : []; //开始时间
let startYear = Number(startDateArr[0]) || 1; //开始年
let startMonth = Number(startDateArr[1]) || 1; //开始月
let startDay = Number(startDateArr[2]) || 1; //开始天数
let startHour = Number(startTimeArr[0]) || 0 //开始小时
let startMinute = Number(startTimeArr[1]) || 0 //开始分钟
let startSecond = Number(startTimeArr[2]) || 0 //开始秒
//结束年月日时分秒
let endDateArr = endArr[0] ? endArr[0].split("-") : [] //结束日期
let endTimeArr = endArr[1] ? endArr[1].split(":") : []; //结束时间
let endYear = Number(endDateArr[0]) || 12; //结束年
let endMonth = Number(endDateArr[1]) || 12; //结束月
let endDay = Number(endDateArr[2]) || totalDays; //结束天数
let endHour = Number(endTimeArr[0]) || 0 //结束小时
let endMinute = Number(endTimeArr[1]) || 0 //结束分钟
let endSecond = Number(endTimeArr[2]) || 0 //结束秒
// 转为数值格式否则用户给end-year等传递字符串值时下面的end+1会导致字符串拼接而不是相加
if (type == 'year') {
startYear = Number(startYear);
endYear = Number(endYear);
endYear = endYear > startYear ? endYear : startYear;
// 生成数组,获取其中的索引,并剪出来
this.years = [...Array(endYear + 1).keys()].slice(startYear);
this.generateArray('month')
} else if (type == 'month') {
let months = []
if (startYear == Number(this.year)) {
if (endYear == Number(this.year)) { // 起始年份,末尾年份一样时
months = [...Array(endMonth + 1).keys()].slice(startMonth);
} else {
months = [...Array(12 + 1).keys()].slice(startMonth);
}
} else if (endYear == Number(this.year)) {
months = [...Array(endMonth + 1).keys()].slice(1);
} else {
months = [...Array(12 + 1).keys()].slice(1);
}
this.months = months
this.generateArray('day')
} else if (type === 'day') {
let days = []
if (startYear == Number(this.year) && startMonth == Number(this.month)) {
if (endYear == Number(this.year) && endMonth == Number(this
.month)) {
days = [...Array(endDay + 1).keys()].slice(startDay);
} else {
days = [...Array(totalDays + 1).keys()].slice(startDay);
}
} else if (endYear == Number(this.year) && endMonth == Number(this.month)) {
days = [...Array(endDay + 1).keys()].slice(1);
} else {
days = [...Array(totalDays + 1).keys()].slice(1);
}
this.days = days
this.generateArray('hour')
} else if (type === 'hour') {
let hours = []
if (startYear == Number(this.year) && startMonth == Number(this.month) && startDay == Number(
this.day)) {
if (endYear == Number(this.year) && endMonth == Number(this.month) && endDay == Number(this
.day)) {
hours = [...Array(endHour + 1).keys()].slice(startHour);
} else {
hours = [...Array(23 + 1).keys()].slice(startHour);
}
} else if (endYear == Number(this.year) && endMonth == Number(this.month) && endDay == Number(
this.day)) {
hours = [...Array(endHour + 1).keys()].slice(0);
} else {
hours = [...Array(23 + 1).keys()].slice(0);
}
this.hours = hours
this.generateArray('minute')
} else if (type === 'minute') {
let minutes = []
if (startYear == Number(this.year) && startMonth == Number(this.month) && startDay == Number(
this.day) && startHour == Number(this.hour)) {
if (endYear == Number(this.year) && endMonth == Number(this.month) && endDay == Number(this.day) &&
endHour == Number(this.hour)) {
minutes = [...Array(endMinute + 1).keys()].slice(startMinute);
} else {
minutes = [...Array(59 + 1).keys()].slice(startMinute);
}
} else if (endYear == Number(this.year) && endMonth == Number(this.month) && endDay == Number(
this.day) && endHour == Number(this.hour)) {
minutes = [...Array(endMinute + 1).keys()].slice(0);
} else {
minutes = [...Array(59 + 1).keys()].slice(0);
}
this.minutes = minutes
this.generateArray('seconds')
} else {
let seconds = []
if (startYear == Number(this.year) && startMonth == Number(this.month) && startDay == Number(
this.day) && startHour == Number(this.hour) && startMinute ==
Number(this.minute)) {
if (endYear == Number(this.year) && endMonth == Number(this.month) && endDay == Number(this
.day) && endHour == Number(this.hour) && endMinute ==
Number(this.minute)) {
seconds = [...Array(endSecond + 1).keys()].slice(startSecond);
} else {
seconds = [...Array(59 + 1).keys()].slice(startSecond);
}
} else if (endYear == Number(this.year) && endMonth == Number(this.month) && endDay == Number(this
.day) && endHour == Number(this.hour) && endMinute == Number(
this.minute)) {
seconds = [...Array(endSecond + 1).keys()].slice(0);
} else {
seconds = [...Array(59 + 1).keys()].slice(0);
}
this.seconds = seconds
}
},
close() {
this.$emit('close')
},
// 用户更改picker的列选项
change(e) {
this.valueArr = e.detail.value;
let i = 0;
// 这里使用i++是因为this.valueArr数组的长度是不确定长度的它根据this.params的值来配置长度
// 进入if规则i会加1保证了能获取准确的值
if (this.params.year) {
this.year = this.years[this.valueArr[i++]];
this.generateArray('year')
}
if (this.params.month) {
this.month = this.months[this.valueArr[i++]];
this.generateArray('month')
}
if (this.params.day) {
const index = this.valueArr[i++]
this.day = this.days[index] ? this.days[index] : this.days[0];
this.generateArray('day')
}
if (this.params.hour) {
this.hour = this.hours[this.valueArr[i++]];
this.generateArray('hour')
}
if (this.params.minute) {
this.minute = this.minutes[this.valueArr[i++]];
this.generateArray('minute')
}
if (this.params.second) {
this.second = this.seconds[this.valueArr[i++]];
this.generateArray('second')
}
},
// 用户点击确定按钮
getResult() {
// #ifdef MP-WEIXIN
if (this.moving) return;
// #endif
let result = {};
// 只返回用户在this.params中配置了为true的字段
if (this.params.year) result.year = this.formatNumber(this.year || 0);
if (this.params.month) result.month = this.formatNumber(this.month || 0);
if (this.params.day) result.day = this.formatNumber(this.day || 0);
if (this.params.hour) result.hour = this.formatNumber(this.hour || 0);
if (this.params.minute) result.minute = this.formatNumber(this.minute || 0);
if (this.params.second) result.second = this.formatNumber(this.second || 0);
if (this.params.timestamp) result.timestamp = this.getTimestamp();
this.$emit('confirm', result);
this.close();
},
// 小于10前面补0用于月份日期时分秒等
formatNumber(num) {
return +num < 10 ? '0' + num : String(num);
},
// 获取时间戳
getTimestamp() {
let format = this.yunzhupaas.handelFormat(this.format)
let timeType = format === 'yyyy' ? '/01/01 00:00:00' : format === 'yyyy-MM' ? '/01 00:00:00' :
format === 'yyyy-MM-dd' ?
' 00:00:00' : ''
// yyyy-mm-dd为安卓写法不支持iOS需要使用"/"分隔,才能二者兼容
let time = "";
if (this.params.year && !this.params.month && !this.params.day && !this.params.hour && !this.params
.minute && !this.params.second) {
time = this.year + timeType
} else if (this.params.year && this.params.month && !this.params.day && !this.params.hour && !this.params
.minute && !this.params.second) {
time = this.year + '/' + this.month + timeType
} else if (this.params.year && this.params.month && this.params.day && !this.params.hour && !this.params
.minute && !this.params.second) {
time = this.year + '/' + this.month + '/' + this.day + timeType
} else if (this.params.year && this.params.month && this.params.day && this.params.hour && !this.params
.minute && !this.params.second) {
time = this.year + '/' + this.month + '/' + this.day + " " + this.hour + timeType
} else if (this.params.year && this.params.month && this.params.day && this.params.hour && this.params
.minute && !this.params.second) {
time = this.year + '/' + this.month + '/' + this.day + " " + this.hour + ":" + this.minute + timeType
} else {
time = this.year + '/' + this.month + '/' + this.day + " " + this.hour + ":" + this.minute + ":" + this
.second + timeType
}
return new Date(time).getTime();
}
}
};
</script>
<style lang="scss" scoped>
.u-datetime-picker {
position: relative;
z-index: 999;
}
.u-picker-view {
height: 100%;
box-sizing: border-box;
}
.u-picker-header {
width: 100%;
height: 90rpx;
padding: 0 40rpx;
display: flex;
justify-content: space-between;
align-items: center;
box-sizing: border-box;
font-size: 30rpx;
background: #fff;
position: relative;
}
.u-picker-header::after {
content: '';
position: absolute;
border-bottom: 1rpx solid #eaeef1;
-webkit-transform: scaleY(0.5);
transform: scaleY(0.5);
bottom: 0;
right: 0;
left: 0;
}
.u-picker__title {
color: $u-content-color;
}
.u-picker-body {
width: 100%;
height: 500rpx;
overflow: hidden;
background-color: #fff;
}
.u-column-item {
display: flex;
align-items: center;
justify-content: center;
font-size: 32rpx;
color: $u-main-color;
padding: 0 8rpx;
}
.u-text {
font-size: 24rpx;
padding-left: 8rpx;
}
.u-btn-picker {
padding: 16rpx;
box-sizing: border-box;
text-align: center;
text-decoration: none;
}
.u-opacity {
opacity: 0.5;
}
.u-btn-picker--primary {
color: $u-type-primary;
}
.u-btn-picker--tips {
color: $u-tips-color;
}
</style>

View File

@@ -0,0 +1,206 @@
<template>
<view class="yunzhupaas-date-time">
<selectBox v-model="innerValue" :placeholder="placeholder" @openSelect="openSelect" :select-open="selectShow">
</selectBox>
<Select v-if="selectShow" v-model="selectShow" mode="time" :defaultTime="defaultTime" :params="params"
:startDate="startDate" :endDate="endDate" :format='format' @close="handleClose" @confirm="handleConfirm" />
</view>
</template>
<script>
import Select from './Select.vue';
import selectBox from '@/components/selectBox'
export default {
name: 'yunzhupaas-dateTime',
components: {
Select,
selectBox
},
props: {
scene: {
type: String,
default: 'form'
},
inputType: {
type: String,
default: 'select'
},
modelValue: {
type: [String, Number],
default: ''
},
placeholder: {
type: String,
default: '请选择'
},
disabled: {
type: Boolean,
default: false
},
type: {
type: String,
default: 'date'
},
startTime: {
type: [String, Number],
default: 0
},
selectType: {
type: String,
default: ''
},
endTime: {
type: [String, Number],
default: 0
},
format: {
type: String,
default: 'yyyy-MM-dd HH:mm:ss'
}
},
data() {
return {
startDate: '',
endDate: '',
params: {
year: true,
month: true,
day: true,
hour: true,
minute: true,
second: true,
timestamp: true
},
defaultTime: '',
selectShow: false,
innerValue: '',
startTimestamp: -25140,
endTimestamp: 7289625599000,
formatObj: {
'yyyy': 'yyyy',
'yyyy-MM': 'yyyy-mm',
'yyyy-MM-dd': 'yyyy-mm-dd',
'yyyy-MM-dd HH:mm': 'yyyy-mm-dd hh:MM',
'yyyy-MM-dd HH:mm:ss': 'yyyy-mm-dd hh:MM:ss',
'HH:mm:ss': 'hh:MM:ss',
"HH:mm": "hh:MM",
'YYYY': 'yyyy',
'YYYY-MM': 'yyyy-mm',
'YYYY-MM-DD': 'yyyy-mm-dd',
'YYYY-MM-DD HH:mm': 'yyyy-mm-dd hh:MM',
'YYYY-MM-DD HH:mm:ss': 'yyyy-mm-dd hh:MM:ss',
}
}
},
watch: {
modelValue(val) {
this.setDefault()
},
startTime(val) {
this.setMode()
},
endTime(val) {
this.setMode()
}
},
created() {
this.setMode()
this.setDefault()
},
methods: {
setMode() {
let str = this.formatObj[this.format] || 'yyyy-mm-dd hh:MM:ss'
let formatArr = str.trim().split(" ")
let startYear = '970'
if (this.type === 'time') {
let t = formatArr[0].split(":") || []
this.params = {
...this.params,
year: false,
month: false,
day: false,
hour: t.includes('hh'),
minute: t.includes('MM'),
second: t.includes('ss'),
}
this.startDate = this.startTime ? this.getYearDate() + ' ' + this.startTime : this.getYearDate() +
' ' + "00:00:00"
this.endDate = this.endTime ? this.getYearDate() + ' ' + this.endTime : this.getYearDate() + ' ' +
"23:59:59"
} else {
let y = formatArr[0] ? formatArr[0].split("-") : []
let t = formatArr[1] ? formatArr[1].split(":") : []
this.params = {
...this.params,
year: y.includes('yyyy'),
month: y.includes('mm'),
day: y.includes('dd'),
hour: t.includes('hh'),
minute: t.includes('MM'),
second: t.includes('ss'),
}
// #ifdef APP
const sys = uni.getSystemInfoSync()
let platform = sys.platform
startYear = platform === 'ios' ? '1899' : '970'
// #endif
this.startDate = this.startTime ? this.$u.timeFormat(this.startTime, str) : startYear + '-1-1 00:00:00'
this.endDate = this.endTime ? this.$u.timeFormat(this.endTime, str) : '2500-12-31 23:59:59'
}
},
getYearDate() {
let date = new Date();
let year = date.getFullYear()
let month = date.getMonth() + 1
let day = date.getDate()
return year + '-' + month + '-' + day
},
setDefault() {
if (!this.modelValue) return this.innerValue = ''
if (this.type === 'time') {
let valueArr = this.modelValue.split(':')
let formatArr = this.formatObj[this.format].split(':')
this.innerValue = this.modelValue
if (valueArr.length != formatArr.length) this.innerValue = valueArr[0] + ':' + valueArr[1]
this.defaultTime = this.getYearDate() + ' ' + this.modelValue
} else {
const format = 'yyyy-mm-dd hh:MM:ss'
this.innerValue = this.$u.timeFormat(this.modelValue, this.formatObj[this.format])
this.defaultTime = this.$u.timeFormat(this.modelValue, format)
}
},
openSelect() {
uni.hideKeyboard()
if (this.disabled) return
if (new Date(this.startDate).getTime() > new Date(this.endDate).getTime()) return this
.$u.toast('开始时间不能大于结束时间')
this.selectShow = true
},
handleConfirm(e) {
let newFormat = this.format
let timeType = newFormat === 'yyyy' ? '/01/01 00:00:00' : newFormat === 'yyyy-MM' ? '/01 00:00:00' :
newFormat === 'yyyy-MM-dd' ?
' 00:00:00' : ''
this.innerValue = ''
if (this.params.year) this.innerValue += e.year
if (this.params.month) this.innerValue += '-' + e.month
if (this.params.day) this.innerValue += '-' + e.day
if (this.params.hour) this.innerValue += (this.type === 'time' ? '' : ' ') + e.hour
if (this.params.minute) this.innerValue += ':' + e.minute
if (this.params.second) this.innerValue += ':' + e.second
const value = this.type === 'time' ? this.innerValue : e.timestamp
if (this.modelValue === value) return
this.$emit('update:modelValue', value)
this.$emit('change', value, this.selectType)
},
handleClose() {
this.selectShow = false
}
}
}
</script>
<style lang="scss" scoped>
.yunzhupaas-date-time {
width: 100%;
}
</style>

View File

@@ -0,0 +1,103 @@
<template>
<view class="yunzhupaas-date-range">
<YunzhupaasDatePicker v-if="type=='date'" v-model="startValue" :placeholder="placeholder" :disabled="disabled"
inputType="text" scene="searchList" :format="format" @change="change" :defaultTime="startDefaultTime"
selectType='start' :key="key" ref="dateTime" />
<YunzhupaasTimePicker v-else v-model="startValue" :placeholder="placeholder" :disabled="disabled" inputType="text"
scene="searchList" :format="format" @change="change" :defaultTime="startDefaultTime" selectType='start'
:key="key" ref="dateTime" />
<view class="u-p-l-10 u-p-r-10">
</view>
<YunzhupaasDatePicker v-if="type=='date'" v-model="endValue" :placeholder="placeholder" :disabled="disabled"
inputType="text" scene="searchList" :format="format" @change="change" :defaultTime="endDefaultTime"
selectType='end' :key="key+1" ref="dateTime" />
<YunzhupaasTimePicker v-else v-model="endValue" :placeholder="placeholder" :disabled="disabled" inputType="text"
scene="searchList" :format="format" @change="change" :defaultTime="endDefaultTime" selectType='end'
:key="key+1" ref="dateTime" />
</view>
</template>
<script>
export default {
name: 'yunzhupaas-date-range',
props: {
modelValue: {
type: Array,
default: () => []
},
placeholder: {
type: String,
default: '请选择日期范围'
},
disabled: {
type: Boolean,
default: false
},
format: {
type: String,
default: 'yyyy-MM-dd HH:mm:ss'
},
type: {
type: String,
default: 'date'
}
},
data() {
return {
startDefaultTime: '',
endDefaultTime: '',
startValue: '',
endValue: '',
datetimerange: [],
datetimerangeObj: {},
key: +new Date()
}
},
watch: {
modelValue: {
handler(val) {
if (Array.isArray(val) && val.length) {
this.startValue = val[0]
this.endValue = val[1]
} else {
this.startValue = ''
this.endValue = ''
this.datetimerangeObj = {}
}
},
immediate: true
},
},
methods: {
change(e, type) {
this.datetimerange = []
if (type == 'start') {
const format = 'yyyy-mm-dd hh:MM:ss'
this.$set(this.datetimerangeObj, type, e)
this.$refs.dateTime.defaultTime = this.type == 'time' ? this.datetimerangeObj['start'] : this.$u
.timeFormat(this.datetimerangeObj['start'], format)
this.handelValue()
} else {
this.$set(this.datetimerangeObj, type, e)
this.handelValue()
}
},
handelValue() {
this.datetimerange.unshift(this.datetimerangeObj['start'])
this.datetimerange.push(this.datetimerangeObj['end'])
if (this.datetimerange[0] > this.datetimerange[1]) {
this.$u.toast('开始不能大于结束')
setTimeout(() => {
this.startValue = ""
this.endValue = ""
this.datetimerangeObj = {}
this.datetimerange = []
this.key = +new Date()
}, 500)
return
}
this.$emit('update:modelValue', this.datetimerange)
}
}
}
</script>

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