初始代码
This commit is contained in:
168
components/CommonTabs/index.vue
Normal file
168
components/CommonTabs/index.vue
Normal 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>
|
||||
53
components/CustomButton/index.vue
Normal file
53
components/CustomButton/index.vue
Normal 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>
|
||||
314
components/MultSelect/index.vue
Normal file
314
components/MultSelect/index.vue
Normal 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>
|
||||
254
components/SwipeItem/index.vue
Normal file
254
components/SwipeItem/index.vue
Normal 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>
|
||||
304
components/assistantMsg/index.vue
Normal file
304
components/assistantMsg/index.vue
Normal 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>
|
||||
490
components/dataLog/index.vue
Normal file
490
components/dataLog/index.vue
Normal 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>
|
||||
142
components/displayList/index.vue
Normal file
142
components/displayList/index.vue
Normal 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
400
components/index.js
Normal 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
|
||||
}
|
||||
200
components/ly-tree/components/ly-checkbox.vue
Normal file
200
components/ly-tree/components/ly-checkbox.vue
Normal 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>
|
||||
401
components/ly-tree/ly-tree-node.vue
Normal file
401
components/ly-tree/ly-tree-node.vue
Normal 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>
|
||||
651
components/ly-tree/ly-tree.vue
Normal file
651
components/ly-tree/ly-tree.vue
Normal 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>
|
||||
538
components/ly-tree/model/node.js
Normal file
538
components/ly-tree/model/node.js
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
428
components/ly-tree/model/tree-store.js
Normal file
428
components/ly-tree/model/tree-store.js
Normal 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);
|
||||
}
|
||||
}
|
||||
};
|
||||
115
components/ly-tree/tool/util.js
Normal file
115
components/ly-tree/tool/util.js
Normal 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 === '';
|
||||
}
|
||||
63
components/noData/index.vue
Normal file
63
components/noData/index.vue
Normal 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>
|
||||
71
components/selectBox/index.vue
Normal file
71
components/selectBox/index.vue
Normal 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>
|
||||
101
components/treeCollapse/index.vue
Normal file
101
components/treeCollapse/index.vue
Normal 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>
|
||||
377
components/treeCollapse/ly-tree-node.vue
Normal file
377
components/treeCollapse/ly-tree-node.vue
Normal 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>
|
||||
625
components/treeCollapse/ly-tree.vue
Normal file
625
components/treeCollapse/ly-tree.vue
Normal 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>
|
||||
538
components/treeCollapse/model/node.js
Normal file
538
components/treeCollapse/model/node.js
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
428
components/treeCollapse/model/tree-store.js
Normal file
428
components/treeCollapse/model/tree-store.js
Normal 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);
|
||||
}
|
||||
}
|
||||
};
|
||||
115
components/treeCollapse/tool/util.js
Normal file
115
components/treeCollapse/tool/util.js
Normal 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 === '';
|
||||
}
|
||||
59
components/yunzhupaas/Alert/index.vue
Normal file
59
components/yunzhupaas/Alert/index.vue
Normal 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>
|
||||
241
components/yunzhupaas/AreaSelect/Tree.vue
Normal file
241
components/yunzhupaas/AreaSelect/Tree.vue
Normal 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>
|
||||
110
components/yunzhupaas/AreaSelect/index.vue
Normal file
110
components/yunzhupaas/AreaSelect/index.vue
Normal 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>
|
||||
212
components/yunzhupaas/AutoComplete/SearchForm.vue
Normal file
212
components/yunzhupaas/AutoComplete/SearchForm.vue
Normal 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>
|
||||
136
components/yunzhupaas/AutoComplete/index.vue
Normal file
136
components/yunzhupaas/AutoComplete/index.vue
Normal 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>
|
||||
116
components/yunzhupaas/Barcode/index.vue
Normal file
116
components/yunzhupaas/Barcode/index.vue
Normal 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>
|
||||
212
components/yunzhupaas/Barcode/tki-barcode/barcode.js
Normal file
212
components/yunzhupaas/Barcode/tki-barcode/barcode.js
Normal 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
|
||||
@@ -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
|
||||
@@ -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;
|
||||
@@ -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;
|
||||
@@ -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;
|
||||
@@ -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;
|
||||
@@ -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;
|
||||
@@ -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
|
||||
@@ -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 (0–9, A–Z and control codes), special characters, and FNC 1–4
|
||||
var A_CHARS = "[\x00-\x5F\xC8-\xCF]";
|
||||
|
||||
// 128B (Code Set B)
|
||||
// ASCII characters 32 to 127 (0–9, A–Z, a–z), special characters, and FNC 1–4
|
||||
var B_CHARS = "[\x20-\x7F\xC8-\xCF]";
|
||||
|
||||
// 128C (Code Set C)
|
||||
// 00–99 (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
|
||||
}
|
||||
@@ -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,
|
||||
};
|
||||
@@ -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;
|
||||
@@ -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;
|
||||
@@ -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;
|
||||
@@ -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;
|
||||
@@ -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;
|
||||
@@ -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;
|
||||
@@ -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
|
||||
};
|
||||
@@ -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;
|
||||
@@ -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
|
||||
}
|
||||
@@ -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
|
||||
@@ -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
|
||||
}
|
||||
100
components/yunzhupaas/Barcode/tki-barcode/barcodes/ITF/ITF.js
Normal file
100
components/yunzhupaas/Barcode/tki-barcode/barcodes/ITF/ITF.js
Normal 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;
|
||||
@@ -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;
|
||||
@@ -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
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
'use strict';
|
||||
|
||||
import ITF from './ITF'
|
||||
import ITF14 from './ITF14'
|
||||
|
||||
export default {
|
||||
ITF,
|
||||
ITF14
|
||||
}
|
||||
111
components/yunzhupaas/Barcode/tki-barcode/barcodes/MSI/MSI.js
Normal file
111
components/yunzhupaas/Barcode/tki-barcode/barcodes/MSI/MSI.js
Normal 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;
|
||||
@@ -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;
|
||||
@@ -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;
|
||||
@@ -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;
|
||||
@@ -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;
|
||||
@@ -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
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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;
|
||||
37
components/yunzhupaas/Barcode/tki-barcode/barcodes/index.js
Normal file
37
components/yunzhupaas/Barcode/tki-barcode/barcodes/index.js
Normal 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,
|
||||
}
|
||||
@@ -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;
|
||||
203
components/yunzhupaas/Barcode/tki-barcode/tki-barcode.vue
Normal file
203
components/yunzhupaas/Barcode/tki-barcode/tki-barcode.vue
Normal 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>
|
||||
60
components/yunzhupaas/Button/index.vue
Normal file
60
components/yunzhupaas/Button/index.vue
Normal 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>
|
||||
253
components/yunzhupaas/Calculate/index.vue
Normal file
253
components/yunzhupaas/Calculate/index.vue
Normal 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>
|
||||
277
components/yunzhupaas/Cascader/Tree.vue
Normal file
277
components/yunzhupaas/Cascader/Tree.vue
Normal 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>
|
||||
150
components/yunzhupaas/Cascader/index.vue
Normal file
150
components/yunzhupaas/Cascader/index.vue
Normal 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>
|
||||
84
components/yunzhupaas/Checkbox/index.vue
Normal file
84
components/yunzhupaas/Checkbox/index.vue
Normal 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>
|
||||
124
components/yunzhupaas/ColorPicker/index.vue
Normal file
124
components/yunzhupaas/ColorPicker/index.vue
Normal 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>
|
||||
633
components/yunzhupaas/ColorPicker/t-color-picker.vue
Normal file
633
components/yunzhupaas/ColorPicker/t-color-picker.vue
Normal 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>
|
||||
633
components/yunzhupaas/DatePicker/Select.vue
Normal file
633
components/yunzhupaas/DatePicker/Select.vue
Normal 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 是一个 Array<Object> 时,通过 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监听月份的变化,实时变更日的天数,因为不同月份,天数不一样
|
||||
// 一个月可能有30,31天,甚至闰年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>
|
||||
206
components/yunzhupaas/DatePicker/index.vue
Normal file
206
components/yunzhupaas/DatePicker/index.vue
Normal 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>
|
||||
103
components/yunzhupaas/DateRange/index.vue
Normal file
103
components/yunzhupaas/DateRange/index.vue
Normal 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>
|
||||
206
components/yunzhupaas/DepSelect/Tree.vue
Normal file
206
components/yunzhupaas/DepSelect/Tree.vue
Normal file
@@ -0,0 +1,206 @@
|
||||
<template>
|
||||
<u-popup class="yunzhupaas-tree-select-popup" mode="right" :popup="false" v-model="showPopup" length="auto"
|
||||
:z-index="uZIndex" width="100%" @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">
|
||||
<u-search :placeholder="$t('app.apply.pleaseKeyword')" v-model="keyword" height="72"
|
||||
:show-action="false" @change="handleSearch" 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 selectList" :key="index"
|
||||
:text="list.fullName" 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" v-if="selectType === 'all'" :props="realProps" :node-key="realProps.value"
|
||||
:load="loadNode" lazy :tree-data="lazyOptions" show-node-icon :defaultExpandAll='false'
|
||||
@node-click="handleNodeClick" />
|
||||
<ly-tree v-else ref="tree" :node-key="realProps.value" :tree-data="options"
|
||||
@node-click="handleNodeClick" :props="realProps" show-node-icon
|
||||
: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>
|
||||
const defaultProps = {
|
||||
label: 'fullName',
|
||||
value: 'id',
|
||||
icon: 'icon',
|
||||
children: 'children'
|
||||
}
|
||||
import {
|
||||
selectAsyncList
|
||||
} from '@/api/common.js'
|
||||
export default {
|
||||
props: {
|
||||
options: {
|
||||
type: Array,
|
||||
default () {
|
||||
return [];
|
||||
}
|
||||
},
|
||||
selectedData: {
|
||||
type: Array,
|
||||
default () {
|
||||
return [];
|
||||
}
|
||||
},
|
||||
ids: {
|
||||
default: ''
|
||||
},
|
||||
selectType: {
|
||||
default: ''
|
||||
},
|
||||
modelValue: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
zIndex: {
|
||||
type: [String, Number],
|
||||
default: 0
|
||||
},
|
||||
props: {
|
||||
type: Object,
|
||||
default: () => ({
|
||||
label: 'fullName',
|
||||
value: 'id',
|
||||
icon: 'icon',
|
||||
children: 'children',
|
||||
isLeaf: 'isLeaf'
|
||||
})
|
||||
},
|
||||
multiple: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
moving: false,
|
||||
selectList: [],
|
||||
selectListId: [],
|
||||
newListId: [],
|
||||
keyword: '',
|
||||
showPopup: false,
|
||||
lazyOptions: []
|
||||
};
|
||||
},
|
||||
watch: {
|
||||
// 在select弹起的时候,重新初始化所有数据
|
||||
modelValue: {
|
||||
handler(val) {
|
||||
this.showPopup = val
|
||||
if (val) setTimeout(() => this.init(), 10);
|
||||
},
|
||||
immediate: true
|
||||
},
|
||||
},
|
||||
computed: {
|
||||
uZIndex() {
|
||||
return this.zIndex ? this.zIndex : this.$u.zIndex.popup;
|
||||
},
|
||||
realProps() {
|
||||
return {
|
||||
...defaultProps,
|
||||
...this.props
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
init() {
|
||||
this.keyword = ""
|
||||
this.selectListId = Array.isArray(this.ids) ? JSON.parse(JSON.stringify(this.ids.filter(item => item
|
||||
?.trim() !== ''))) : []
|
||||
this.selectList = JSON.parse(JSON.stringify(this.selectedData))
|
||||
},
|
||||
loadNode(node, resolve) {
|
||||
let id = node.key === null ? 0 : node.key
|
||||
this.level = node.level
|
||||
let data = {
|
||||
keyword: '',
|
||||
currOrgId: 0
|
||||
}
|
||||
selectAsyncList(data, id).then(res => {
|
||||
resolve(res.data?.list)
|
||||
})
|
||||
},
|
||||
selectAsyncList() {
|
||||
let data = {
|
||||
keyword: this.keyword,
|
||||
currOrgId: 0
|
||||
}
|
||||
this.lazyOptions = []
|
||||
selectAsyncList(data, 0).then(res => {
|
||||
this.lazyOptions = res.data.list || []
|
||||
})
|
||||
},
|
||||
handleNodeClick(obj) {
|
||||
let data = obj.data
|
||||
if (data.type === 'company') return
|
||||
if (this.multiple) {
|
||||
this.selectListId.push(data.id)
|
||||
this.selectListId = [...new Set(this.selectListId)];
|
||||
} else {
|
||||
this.selectList = []
|
||||
this.selectListId = data.id
|
||||
}
|
||||
this.selectList.push({
|
||||
fullName: this.selectType === 'all' ? data.fullName : data.lastFullName,
|
||||
id: data.id
|
||||
})
|
||||
//数组对象去重--[...new Set(this.selectList.map(JSON.stringify))].map(JSON.parse)
|
||||
//数组去重--[...new Set(this.selectList)]
|
||||
this.selectList = [...new Set(this.selectList.map(JSON.stringify))].map(JSON.parse);
|
||||
},
|
||||
delSelect(index) {
|
||||
this.selectList.splice(index, 1);
|
||||
this.selectListId.splice(index, 1);
|
||||
},
|
||||
setCheckAll() {
|
||||
this.selectListId = [];
|
||||
this.selectList = [];
|
||||
this.$refs.tree.setCheckAll(false);
|
||||
},
|
||||
filterNode(value, data) {
|
||||
if (!value) return true;
|
||||
return data[this.realProps.label].indexOf(value) !== -1;
|
||||
},
|
||||
handleSearch(val) {
|
||||
this.keyword = val
|
||||
if (this.selectType === 'all') return this.$u.debounce(this.selectAsyncList, 600)
|
||||
this.$refs.tree && this.$refs.tree.filter(val)
|
||||
},
|
||||
handleConfirm() {
|
||||
this.$emit('confirm', this.selectList, this.selectListId);
|
||||
this.close();
|
||||
},
|
||||
close() {
|
||||
this.$emit('close', false);
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
191
components/yunzhupaas/DepSelect/index.vue
Normal file
191
components/yunzhupaas/DepSelect/index.vue
Normal file
@@ -0,0 +1,191 @@
|
||||
<template>
|
||||
<view class="yunzhupaas-dep-select">
|
||||
<selectBox v-model="innerValue" :placeholder="placeholder" @openSelect="openSelect" :select-open="selectShow">
|
||||
</selectBox>
|
||||
<Tree v-if="selectShow" v-model="selectShow" :multiple="multiple" :props="props" :selectedData="selectedData"
|
||||
:options="options" :ids="multiple ? modelValue : [modelValue]" @close="handleClose" @confirm="handleConfirm"
|
||||
:selectType="selectType" />
|
||||
</view>
|
||||
</template>
|
||||
<script>
|
||||
import selectBox from '@/components/selectBox'
|
||||
import Tree from './Tree.vue';
|
||||
import {
|
||||
selectedList,
|
||||
getOrgByOrganizeCondition
|
||||
} from '@/api/common.js'
|
||||
import {
|
||||
useBaseStore
|
||||
} from '@/store/modules/base'
|
||||
const baseStore = useBaseStore()
|
||||
export default {
|
||||
components: {
|
||||
Tree,
|
||||
selectBox
|
||||
},
|
||||
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
|
||||
},
|
||||
selectType: {
|
||||
type: String,
|
||||
default: 'all'
|
||||
},
|
||||
ableIds: {
|
||||
type: Array,
|
||||
default: () => []
|
||||
},
|
||||
type: {
|
||||
type: String,
|
||||
default: 'user'
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
selectShow: false,
|
||||
innerValue: '',
|
||||
selectedData: [],
|
||||
allList: [],
|
||||
options: []
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
modelValue: {
|
||||
immediate: true,
|
||||
handler(val) {
|
||||
this.getOptions()
|
||||
if (!val || !val.length) {
|
||||
this.innerValue = ''
|
||||
this.selectedData = [];
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
async getOptions() {
|
||||
let val = this.multiple ? this.modelValue : [this.modelValue];
|
||||
if (this.selectType !== 'all') {
|
||||
this.options = await baseStore.getDepartmentTree()
|
||||
this.allList = await this.treeToArray()
|
||||
this.options = []
|
||||
let query = {
|
||||
'departIds': this.ableIds
|
||||
}
|
||||
await getOrgByOrganizeCondition(query).then(res => {
|
||||
this.options = res.data.list
|
||||
if (!val || !val.length) return
|
||||
this.setDefault()
|
||||
})
|
||||
} else {
|
||||
let ids = val
|
||||
const query = {
|
||||
ids
|
||||
};
|
||||
if (!this.modelValue) return
|
||||
selectedList(query).then(res => {
|
||||
this.options = res.data.list || []
|
||||
this.selectedData = []
|
||||
this.$nextTick(() => {
|
||||
if (this.multiple) {
|
||||
this.innerValue = this.options.map(o => o.fullName).join(',') || '';
|
||||
this.options.map(o => {
|
||||
this.selectedData.push({
|
||||
'fullName': o.fullName,
|
||||
'id': o.id
|
||||
})
|
||||
})
|
||||
} else {
|
||||
this.innerValue = this.options[0]?.fullName || ''
|
||||
this.selectedData.push({
|
||||
'fullName': this.options[0]?.fullName,
|
||||
'id': this.options[0]?.id
|
||||
})
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
},
|
||||
setDefault() {
|
||||
this.selectedData = [];
|
||||
let val = this.multiple ? this.modelValue : [this.modelValue];
|
||||
let txt = ''
|
||||
for (let i = 0; i < val.length; i++) {
|
||||
inner: for (let j = 0; j < this.allList.length; j++) {
|
||||
if (this.allList[j].id === val[i]) {
|
||||
this.selectedData.push({
|
||||
'fullName': this.allList[j].fullName,
|
||||
'id': this.allList[j].id
|
||||
})
|
||||
break inner
|
||||
}
|
||||
}
|
||||
}
|
||||
for (let i = 0; i < this.selectedData.length; i++) {
|
||||
if (!!this.selectedData[i].lastFullName) {
|
||||
txt += (i ? ',' : '') + this.selectedData[i].lastFullName
|
||||
} else {
|
||||
txt += (i ? ',' : '') + this.selectedData[i].fullName
|
||||
}
|
||||
}
|
||||
this.innerValue = txt
|
||||
},
|
||||
async treeToArray() {
|
||||
let options = JSON.parse(JSON.stringify(this.options))
|
||||
let list = []
|
||||
const loop = (options) => {
|
||||
for (let i = 0; i < options.length; i++) {
|
||||
const item = options[i]
|
||||
list.push(item)
|
||||
if (item.hasChildren && item.children && Array.isArray(item.children)) {
|
||||
loop(item.children)
|
||||
}
|
||||
}
|
||||
}
|
||||
loop(options)
|
||||
return list
|
||||
},
|
||||
openSelect() {
|
||||
if (this.disabled) return
|
||||
this.selectShow = true
|
||||
},
|
||||
handleConfirm(e, selectId) {
|
||||
if (!this.multiple) {
|
||||
this.$emit('update:modelValue', selectId)
|
||||
this.$emit('change', e[0], selectId)
|
||||
} else {
|
||||
this.$emit('update:modelValue', selectId)
|
||||
this.$emit('change', e, selectId)
|
||||
}
|
||||
},
|
||||
handleClose() {
|
||||
this.selectShow = false
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.yunzhupaas-dep-select {
|
||||
width: 100%;
|
||||
}
|
||||
</style>
|
||||
13
components/yunzhupaas/Divider/index.vue
Normal file
13
components/yunzhupaas/Divider/index.vue
Normal file
@@ -0,0 +1,13 @@
|
||||
<template>
|
||||
<u-divider half-width="200" height="80">{{content}}</u-divider>
|
||||
</template>
|
||||
<script>
|
||||
export default {
|
||||
name: 'yunzhupaas-divider',
|
||||
props: {
|
||||
content: {
|
||||
default: ''
|
||||
}
|
||||
},
|
||||
}
|
||||
</script>
|
||||
BIN
components/yunzhupaas/Editor/Pacifico-Regular.ttf
Normal file
BIN
components/yunzhupaas/Editor/Pacifico-Regular.ttf
Normal file
Binary file not shown.
238
components/yunzhupaas/Editor/editor-icon.css
Normal file
238
components/yunzhupaas/Editor/editor-icon.css
Normal file
File diff suppressed because one or more lines are too long
BIN
components/yunzhupaas/Editor/iconfont.ttf
Normal file
BIN
components/yunzhupaas/Editor/iconfont.ttf
Normal file
Binary file not shown.
269
components/yunzhupaas/Editor/index.vue
Normal file
269
components/yunzhupaas/Editor/index.vue
Normal file
@@ -0,0 +1,269 @@
|
||||
<template>
|
||||
<view class="yunzhupaas-editor">
|
||||
<template v-if="!detailed">
|
||||
<view class='toolbar'>
|
||||
<view :class="{'ql-active':formats.bold}" class="iconfont icon-zitijiacu" data-name="bold"
|
||||
@tap="format">
|
||||
</view>
|
||||
<view :class="{'ql-active':formats.italic}" class="iconfont icon-zitixieti" data-name="italic"
|
||||
@tap="format"></view>
|
||||
<view :class="{'ql-active':formats.underline}" class="iconfont icon-zitixiahuaxian"
|
||||
data-name="underline" @tap="format"></view>
|
||||
<view :class="{'ql-active':formats.strike}" class="iconfont icon-zitishanchuxian" data-name="strike"
|
||||
@tap="format"></view>
|
||||
<view :class="{'ql-active':formats.align==='left'}" class="iconfont icon-zuoduiqi" data-name="align"
|
||||
data-value="left" @tap="format"></view>
|
||||
<view :class="{'ql-active':formats.align==='center'}" class="iconfont icon-juzhongduiqi"
|
||||
data-name="align" data-value="center" @tap="format"></view>
|
||||
<view :class="{'ql-active':formats.align==='right'}" class="iconfont icon-youduiqi" data-name="align"
|
||||
data-value="right" @tap="format"></view>
|
||||
<view :class="{'ql-active':formats.align==='justify'}" class="iconfont icon-zuoyouduiqi"
|
||||
data-name="align" data-value="justify" @tap="format"></view>
|
||||
<view :class="{'ql-active':formats.lineHeight}" class="iconfont icon-line-height" data-name="lineHeight"
|
||||
data-value="2" @tap="format"></view>
|
||||
<view :class="{'ql-active':formats.letterSpacing}" class="iconfont icon-Character-Spacing"
|
||||
data-name="letterSpacing" data-value="2em" @tap="format"></view>
|
||||
<view :class="{'ql-active':formats.marginTop}" class="iconfont icon-722bianjiqi_duanqianju"
|
||||
data-name="marginTop" data-value="20px" @tap="format"></view>
|
||||
<view :class="{'ql-active':formats.marginBottom}" class="iconfont icon-723bianjiqi_duanhouju"
|
||||
data-name="marginBottom" data-value="20px" @tap="format"></view>
|
||||
<view class="iconfont icon-clearedformat" @tap="removeFormat"></view>
|
||||
<view :class="{'ql-active':formats.fontFamily}" class="iconfont icon-font" data-name="fontFamily"
|
||||
data-value="Pacifico" @tap="format"></view>
|
||||
<view :class="{'ql-active':formats.fontSize === '24px'}" class="iconfont icon-fontsize"
|
||||
data-name="fontSize" data-value="24px" @tap="format"></view>
|
||||
<view :class="{'ql-active':formats.color === '#0000ff'}" class="iconfont icon-text_color"
|
||||
data-name="color" data-value="#0000ff" @tap="format"></view>
|
||||
<view :class="{'ql-active':formats.backgroundColor === '#00ff00'}" class="iconfont icon-fontbgcolor"
|
||||
data-name="backgroundColor" data-value="#00ff00" @tap="format"></view>
|
||||
<view class="iconfont icon-date" @tap="insertDate"></view>
|
||||
<view class="iconfont icon--checklist" data-name="list" data-value="check" @tap="format"></view>
|
||||
<view :class="{'ql-active':formats.list === 'ordered'}" class="iconfont icon-youxupailie"
|
||||
data-name="list" data-value="ordered" @tap="format"></view>
|
||||
<view :class="{'ql-active':formats.list === 'bullet'}" class="iconfont icon-wuxupailie" data-name="list"
|
||||
data-value="bullet" @tap="format"></view>
|
||||
<view class="iconfont icon-undo" @tap="undo"></view>
|
||||
<view class="iconfont icon-redo" @tap="redo"></view>
|
||||
<view class="iconfont icon-outdent" data-name="indent" data-value="-1" @tap="format"></view>
|
||||
<view class="iconfont icon-indent" data-name="indent" data-value="+1" @tap="format"></view>
|
||||
<view class="iconfont icon-fengexian" @tap="insertDivider"></view>
|
||||
<view class="iconfont icon-charutupian" @tap="insertImage"></view>
|
||||
<view :class="{'ql-active':formats.header === 1}" class="iconfont icon-format-header-1"
|
||||
data-name="header" :data-value="1" @tap="format"></view>
|
||||
<view :class="{'ql-active':formats.script === 'sub'}" class="iconfont icon-zitixiabiao"
|
||||
data-name="script" data-value="sub" @tap="format"></view>
|
||||
<view :class="{'ql-active':formats.script === 'super'}" class="iconfont icon-zitishangbiao"
|
||||
data-name="script" data-value="super" @tap="format"></view>
|
||||
<view class="iconfont icon-shanchu" @tap="clear"></view>
|
||||
<view :class="{'ql-active':formats.direction === 'rtl'}" class="iconfont icon-direction-rtl"
|
||||
data-name="direction" data-value="rtl" @tap="format"></view>
|
||||
</view>
|
||||
<view class="editor-wrapper">
|
||||
<editor :id="id" class="ql-container" :placeholder="placeholder" showImgSize showImgToolbar
|
||||
showImgResize @statuschange="onStatusChange" :read-only="disabled" @ready="onEditorReady"
|
||||
@input="getValue">
|
||||
</editor>
|
||||
</view>
|
||||
</template>
|
||||
<view v-else>
|
||||
<mp-html class="editor-box" :content="modelValue" />
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'yunzhupaas-editor',
|
||||
props: {
|
||||
modelValue: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
placeholder: {
|
||||
type: String,
|
||||
default: '请输入'
|
||||
},
|
||||
disabled: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
detailed: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
innerValue: '',
|
||||
readOnly: false,
|
||||
formats: {},
|
||||
editorChange: false,
|
||||
id: 'yunzhupaas-editor-' + this.yunzhupaas.idGenerator(),
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
modelValue(val) {
|
||||
if (this.editorChange && val) return
|
||||
this.editorChange = false
|
||||
this.editorCtx && this.editorCtx.setContents({
|
||||
html: val
|
||||
})
|
||||
}
|
||||
},
|
||||
onLoad() {
|
||||
uni.loadFontFace({
|
||||
family: 'Pacifico',
|
||||
source: 'url("/Pacifico-Regular.ttf")'
|
||||
})
|
||||
},
|
||||
methods: {
|
||||
readOnlyChange() {
|
||||
this.readOnly = !this.readOnly
|
||||
},
|
||||
onEditorReady() {
|
||||
// #ifdef APP-PLUS || H5 ||MP-WEIXIN
|
||||
uni.createSelectorQuery().in(this).select('#' + this.id).context((res) => {
|
||||
this.editorCtx = res.context
|
||||
this.editorCtx.setContents({
|
||||
html: this.modelValue
|
||||
})
|
||||
}).exec()
|
||||
// #endif
|
||||
},
|
||||
undo() {
|
||||
this.editorCtx.undo()
|
||||
},
|
||||
redo() {
|
||||
this.editorCtx.redo()
|
||||
},
|
||||
format(e) {
|
||||
let {
|
||||
name,
|
||||
value
|
||||
} = e.target.dataset
|
||||
if (!name) return
|
||||
this.editorCtx.format(name, value)
|
||||
},
|
||||
onStatusChange(e) {
|
||||
const formats = e.detail
|
||||
this.formats = formats
|
||||
},
|
||||
insertDivider() {
|
||||
this.editorCtx.insertDivider()
|
||||
},
|
||||
clear() {
|
||||
this.editorCtx.clear()
|
||||
},
|
||||
removeFormat() {
|
||||
this.editorCtx.removeFormat()
|
||||
},
|
||||
insertDate() {
|
||||
const date = new Date()
|
||||
const formatDate = `${date.getFullYear()}/${date.getMonth() + 1}/${date.getDate()}`
|
||||
this.editorCtx.insertText({
|
||||
text: formatDate
|
||||
})
|
||||
},
|
||||
insertImage() {
|
||||
uni.chooseImage({
|
||||
count: 1,
|
||||
success: (res) => {
|
||||
this.getImageBase64(res)
|
||||
}
|
||||
})
|
||||
},
|
||||
getImageBase64(res) {
|
||||
const image = res.tempFilePaths[0]
|
||||
// #ifdef MP-WEIXIN
|
||||
uni.getFileSystemManager().readFile({
|
||||
filePath: image,
|
||||
encoding: "base64",
|
||||
success: (e) => {
|
||||
this.insertImageVal('data:image/jpeg;base64,' + e.data)
|
||||
},
|
||||
});
|
||||
// #endif
|
||||
// #ifdef APP-PLUS
|
||||
let path = plus.io.convertLocalFileSystemURL(image);
|
||||
let fileReader = new plus.io.FileReader();
|
||||
fileReader.readAsDataURL(path);
|
||||
fileReader.onloadend = (e) => {
|
||||
this.insertImageVal(e.target.result);
|
||||
}
|
||||
// #endif
|
||||
// #ifdef H5
|
||||
uni.request({
|
||||
url: image, //临时路径
|
||||
responseType: 'arraybuffer', //设置返回的数据格式为arraybuffer
|
||||
success: res => {
|
||||
const base64 = wx.arrayBufferToBase64(res.data)
|
||||
this.insertImageVal('data:image/jpeg;base64,' + base64);
|
||||
},
|
||||
})
|
||||
// #endif
|
||||
},
|
||||
insertImageVal(image) {
|
||||
this.editorCtx.insertImage({
|
||||
src: image,
|
||||
alt: '图像',
|
||||
success: function() {}
|
||||
})
|
||||
},
|
||||
getValue(e) {
|
||||
this.editorChange = true
|
||||
const that = this
|
||||
this.editorCtx.getContents({
|
||||
success: function(res) {
|
||||
let val = res.text === '\n' ? '' : res.html
|
||||
that.$emit('update:modelValue', val)
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@import "./editor-icon.css";
|
||||
|
||||
:deep(.ql-editor) {
|
||||
word-break: break-all;
|
||||
}
|
||||
|
||||
.yunzhupaas-editor {
|
||||
background-color: #fff;
|
||||
|
||||
.iconfont {
|
||||
display: inline-block;
|
||||
width: 80rpx;
|
||||
height: 80rpx;
|
||||
cursor: pointer;
|
||||
font-size: 20px;
|
||||
line-height: 80rpx;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.toolbar {
|
||||
height: 240rpx;
|
||||
background: #f5f5f5;
|
||||
overflow-y: auto;
|
||||
box-sizing: border-box;
|
||||
border-bottom: 0;
|
||||
font-family: 'Helvetica Neue', 'Helvetica', 'Arial', sans-serif;
|
||||
}
|
||||
|
||||
.ql-container {
|
||||
box-sizing: border-box;
|
||||
padding: 20rpx;
|
||||
width: 100%;
|
||||
height: 400rpx;
|
||||
margin-top: 20rpx;
|
||||
font-size: 30rpx;
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
.ql-active {
|
||||
color: #06c;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
175
components/yunzhupaas/GroupSelect/Tree.vue
Normal file
175
components/yunzhupaas/GroupSelect/Tree.vue
Normal file
@@ -0,0 +1,175 @@
|
||||
<template>
|
||||
<u-popup class="yunzhupaas-tree-select-popup" mode="right" v-model="showPopup" @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-select-search">
|
||||
<u-search :placeholder="$t('app.apply.pleaseKeyword')" v-model="keyword" height="72"
|
||||
:show-action="false" @change="handleSearch" 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 selectList" :key="index"
|
||||
:text="list.fullName" 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"
|
||||
@node-click="handleNodeClick" :props="realProps" :show-node-icon="true" :show-radio="false"
|
||||
:filter-node-method="filterNode" :highlight-current="true" />
|
||||
</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'
|
||||
}
|
||||
|
||||
export default {
|
||||
props: {
|
||||
options: {
|
||||
type: Array,
|
||||
default () {
|
||||
return [];
|
||||
}
|
||||
},
|
||||
selectedData: {
|
||||
type: Array,
|
||||
default () {
|
||||
return [];
|
||||
}
|
||||
},
|
||||
selectId: {
|
||||
default: ""
|
||||
},
|
||||
// 通过双向绑定控制组件的弹出与收起
|
||||
modelValue: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
// 弹出的z-index值
|
||||
zIndex: {
|
||||
type: [String, Number],
|
||||
default: 99999
|
||||
},
|
||||
props: {
|
||||
type: Object,
|
||||
default: () => ({
|
||||
label: 'fullName',
|
||||
value: 'id',
|
||||
icon: 'icon',
|
||||
children: 'children',
|
||||
isLeaf: 'isLeaf'
|
||||
})
|
||||
},
|
||||
multiple: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
moving: false,
|
||||
selectList: [],
|
||||
selectListId: [],
|
||||
newListId: [],
|
||||
keyword: '',
|
||||
showPopup: false
|
||||
};
|
||||
},
|
||||
watch: {
|
||||
modelValue: {
|
||||
handler(val) {
|
||||
this.showPopup = val
|
||||
if (val) setTimeout(() => this.init(), 10);
|
||||
},
|
||||
immediate: true
|
||||
},
|
||||
},
|
||||
created() {
|
||||
this.init()
|
||||
},
|
||||
computed: {
|
||||
uZIndex() {
|
||||
// 如果用户有传递z-index值,优先使用
|
||||
return this.zIndex ? this.zIndex : this.$u.zIndex.popup;
|
||||
},
|
||||
realProps() {
|
||||
return {
|
||||
...defaultProps,
|
||||
...this.props
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
init() {
|
||||
this.keyword = ''
|
||||
this.selectListId = JSON.parse(JSON.stringify(this.selectId))
|
||||
if (!Array.isArray(this.selectId)) this.selectListId = []
|
||||
this.selectList = JSON.parse(JSON.stringify(this.selectedData))
|
||||
this.handleSearch()
|
||||
},
|
||||
handleNodeClick(obj) {
|
||||
if (obj.level == 1) return
|
||||
let isExist = false;
|
||||
if (!this.multiple) {
|
||||
// 单选
|
||||
this.selectList = [];
|
||||
this.selectListId = [];
|
||||
}
|
||||
if (!this.selectList.some(item => item.id === obj.data.id)) {
|
||||
this.selectList.push(obj.data);
|
||||
this.selectListId.push(obj.data.id);
|
||||
}
|
||||
},
|
||||
delSelect(index) {
|
||||
this.selectList.splice(index, 1);
|
||||
this.selectListId.splice(index, 1);
|
||||
},
|
||||
setCheckAll() {
|
||||
this.selectList = [];
|
||||
this.selectListId = [];
|
||||
this.$refs.tree.setCheckAll(false);
|
||||
},
|
||||
handleConfirm() {
|
||||
this.$emit('confirm', this.selectList, this.selectListId);
|
||||
this.close();
|
||||
},
|
||||
close() {
|
||||
this.$emit('close');
|
||||
},
|
||||
filterNode(value, data) {
|
||||
if (!value) return true;
|
||||
return data[this.realProps.label].indexOf(value) !== -1;
|
||||
},
|
||||
handleSearch(val) {
|
||||
this.$refs.tree && this.$refs.tree.filter(this.keyword)
|
||||
},
|
||||
}
|
||||
};
|
||||
</script>
|
||||
151
components/yunzhupaas/GroupSelect/index.vue
Normal file
151
components/yunzhupaas/GroupSelect/index.vue
Normal file
@@ -0,0 +1,151 @@
|
||||
<template>
|
||||
<view class="yunzhupaas-group-select">
|
||||
<selectBox v-model="innerValue" :placeholder="placeholder" @openSelect="openSelect" :select-open="selectShow">
|
||||
</selectBox>
|
||||
<Tree v-model="selectShow" :options="options" :multiple="multiple" :props="props" :selectedData="selectedData"
|
||||
:selectId="!multiple ? [modelValue] : modelValue" @close="handleClose" @confirm="handleConfirm" />
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import Tree from './Tree.vue';
|
||||
import selectBox from '@/components/selectBox'
|
||||
import {
|
||||
getGroupCondition
|
||||
} from '@/api/common.js'
|
||||
import {
|
||||
useBaseStore
|
||||
} from '@/store/modules/base'
|
||||
const baseStore = useBaseStore()
|
||||
export default {
|
||||
name: 'yunzhupaas-group-select',
|
||||
components: {
|
||||
Tree,
|
||||
selectBox
|
||||
},
|
||||
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
|
||||
},
|
||||
selectType: {
|
||||
type: String,
|
||||
default: 'all'
|
||||
},
|
||||
ableIds: {
|
||||
type: Array,
|
||||
default: () => []
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
selectShow: false,
|
||||
innerValue: '',
|
||||
options: [],
|
||||
selectedData: [],
|
||||
allList: [],
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
modelValue: {
|
||||
handler(val) {
|
||||
this.getOptions()
|
||||
},
|
||||
immediate: true
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
getOptions() {
|
||||
this.selectType === 'custom' ? this.getGroupCondition() : this.getAllOptions()
|
||||
},
|
||||
setDefault() {
|
||||
if (!this.modelValue || !this.modelValue.length) return this.setNullValue();
|
||||
this.selectedData = [];
|
||||
let val = this.multiple ? this.modelValue : [this.modelValue];
|
||||
for (let i = 0; i < val.length; i++) {
|
||||
inner: for (let j = 0; j < this.allList.length; j++) {
|
||||
if (this.allList[j].id === val[i]) {
|
||||
this.selectedData.push(this.allList[j])
|
||||
break inner
|
||||
}
|
||||
}
|
||||
}
|
||||
this.innerValue = this.selectedData.map(o => o.fullName).join();
|
||||
},
|
||||
async getAllOptions() {
|
||||
this.options = await baseStore.getGroupTree()
|
||||
this.allList = await this.treeToArray()
|
||||
this.setDefault()
|
||||
},
|
||||
getGroupCondition() {
|
||||
let query = {
|
||||
ids: this.ableIds
|
||||
}
|
||||
getGroupCondition(query).then(res => {
|
||||
this.options = res.data.list || [];
|
||||
this.allList = this.treeToArray()
|
||||
|
||||
this.setDefault()
|
||||
})
|
||||
},
|
||||
setNullValue() {
|
||||
this.innerValue = '';
|
||||
this.selectedData = [];
|
||||
},
|
||||
treeToArray() {
|
||||
let options = JSON.parse(JSON.stringify(this.options))
|
||||
let list = []
|
||||
const loop = (options) => {
|
||||
for (let i = 0; i < options.length; i++) {
|
||||
const item = options[i]
|
||||
list.push(item)
|
||||
if (item.children && Array.isArray(item.children)) loop(item.children)
|
||||
}
|
||||
}
|
||||
loop(options)
|
||||
return list
|
||||
},
|
||||
openSelect() {
|
||||
if (this.disabled) return
|
||||
this.selectShow = true
|
||||
},
|
||||
handleConfirm(e, selectId) {
|
||||
if (!this.multiple) {
|
||||
this.$emit('update:modelValue', selectId[0])
|
||||
this.$emit('change', selectId[0], e[0])
|
||||
} else {
|
||||
this.$emit('update:modelValue', selectId)
|
||||
this.$emit('change', selectId, e)
|
||||
}
|
||||
},
|
||||
handleClose() {
|
||||
this.selectShow = false
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.yunzhupaas-group-select {
|
||||
width: 100%;
|
||||
}
|
||||
</style>
|
||||
40
components/yunzhupaas/GroupTitle/index.vue
Normal file
40
components/yunzhupaas/GroupTitle/index.vue
Normal file
@@ -0,0 +1,40 @@
|
||||
<template>
|
||||
<view class="yunzhupaas-group-title" :style="{'text-align':contentPosition}" @click="handleClick()">{{content}}
|
||||
<u-icon :name="helpMessage? 'question-circle-fill':''" class="u-m-l-10" color="#a0acb7"></u-icon>
|
||||
</view>
|
||||
</template>
|
||||
<script>
|
||||
export default {
|
||||
name: 'yunzhupaas-group-title',
|
||||
props: {
|
||||
content: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
helpMessage: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
contentPosition: {
|
||||
type: String,
|
||||
default: 'left'
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
handleClick() {
|
||||
if (!this.helpMessage) return
|
||||
this.$emit('groupIcon')
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.yunzhupaas-group-title {
|
||||
width: 100%;
|
||||
color: #333333;
|
||||
font-size: 32rpx;
|
||||
line-height: 70rpx;
|
||||
margin: 0;
|
||||
padding: 0 20rpx;
|
||||
}
|
||||
</style>
|
||||
217
components/yunzhupaas/Input/index.vue
Normal file
217
components/yunzhupaas/Input/index.vue
Normal file
@@ -0,0 +1,217 @@
|
||||
<template>
|
||||
<view class="yunzhupaas-input">
|
||||
<template v-if="!detailed">
|
||||
<view class="input-content" :class="{'input-border':addonBefore||addonAfter}">
|
||||
<view class="input-left u-line-1" v-if="addonBefore">{{addonBefore}}</view>
|
||||
<view class="input-center">
|
||||
<u-input input-align='right' :border="false" v-model="innerValue"
|
||||
:type="showPassword?'password':'text'" :maxlength="maxlength||maxlength===0?maxlength:9999"
|
||||
:placeholder="placeholder" :disabled="disabled" :clearable='disabled ? false : clearable'
|
||||
@input="onInput" @blur="onBlur" />
|
||||
</view>
|
||||
<!-- #ifndef H5 -->
|
||||
<text class="icon-ym icon-ym-scanCode1" v-if="useScan" @click="scanCode" />
|
||||
<!-- #endif -->
|
||||
<view class="input-right u-line-1" v-if="addonAfter">{{addonAfter}}</view>
|
||||
<view class="input-count" v-if="showCount&&!addonBefore&&!addonAfter">
|
||||
<text>{{ innerValue?String(innerValue).length:0 }}</text><text
|
||||
v-if="maxlength">/{{ maxlength }}</text>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
<view class="detail-text" :class="{ ellipsis: showOverflow ,['detail-text-'+align]:true}" v-else>
|
||||
<text class="detail-text-addon" v-if="addonBefore">{{ addonBefore }}</text>
|
||||
{{ maskedValue }}
|
||||
<text class="detail-text-addon" v-if="addonAfter">{{ addonAfter }}</text>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
<script>
|
||||
import {
|
||||
useTextMask
|
||||
} from './useTextMask';
|
||||
export default {
|
||||
name: 'yunzhupaas-input',
|
||||
props: {
|
||||
modelValue: {
|
||||
type: [String, Number],
|
||||
default: ''
|
||||
},
|
||||
placeholder: {
|
||||
type: String,
|
||||
default: '请输入'
|
||||
},
|
||||
maxlength: {
|
||||
type: Number,
|
||||
default: null
|
||||
},
|
||||
showPassword: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
disabled: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
clearable: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
detailed: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
showOverflow: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
addonBefore: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
addonAfter: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
align: {
|
||||
type: String,
|
||||
default: 'right'
|
||||
},
|
||||
useScan: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
useMask: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
maskConfig: {
|
||||
type: Object,
|
||||
default: () => {}
|
||||
},
|
||||
showCount: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
innerValue: '',
|
||||
maskedValue: '',
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
modelValue: {
|
||||
handler(val) {
|
||||
this.innerValue = val
|
||||
if (!this.useMask) return (this.maskedValue = val);
|
||||
const {
|
||||
getMaskedText
|
||||
} = useTextMask(this.maskConfig);
|
||||
this.maskedValue = getMaskedText(val);
|
||||
},
|
||||
immediate: true,
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
onInput(val) {
|
||||
this.$nextTick(() => {
|
||||
this.$emit('update:modelValue', val)
|
||||
this.$emit('change', val)
|
||||
})
|
||||
},
|
||||
onBlur(val) {
|
||||
this.$emit('blur', val)
|
||||
},
|
||||
isJSON(str) {
|
||||
try {
|
||||
var obj = JSON.parse(str);
|
||||
if (typeof obj == 'object' && obj) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
} catch (e) {
|
||||
return false;
|
||||
}
|
||||
},
|
||||
scanCode() {
|
||||
uni.scanCode({
|
||||
success: res => {
|
||||
if (!res.result || typeof res.result !== 'string') return
|
||||
this.onInput(res.result)
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style lang="scss">
|
||||
.yunzhupaas-input {
|
||||
width: 100%;
|
||||
|
||||
.input-content {
|
||||
display: flex;
|
||||
border-radius: 10rpx;
|
||||
height: 74rpx;
|
||||
|
||||
&.input-border {
|
||||
border: 1rpx solid rgb(220, 223, 230)
|
||||
}
|
||||
|
||||
.input-center {
|
||||
flex: 1;
|
||||
// padding: 0 8rpx;
|
||||
}
|
||||
|
||||
.input-left,
|
||||
.input-right {
|
||||
flex-shrink: 0;
|
||||
width: 128rpx;
|
||||
background-color: #f5f7fa;
|
||||
color: #909399;
|
||||
padding: 0 10rpx;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.input-left {
|
||||
border-right: 1rpx solid #dcdfe6;
|
||||
border-radius: 10rpx 0 0 10rpx;
|
||||
}
|
||||
|
||||
.input-right {
|
||||
border-left: 1rpx solid #dcdfe6;
|
||||
border-radius: 0px 10px 10px 0px;
|
||||
}
|
||||
|
||||
.icon-ym-scanCode1 {
|
||||
margin-right: 8rpx;
|
||||
color: #909399;
|
||||
}
|
||||
|
||||
.input-count {
|
||||
color: #909399;
|
||||
font-size: 24rpx;
|
||||
}
|
||||
}
|
||||
|
||||
.detail-text {
|
||||
word-break: break-all;
|
||||
text-align: right;
|
||||
|
||||
.detail-text-addon {
|
||||
color: #909399;
|
||||
}
|
||||
|
||||
&.ellipsis {
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
&.detail-text-left {
|
||||
text-align: left;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
170
components/yunzhupaas/Input/useTextMask.js
Normal file
170
components/yunzhupaas/Input/useTextMask.js
Normal file
@@ -0,0 +1,170 @@
|
||||
/**
|
||||
* maskType
|
||||
* 1 - 全掩盖
|
||||
* 2 - 姓名-显示前1个字,后1个字
|
||||
* 3 - 手机号-显示前3位,后4位
|
||||
* 4 - 邮箱-显示前3个字,@和之后的字
|
||||
* 5 - 身份证-显示前6位,后3位,虚拟为4位
|
||||
* 6 - IP地址-显示第1段IP
|
||||
* 7 - 车牌号-显示前1个字,后2位
|
||||
* 8 - 银行卡号-显示前6位,后4位
|
||||
* 0 - 自定义规则
|
||||
*/
|
||||
export const defaultMaskOptions = {
|
||||
filler: '*', // 填充符号
|
||||
maskType: 1, // 掩码规则
|
||||
prefixType: 1, // 开头显示
|
||||
prefixLimit: 0, // 开头字数
|
||||
prefixSpecifyChar: '', // 开头字符
|
||||
suffixType: 1, // 结尾显示
|
||||
suffixLimit: 0, // 结尾字数
|
||||
suffixSpecifyChar: '', // 结尾字符
|
||||
ignoreChar: '', // 显示字符
|
||||
useUnrealMask: false, // 虚拟掩码
|
||||
unrealMaskLength: 1, // 虚拟掩码长度
|
||||
};
|
||||
|
||||
export function useTextMask(options = {}) {
|
||||
const config = {
|
||||
...defaultMaskOptions,
|
||||
...options
|
||||
};
|
||||
|
||||
// 全掩盖
|
||||
function maskAll(str) {
|
||||
return config.filler.repeat(str.length);
|
||||
}
|
||||
//姓名 显示前1个字,后1个字
|
||||
function maskName(str) {
|
||||
if (str.length <= 1) return str;
|
||||
const prefix = str[0];
|
||||
if (str.length === 2) return prefix + config.filler;
|
||||
const suffix = str.slice(-1);
|
||||
const maskedChars = config.filler.repeat(str.length - 2);
|
||||
return prefix + maskedChars + suffix;
|
||||
}
|
||||
// 手机号 - 显示前3位,后4位
|
||||
function maskPhoneNumber(str) {
|
||||
if (str.length <= 7) return str;
|
||||
const prefix = str.slice(0, 3);
|
||||
const suffix = str.slice(-4);
|
||||
const maskedChars = config.filler.repeat(str.length - 7);
|
||||
return prefix + maskedChars + suffix;
|
||||
}
|
||||
// 邮箱 - 显示前3个字,@和之后的字
|
||||
function maskEmailAddress(str) {
|
||||
const atIndex = str.indexOf('@');
|
||||
if (str.length <= 3 || (atIndex > -1 && atIndex < 3)) return str;
|
||||
let suffixLength = 0;
|
||||
let maskedCharsLength = str.length - 3;
|
||||
if (atIndex > 0) {
|
||||
suffixLength = atIndex;
|
||||
maskedCharsLength = atIndex - 3;
|
||||
}
|
||||
const prefix = str.slice(0, 3);
|
||||
const suffix = suffixLength ? str.slice(suffixLength) : '';
|
||||
const maskedChars = config.filler.repeat(maskedCharsLength);
|
||||
return prefix + maskedChars + suffix;
|
||||
}
|
||||
// 身份证 - 显示前6位,后3位,虚拟为4位
|
||||
function maskIdNumber(str) {
|
||||
if (str.length <= 9) return str;
|
||||
const prefix = str.slice(0, 6);
|
||||
const suffix = str.slice(-3);
|
||||
const maskedChars = config.filler.repeat(4);
|
||||
return prefix + maskedChars + suffix;
|
||||
}
|
||||
// IP地址-显示第1段IP
|
||||
function maskIPAddress(str) {
|
||||
const segments = str.split('.');
|
||||
if (segments.length < 1) return str;
|
||||
const maskedChars = ('.' + config.filler.repeat(3)).repeat(3);
|
||||
return segments[0] + maskedChars;
|
||||
}
|
||||
// 车牌号-显示前1个字,后2位
|
||||
function maskLicensePlate(str) {
|
||||
if (str.length <= 3) return str;
|
||||
const prefix = str[0];
|
||||
const suffix = str.slice(-2);
|
||||
const maskedChars = config.filler.repeat(str.length - 3);
|
||||
return prefix + maskedChars + suffix;
|
||||
}
|
||||
// 银行卡号-显示前6位,后4位
|
||||
function maskBankCard(str) {
|
||||
if (str.length <= 10) return str;
|
||||
const prefix = str.slice(0, 6);
|
||||
const suffix = str.slice(-4);
|
||||
const maskedChars = config.filler.repeat(str.length - 10);
|
||||
return prefix + maskedChars + suffix;
|
||||
}
|
||||
// 自定义掩码规则
|
||||
function maskCustom(str) {
|
||||
let prefixLength = 0,
|
||||
suffixLength = 0;
|
||||
if (config.prefixType === 2) prefixLength = config.prefixLimit || 0;
|
||||
if ((config.prefixType === 3 || config.prefixType === 4) && config.prefixSpecifyChar) {
|
||||
let specifyCharIndex = str.indexOf(config.prefixSpecifyChar);
|
||||
if (specifyCharIndex > -1) prefixLength = config.prefixType === 3 ? specifyCharIndex :
|
||||
specifyCharIndex + config.prefixSpecifyChar.length;
|
||||
}
|
||||
if (config.suffixType === 2) suffixLength = config.suffixLimit || 0;
|
||||
if ((config.suffixType === 3 || config.suffixType === 4) && config.suffixSpecifyChar) {
|
||||
let specifyCharIndex = str.indexOf(config.suffixSpecifyChar);
|
||||
if (specifyCharIndex > -1) suffixLength = config.suffixType === 3 ?
|
||||
str.length - specifyCharIndex - config.suffixSpecifyChar.length :
|
||||
str.length - specifyCharIndex;
|
||||
}
|
||||
if (prefixLength + suffixLength >= str.length) return str;
|
||||
const prefix = prefixLength ? str.slice(0, prefixLength) : '';
|
||||
const suffix = suffixLength ? str.slice(-suffixLength) : '';
|
||||
let middleChar = '';
|
||||
if (!config.ignoreChar) {
|
||||
const maskedLength = config.useUnrealMask ? config.unrealMaskLength || 1 : str.length - prefixLength -
|
||||
suffixLength;
|
||||
middleChar = config.filler.repeat(maskedLength);
|
||||
} else {
|
||||
const ignoreCharList = config.ignoreChar.split(',');
|
||||
const middleStr = str.slice(prefixLength, str.length - suffixLength);
|
||||
const reg = new RegExp('(' + ignoreCharList.map(o => o.replace(/\*/g, '\\*')).join('|') + ')', 'g');
|
||||
let list = middleStr.split(reg);
|
||||
list = list.map(o => {
|
||||
if (o && !ignoreCharList.includes(o)) {
|
||||
const maskedLength = config.useUnrealMask ? config.unrealMaskLength || 1 : o.length;
|
||||
o = config.filler.repeat(maskedLength);
|
||||
}
|
||||
return o;
|
||||
});
|
||||
middleChar = list.join('');
|
||||
}
|
||||
|
||||
return prefix + middleChar + suffix;
|
||||
}
|
||||
|
||||
// 获取掩码后文本
|
||||
function getMaskedText(str) {
|
||||
if (!str) return '';
|
||||
if (config.maskType === 1) return maskAll(str);
|
||||
if (config.maskType === 2) return maskName(str);
|
||||
if (config.maskType === 3) return maskPhoneNumber(str);
|
||||
if (config.maskType === 4) return maskEmailAddress(str);
|
||||
if (config.maskType === 5) return maskIdNumber(str);
|
||||
if (config.maskType === 6) return maskIPAddress(str);
|
||||
if (config.maskType === 7) return maskLicensePlate(str);
|
||||
if (config.maskType === 8) return maskBankCard(str);
|
||||
if (config.maskType === 0) return maskCustom(str);
|
||||
return str;
|
||||
}
|
||||
|
||||
return {
|
||||
maskAll,
|
||||
maskName,
|
||||
maskPhoneNumber,
|
||||
maskEmailAddress,
|
||||
maskIdNumber,
|
||||
maskIPAddress,
|
||||
maskLicensePlate,
|
||||
maskBankCard,
|
||||
maskCustom,
|
||||
getMaskedText
|
||||
};
|
||||
}
|
||||
240
components/yunzhupaas/InputNumber/index.vue
Normal file
240
components/yunzhupaas/InputNumber/index.vue
Normal file
@@ -0,0 +1,240 @@
|
||||
<template>
|
||||
<view class="yunzhupaas-input-number">
|
||||
<!-- 数字输入 -->
|
||||
<view v-if="!detailed">
|
||||
<u-number-box v-if="controls" v-model="innerValue" :step="step" :min="min" :max="max" :key="key"
|
||||
:disabled="disabled" :positive-integer="false" :input-height="60" @blur="onNumberBlur"
|
||||
@change="onChange" />
|
||||
<view v-else class="input-content" :class="{'input-border':addonBefore||addonAfter}">
|
||||
<view class="input-left u-line-1" v-if="addonBefore">{{addonBefore}}</view>
|
||||
<view class="input-center">
|
||||
<u-input v-model="innerValue" :placeholder="placeholder"
|
||||
:input-align='addonBefore || addonAfter? "center":"right"' :disabled="disabled"
|
||||
:clearable="false" @focus="onFocus" @blur="onBlur" @input="onInputChange">
|
||||
</u-input>
|
||||
</view>
|
||||
<view class="input-right u-line-1" v-if="addonAfter">{{addonAfter}}</view>
|
||||
</view>
|
||||
</view>
|
||||
<!-- 详情 -->
|
||||
<view v-else>
|
||||
<view class="detail-content u-flex">
|
||||
<view class="detail-left u-line-1" v-if="addonBefore&&!controls">{{addonBefore}}</view>
|
||||
<view class="detail-center">{{thousands?yunzhupaas.thousandsFormat(innerValue) :innerValue}}</view>
|
||||
<view class="detail-right u-line-1" v-if="addonAfter&&!controls">{{addonAfter}}</view>
|
||||
</view>
|
||||
</view>
|
||||
<!-- 大写金额 -->
|
||||
<view class="amount-chinese-name" v-if="isAmountChinese&&getChineseName">{{getChineseName}}</view>
|
||||
</view>
|
||||
|
||||
</template>
|
||||
<script>
|
||||
/**
|
||||
* inputNumber 数字输入框
|
||||
* @modelValue v-model
|
||||
* @min {Number} 最小值
|
||||
* @max {Number} 最大值
|
||||
* @step {Number} 每次点击改变的间隔大小
|
||||
* @placeholder {String} 占位符
|
||||
* @addonBefore {String} 前缀
|
||||
* @addonAfter {String} 后缀
|
||||
* @thousands {Boolean} 金额千位符
|
||||
* @isAmountChinese {Boolean} 金额大写
|
||||
* @detailed {Boolean} 详情
|
||||
*/
|
||||
|
||||
export default {
|
||||
name: 'yunzhupaas-input-number',
|
||||
props: {
|
||||
modelValue: {
|
||||
type: [Number, String],
|
||||
default: ''
|
||||
},
|
||||
min: {
|
||||
type: Number,
|
||||
default: -999999999999999
|
||||
},
|
||||
max: {
|
||||
type: Number,
|
||||
default: 999999999999999
|
||||
},
|
||||
step: {
|
||||
type: Number,
|
||||
default: 1
|
||||
},
|
||||
disabled: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
addonBefore: {
|
||||
default: ''
|
||||
},
|
||||
addonAfter: {
|
||||
default: ''
|
||||
},
|
||||
precision: {
|
||||
type: Number
|
||||
},
|
||||
controls: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
thousands: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
isAmountChinese: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
detailed: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
type: {
|
||||
default: ''
|
||||
},
|
||||
placeholder: {
|
||||
default: '请输入'
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
innerValue: null,
|
||||
key: +new Date()
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
modelValue: {
|
||||
handler(val) {
|
||||
this.setValue(val)
|
||||
},
|
||||
immediate: true
|
||||
},
|
||||
getChineseName(val) {
|
||||
uni.$emit('initCollapse')
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
getChineseName() {
|
||||
if (!this.isAmountChinese || (!this.getNumberValue && this.getNumberValue !== 0)) return ""
|
||||
return this.yunzhupaas.getAmountChinese(this.getNumberValue)
|
||||
},
|
||||
getNumberValue() {
|
||||
return this.handleConvertNum(this.innerValue)
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
setValue(val) {
|
||||
this.innerValue = (!val && val !== 0) || isNaN(val) ? null : Number(val);
|
||||
if (!this.innerValue && this.innerValue !== 0) return
|
||||
if (this.innerValue < this.min) this.innerValue = this.min
|
||||
if (this.innerValue > this.max) this.innerValue = this.max
|
||||
if (!isNaN(this.precision)) {
|
||||
const value = Number(this.getNumberValue).toFixed(this.precision)
|
||||
this.innerValue = this.controls ? Number(value) : value
|
||||
}
|
||||
if (this.thousands) this.innerValue = this.yunzhupaas.thousandsFormat(this.innerValue)
|
||||
},
|
||||
onChange() {
|
||||
this.setValue(this.innerValue)
|
||||
this.$nextTick(() => {
|
||||
this.$emit('update:modelValue', this.innerValue)
|
||||
this.$emit('change', this.innerValue)
|
||||
})
|
||||
},
|
||||
onInputChange() {
|
||||
this.$nextTick(() => {
|
||||
this.$emit('change', this.innerValue)
|
||||
})
|
||||
},
|
||||
onNumberBlur() {
|
||||
this.key = +new Date()
|
||||
this.setValue(this.innerValue)
|
||||
this.$emit('blur', this.innerValue)
|
||||
},
|
||||
onBlur(val) {
|
||||
this.setValue(this.getNumberValue)
|
||||
this.$emit('blur', this.getNumberValue)
|
||||
this.$emit('update:modelValue', this.getNumberValue)
|
||||
},
|
||||
onFocus() {
|
||||
if (!this.innerValue) return
|
||||
if (this.innerValue.toString().indexOf('e+') > -1) return
|
||||
this.innerValue = !isNaN(this.precision) ? Number(this.getNumberValue).toFixed(this.precision) : this
|
||||
.getNumberValue
|
||||
},
|
||||
handleConvertNum(val) {
|
||||
if (!val && val !== 0) return null
|
||||
let num = this.$u.deepClone(val.toString().split("."))
|
||||
const arr2 = num.length > 1 ? num[1].split("").filter(o => (!isNaN(o))).join('') : []
|
||||
let arr = num[0].split("").filter(o => (!isNaN(o))).join('');
|
||||
let res = num[1] ? arr + '.' + arr2 : Number(arr)
|
||||
return val.toString().indexOf('-') != -1 ? Number('-' + res) : res
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.yunzhupaas-input-number {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: flex-end;
|
||||
|
||||
:deep(.u-number-input) {
|
||||
width: 150rpx !important;
|
||||
}
|
||||
|
||||
.input-content {
|
||||
display: flex;
|
||||
border-radius: 10rpx;
|
||||
height: 74rpx;
|
||||
|
||||
&.input-border {
|
||||
border: 1rpx solid rgb(220, 223, 230)
|
||||
}
|
||||
|
||||
.input-left,
|
||||
.input-right {
|
||||
flex-shrink: 0;
|
||||
width: 128rpx;
|
||||
background-color: #f5f7fa;
|
||||
color: #909399;
|
||||
padding: 0 10rpx;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.input-left {
|
||||
border-right: 1rpx solid #dcdfe6;
|
||||
border-radius: 10rpx 0 0 10rpx;
|
||||
}
|
||||
|
||||
.input-right {
|
||||
border-left: 1rpx solid #dcdfe6;
|
||||
border-radius: 0px 10px 10px 0px;
|
||||
}
|
||||
}
|
||||
|
||||
.detail-content {
|
||||
.detail-left {
|
||||
max-width: 128rpx;
|
||||
padding-right: 16rpx;
|
||||
color: #909399;
|
||||
}
|
||||
|
||||
.detail-right {
|
||||
max-width: 128rpx;
|
||||
padding-left: 16rpx;
|
||||
color: #909399;
|
||||
}
|
||||
}
|
||||
|
||||
.amount-chinese-name {
|
||||
color: #999999;
|
||||
line-height: 40rpx;
|
||||
padding: 10rpx 10rpx 0 0;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
62
components/yunzhupaas/Link/index.vue
Normal file
62
components/yunzhupaas/Link/index.vue
Normal file
@@ -0,0 +1,62 @@
|
||||
<template>
|
||||
<view class="yunzhupaas-link" :style="textStyle" @click="handleClick()">
|
||||
<text>{{content}}</text>
|
||||
</view>
|
||||
</template>
|
||||
<script>
|
||||
export default {
|
||||
name: 'yunzhupaas-link',
|
||||
props: {
|
||||
content: {
|
||||
type: String,
|
||||
default: '文本链接'
|
||||
},
|
||||
href: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
target: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
textStyle: {
|
||||
type: Object,
|
||||
default: {}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
handleClick(event) {
|
||||
if (!this.href) return this.$u.toast("未配置跳转链接")
|
||||
if (this.target === '_self') {
|
||||
uni.navigateTo({
|
||||
url: '/pages/apply/externalLink/index?url=' + this.href,
|
||||
fail: (err) => {
|
||||
this.$u.toast("暂无此页面")
|
||||
}
|
||||
})
|
||||
} else {
|
||||
// #ifdef APP
|
||||
plus.runtime.getProperty(plus.runtime.appid, (wgtinfo) => {
|
||||
plus.runtime.openURL(this.href)
|
||||
})
|
||||
// #endif
|
||||
// #ifndef APP
|
||||
uni.navigateTo({
|
||||
url: '/pages/apply/externalLink/index?url=' + this.href,
|
||||
fail: (err) => {
|
||||
this.$u.toast("暂无此页面")
|
||||
}
|
||||
})
|
||||
// #endif
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.yunzhupaas-link {
|
||||
width: 100%;
|
||||
color: #1890ff;
|
||||
text-align: right;
|
||||
}
|
||||
</style>
|
||||
259
components/yunzhupaas/Location/index.vue
Normal file
259
components/yunzhupaas/Location/index.vue
Normal file
@@ -0,0 +1,259 @@
|
||||
<template>
|
||||
<view class="yunzhupaas-location">
|
||||
<u-button class="yunzhupaas-location-btn" @click="handleLocation" v-if="!detailed" size="mini">
|
||||
<u-icon class="yunzhupaas-location-icon" name="map" />
|
||||
{{ innerValue.fullAddress ||errTitle ? $t('app.apply.location.relocation') : $t('app.apply.location.location') }}
|
||||
</u-button>
|
||||
<view class="location-card" v-if="innerValue.fullAddress">
|
||||
<view class="location-card-info" @click="getLocation">
|
||||
<image class="location-card-static-map" :src="staticMapUrl" v-if="enableLocationScope" />
|
||||
<view class="location-card-address">{{ innerValue.fullAddress }}</view>
|
||||
<u-icon name="close-circle-fill" v-if="!detailed && !disabled && clearable" @click="handleClear" />
|
||||
</view>
|
||||
</view>
|
||||
<view v-if="errTitle" class="errTitle">{{errTitle}}</view>
|
||||
</view>
|
||||
</template>
|
||||
<script>
|
||||
import {
|
||||
getAddress
|
||||
} from '@/api/common.js'
|
||||
const defaultValue = {
|
||||
lat: '',
|
||||
lng: '',
|
||||
name: '',
|
||||
fullAddress: '',
|
||||
};
|
||||
export default {
|
||||
name: 'yunzhupaas-location',
|
||||
props: {
|
||||
modelValue: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
autoLocation: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
enableLocationScope: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
adjustmentScope: {
|
||||
type: Number,
|
||||
default: 500
|
||||
},
|
||||
enableDesktopLocation: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
locationScope: {
|
||||
type: Array,
|
||||
default: []
|
||||
},
|
||||
disabled: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
detailed: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
clearable: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
innerValue: '',
|
||||
errTitle: '',
|
||||
emitKey: ''
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
modelValue: {
|
||||
handler(val) {
|
||||
this.innerValue = val ? JSON.parse(val) : defaultValue
|
||||
},
|
||||
immediate: true,
|
||||
},
|
||||
},
|
||||
computed: {
|
||||
staticMapUrl() {
|
||||
if (!this.enableLocationScope) return ' ';
|
||||
const location = this.innerValue.lng + ',' + this.innerValue.lat;
|
||||
const url =
|
||||
`${this.define.baseURL}/api/system/Location/staticmap?location=${location}&zoom=19&size=80*80&key=${this.define.aMapWebKey}`;
|
||||
return url;
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.errTitle = ''
|
||||
this.handleAutoLocation()
|
||||
this.handleListen()
|
||||
},
|
||||
methods: {
|
||||
handleListen() {
|
||||
this.emitKey = 'location' + this.yunzhupaas.idGenerator()
|
||||
uni.$on(this.emitKey, data => {
|
||||
this.handleConfirm(data)
|
||||
})
|
||||
},
|
||||
handleLocation(val) {
|
||||
if (this.disabled || this.detailed) return
|
||||
const data = {
|
||||
adjustmentScope: this.adjustmentScope,
|
||||
enableLocationScope: this.enableLocationScope,
|
||||
enableDesktopLocation: this.enableDesktopLocation,
|
||||
locationScope: this.locationScope,
|
||||
emitKey: this.emitKey
|
||||
}
|
||||
uni.navigateTo({
|
||||
url: '/pages/apply/location/index?data=' + JSON.stringify(data)
|
||||
})
|
||||
},
|
||||
handleAutoLocation() {
|
||||
if (!this.autoLocation || this.innerValue.fullAddress || this.detailed) return;
|
||||
uni.getLocation({
|
||||
type: 'gcj02',
|
||||
isHighAccuracy: true,
|
||||
success: (e) => {
|
||||
const getAddressFun = () => {
|
||||
const query = {
|
||||
location: e.longitude + ',' + e.latitude,
|
||||
key: this.define.aMapWebKey
|
||||
}
|
||||
getAddress(query).then(res => {
|
||||
const data = res.data.regeocode.addressComponent;
|
||||
this.innerValue = {
|
||||
pName: data.province,
|
||||
cName: data.city,
|
||||
adName: data.district,
|
||||
address: data.streetNumber.street + data.streetNumber
|
||||
.number,
|
||||
name: res.data.regeocode.formatted_address,
|
||||
lng: e.longitude,
|
||||
lat: e.latitude,
|
||||
fullAddress: res.data.regeocode.formatted_address,
|
||||
};
|
||||
this.$emit('update:modelValue', JSON.stringify(this.innerValue));
|
||||
this.$emit('change', JSON.stringify(this.innerValue));
|
||||
}).catch(() => {
|
||||
this.handelError()
|
||||
})
|
||||
}
|
||||
if (this.enableDesktopLocation && this.locationScope.length) {
|
||||
let list = [];
|
||||
for (let i = 0; i < this.locationScope.length; i++) {
|
||||
const o = this.locationScope[i];
|
||||
const discount = this.yunzhupaas.getDistance(o.lat, o.lng, e.latitude, e
|
||||
.longitude) || 0;
|
||||
list.push(discount > o.radius);
|
||||
}
|
||||
if (list.every(o => o === true)) return;
|
||||
getAddressFun()
|
||||
} else {
|
||||
getAddressFun()
|
||||
}
|
||||
|
||||
},
|
||||
fail: (err) => {
|
||||
this.handelError()
|
||||
}
|
||||
});
|
||||
},
|
||||
handleConfirm(item) {
|
||||
this.innerValue = item ? JSON.parse(item) : defaultValue
|
||||
this.errTitle = ''
|
||||
this.onchange()
|
||||
},
|
||||
handelError() {
|
||||
this.errTitle = '定位失败,请检查网络畅通、定位开启后重试'
|
||||
},
|
||||
handleClear() {
|
||||
this.innerValue = defaultValue;
|
||||
this.$emit('update:modelValue', '');
|
||||
this.$emit('change', '');
|
||||
},
|
||||
onchange() {
|
||||
let innerValue = this.$u.deepClone(this.innerValue)
|
||||
this.$emit('update:modelValue', JSON.stringify(innerValue))
|
||||
this.$emit('change', JSON.stringify(innerValue))
|
||||
},
|
||||
openMap() {
|
||||
uni.openLocation({
|
||||
latitude: Number(this.innerValue.lat),
|
||||
longitude: Number(this.innerValue.lng),
|
||||
name: this.innerValue.name,
|
||||
address: this.innerValue.address,
|
||||
success: () => {},
|
||||
fail: function(error) {
|
||||
console.log(error)
|
||||
}
|
||||
});
|
||||
},
|
||||
getLocation() {
|
||||
if (this.detailed) return this.openMap()
|
||||
if (this.enableLocationScope) this.handleLocation()
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style lang="scss">
|
||||
.yunzhupaas-location {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
justify-content: flex-end;
|
||||
|
||||
.yunzhupaas-location-btn {
|
||||
margin: unset;
|
||||
|
||||
.yunzhupaas-location-icon {
|
||||
font-size: 28rpx;
|
||||
padding-right: 2px;
|
||||
}
|
||||
}
|
||||
|
||||
.location-card {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-top: 16rpx;
|
||||
background: #f2f2f6;
|
||||
padding: 16rpx;
|
||||
border-radius: 16rpx;
|
||||
justify-content: space-between;
|
||||
|
||||
.location-card-info {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
.location-card-static-map {
|
||||
width: 96rpx;
|
||||
height: 96rpx;
|
||||
margin-right: 8rpx;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.location-card-address {
|
||||
line-height: 1.5;
|
||||
padding: 0 8rpx;
|
||||
word-break: normal;
|
||||
white-space: normal;
|
||||
}
|
||||
}
|
||||
|
||||
.location-card-actions {
|
||||
color: rgb(135, 143, 149);
|
||||
cursor: pointer;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.errTitle {
|
||||
color: $u-type-error
|
||||
}
|
||||
}
|
||||
</style>
|
||||
76
components/yunzhupaas/NumberRange/index.vue
Normal file
76
components/yunzhupaas/NumberRange/index.vue
Normal file
@@ -0,0 +1,76 @@
|
||||
<template>
|
||||
<view class="yunzhupaas-num-range">
|
||||
<u-input input-align='right' v-model="min" :placeholder="$t('component.yunzhupaas.numberRange.min')" type="number" @blur="onblur($event,'min')" />
|
||||
<text class="separator">-</text>
|
||||
<u-input input-align='right' v-model="max" :placeholder="$t('component.yunzhupaas.numberRange.max')" type="number" @blur="onblur($event,'max')" />
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'yunzhupaas-number-range',
|
||||
props: {
|
||||
modelValue: {
|
||||
type: Array,
|
||||
default: () => []
|
||||
},
|
||||
disabled: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
precision: {
|
||||
type: Number,
|
||||
default: undefined
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
min: '',
|
||||
max: ''
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
modelValue: {
|
||||
handler(val) {
|
||||
if (Array.isArray(val) && val.length === 2) {
|
||||
this.min = val[0]
|
||||
this.max = val[1]
|
||||
} else {
|
||||
this.min = ''
|
||||
this.max = ''
|
||||
}
|
||||
},
|
||||
immediate: true,
|
||||
},
|
||||
min(val) {
|
||||
this.onChange()
|
||||
},
|
||||
max(val) {
|
||||
this.onChange()
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
onblur(e, type) {
|
||||
this[type] = !isNaN(this.precision) && (e == '0' || e) ? Number(e).toFixed(this.precision) : e
|
||||
},
|
||||
onChange() {
|
||||
if ((!this.min && this.min !== 0) && (!this.max && this.max !== 0)) return this.$emit('update:modelValue',
|
||||
[])
|
||||
this.$emit('update:modelValue', [this.min, this.max])
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.yunzhupaas-num-range {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
|
||||
.separator {
|
||||
margin: 0 20rpx;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
61
components/yunzhupaas/OpenData/index.vue
Normal file
61
components/yunzhupaas/OpenData/index.vue
Normal file
@@ -0,0 +1,61 @@
|
||||
<template>
|
||||
<u-input input-align='right' :modelValue="modelValue" placeholder="系统自动生成" disabled />
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'yunzhupaas-open-data',
|
||||
props: {
|
||||
modelValue: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
/**
|
||||
* currUser - 当前用户
|
||||
* currTime - 当前时间
|
||||
* currOrganize - 所属组织
|
||||
* currPosition - 所属岗位
|
||||
*/
|
||||
type: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
showLevel: {
|
||||
type: String,
|
||||
default: 'last'
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
innerValue: '',
|
||||
userInfo: ''
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
showLevel() {
|
||||
this.setDefault()
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.userInfo = uni.getStorageSync('userInfo') || {}
|
||||
this.setDefault()
|
||||
},
|
||||
methods: {
|
||||
setDefault() {
|
||||
if (this.type === 'currUser') {
|
||||
this.innerValue = this.userInfo.userName + '/' + this.userInfo.userAccount
|
||||
if (!this.userInfo.userName && !this.userInfo.userAccount) this.innerValue = ""
|
||||
}
|
||||
if (this.type === 'currTime') {
|
||||
this.innerValue = this.$u.timeFormat(new Date(), 'yyyy-mm-dd hh:MM:ss')
|
||||
}
|
||||
if (this.type === 'currOrganize') {
|
||||
this.innerValue = this.showLevel === 'last' ? this.userInfo.departmentName : this.userInfo.organizeName
|
||||
}
|
||||
if (this.type === 'currPosition') {
|
||||
this.innerValue = this.userInfo.positionName || ""
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
211
components/yunzhupaas/OrganizeSelect/Tree.vue
Normal file
211
components/yunzhupaas/OrganizeSelect/Tree.vue
Normal file
@@ -0,0 +1,211 @@
|
||||
<template>
|
||||
<u-popup class="yunzhupaas-tree-select-popup" mode="right" v-model="showPopup" width="100%" @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">
|
||||
<u-search :placeholder="$t('app.apply.pleaseKeyword')" v-model="keyword" height="72"
|
||||
:show-action="false" @change="handleSearch" 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 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 v-if="selectType !== 'all'" :tree-data="options" :node-key="realProps.value"
|
||||
default-expand-all :props="realProps" :filter-node-method="filterNode"
|
||||
child-visible-for-filter-node @node-click="handleNodeClick" ref="tree">
|
||||
</ly-tree>
|
||||
<ly-tree ref="tree" v-if="selectType === 'all'" :props="realProps" :node-key="realProps.value"
|
||||
:load="loadNode" lazy :tree-data="lazyOptions" show-node-icon :defaultExpandAll='false'
|
||||
@node-click="handleNodeClick" />
|
||||
</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'
|
||||
}
|
||||
import {
|
||||
getOrgByOrganizeCondition,
|
||||
selectAsyncList
|
||||
} from '@/api/common.js'
|
||||
export default {
|
||||
props: {
|
||||
options: {
|
||||
type: Array,
|
||||
default () {
|
||||
return [];
|
||||
}
|
||||
},
|
||||
selectedData: {
|
||||
type: Array,
|
||||
default () {
|
||||
return [];
|
||||
}
|
||||
},
|
||||
selectType: {
|
||||
type: String,
|
||||
default: 'all'
|
||||
},
|
||||
ids: {
|
||||
type: [Array, String],
|
||||
default () {
|
||||
return [];
|
||||
}
|
||||
},
|
||||
// 通过双向绑定控制组件的弹出与收起
|
||||
modelValue: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
// 弹出的z-index值
|
||||
zIndex: {
|
||||
type: [String, Number],
|
||||
default: 0
|
||||
},
|
||||
props: {
|
||||
type: Object,
|
||||
default: () => ({
|
||||
label: 'fullName',
|
||||
value: 'id',
|
||||
icon: 'icon',
|
||||
children: 'children',
|
||||
isLeaf: 'isLeaf'
|
||||
})
|
||||
},
|
||||
multiple: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
moving: false,
|
||||
selectList: [],
|
||||
selectListId: [],
|
||||
keyword: '',
|
||||
showPopup: false,
|
||||
lazyOptions: [],
|
||||
level: 0
|
||||
};
|
||||
},
|
||||
watch: {
|
||||
// 在select弹起的时候,重新初始化所有数据
|
||||
modelValue: {
|
||||
handler(val) {
|
||||
this.showPopup = val
|
||||
if (val) setTimeout(() => this.init(), 10);
|
||||
},
|
||||
immediate: true
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.init()
|
||||
},
|
||||
computed: {
|
||||
uZIndex() {
|
||||
// 如果用户有传递z-index值,优先使用
|
||||
return this.zIndex ? this.zIndex : this.$u.zIndex.popup;
|
||||
},
|
||||
realProps() {
|
||||
return {
|
||||
...defaultProps,
|
||||
...this.props
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
init() {
|
||||
this.keyword = ""
|
||||
this.selectListId = Array.isArray(this.ids) ? JSON.parse(JSON.stringify(this.ids)) : []
|
||||
this.selectList = JSON.parse(JSON.stringify(this.selectedData))
|
||||
},
|
||||
filterNode(value, data) {
|
||||
if (!value) return true;
|
||||
return data[this.realProps.label].indexOf(value) !== -1;
|
||||
},
|
||||
loadNode(node, resolve) {
|
||||
let id = node.key === null ? 0 : node.key
|
||||
this.level = node.level
|
||||
let data = {
|
||||
keyword: '',
|
||||
currOrgId: 0
|
||||
}
|
||||
selectAsyncList(data, id).then(res => {
|
||||
resolve(res.data?.list)
|
||||
})
|
||||
},
|
||||
selectAsyncList() {
|
||||
let data = {
|
||||
keyword: this.keyword,
|
||||
currOrgId: 0
|
||||
}
|
||||
this.lazyOptions = []
|
||||
selectAsyncList(data, 0).then(res => {
|
||||
this.lazyOptions = res.data.list || []
|
||||
})
|
||||
},
|
||||
handleNodeClick(obj) {
|
||||
let selectList;
|
||||
if (this.multiple) {
|
||||
this.selectList.push(obj.data.organize)
|
||||
this.selectList = [...new Set(this.selectList)];
|
||||
if (obj.data.organizeIds.length) this.selectListId.push(obj.data.organizeIds)
|
||||
this.selectListId = [...new Set(this.selectListId)];
|
||||
this.selectListId = this.selectListId.filter(o => Array.isArray(o))
|
||||
} else {
|
||||
this.selectList = []
|
||||
this.selectList.push(obj.data.organize)
|
||||
this.selectList = [...new Set(this.selectList)];
|
||||
this.selectListId = obj.data.organizeIds
|
||||
}
|
||||
},
|
||||
delSelect(index) {
|
||||
this.selectList.splice(index, 1);
|
||||
this.selectListId.splice(index, 1);
|
||||
},
|
||||
setCheckAll() {
|
||||
this.selectListId = []
|
||||
this.selectList = [];
|
||||
},
|
||||
handleSearch(val) {
|
||||
this.keyword = val
|
||||
if (this.selectType === 'all') return this.$u.debounce(this.selectAsyncList, 600)
|
||||
this.$refs.tree && this.$refs.tree.filter(val)
|
||||
},
|
||||
handleConfirm() {
|
||||
this.$emit('confirm', this.selectList, this.selectListId);
|
||||
this.close();
|
||||
},
|
||||
close() {
|
||||
this.$emit('close', false);
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
148
components/yunzhupaas/OrganizeSelect/index.vue
Normal file
148
components/yunzhupaas/OrganizeSelect/index.vue
Normal file
@@ -0,0 +1,148 @@
|
||||
<template>
|
||||
<view class="yunzhupaas-organize-select">
|
||||
<selectBox v-model="innerValue" :placeholder="placeholder" @openSelect="openSelect" :select-open="selectShow">
|
||||
</selectBox>
|
||||
<Tree v-model="selectShow" :multiple="multiple" :props="props" :selectedData="selectedData" :options="options"
|
||||
:ids='multiple?modelValue:[modelValue]' @close="handleClose" @confirm="handleConfirm"
|
||||
:selectType="selectType" />
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import Tree from './Tree';
|
||||
import selectBox from '@/components/selectBox'
|
||||
import {
|
||||
useBaseStore
|
||||
} from '@/store/modules/base'
|
||||
import {
|
||||
getOrgByOrganizeCondition,
|
||||
selectedList
|
||||
} from '@/api/common.js'
|
||||
const baseStore = useBaseStore()
|
||||
export default {
|
||||
name: 'yunzhupaas-organize-select',
|
||||
components: {
|
||||
Tree,
|
||||
selectBox
|
||||
},
|
||||
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
|
||||
},
|
||||
selectType: {
|
||||
type: String,
|
||||
default: 'all'
|
||||
},
|
||||
ableIds: {
|
||||
type: Array,
|
||||
default: () => []
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
selectShow: false,
|
||||
innerValue: '',
|
||||
selectedData: [],
|
||||
allList: [],
|
||||
options: []
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
modelValue: {
|
||||
handler(val) {
|
||||
this.getOptions()
|
||||
},
|
||||
immediate: true
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
async getOptions() {
|
||||
this.options = await baseStore.getDepartmentTree()
|
||||
this.allList = await this.treeToArray()
|
||||
if (this.selectType !== 'all') {
|
||||
const departIds = this.ableIds ? this.ableIds.map(o => o[o.length - 1]) : [];
|
||||
const query = {
|
||||
departIds
|
||||
};
|
||||
await getOrgByOrganizeCondition(query).then(res => {
|
||||
this.options = res.data.list || []
|
||||
})
|
||||
}
|
||||
if (!this.modelValue || !this.modelValue.length) {
|
||||
this.innerValue = ''
|
||||
this.selectedData = [];
|
||||
return
|
||||
}
|
||||
this.setDefault()
|
||||
},
|
||||
setDefault() {
|
||||
let val = this.multiple ? this.modelValue : [this.modelValue];
|
||||
let textList = []
|
||||
for (let i = 0; i < val.length; i++) {
|
||||
let item = val[i];
|
||||
inner: for (let j = 0; j < this.allList.length; j++) {
|
||||
if (item.toString() === this.allList[j].organizeIds.toString()) {
|
||||
item = this.allList[j].organize
|
||||
break inner
|
||||
}
|
||||
};
|
||||
textList.push(item)
|
||||
}
|
||||
this.selectedData = textList
|
||||
this.innerValue = this.selectedData.join(',')
|
||||
},
|
||||
async treeToArray() {
|
||||
let options = JSON.parse(JSON.stringify(this.options))
|
||||
let list = []
|
||||
const loop = (options) => {
|
||||
for (let i = 0; i < options.length; i++) {
|
||||
const item = options[i]
|
||||
list.push(item)
|
||||
if (item.hasChildren && item.children && Array.isArray(item.children)) {
|
||||
loop(item.children)
|
||||
}
|
||||
}
|
||||
}
|
||||
loop(options)
|
||||
return list
|
||||
},
|
||||
openSelect() {
|
||||
if (this.disabled) return
|
||||
this.selectShow = true
|
||||
},
|
||||
handleConfirm(e, selectId) {
|
||||
this.$emit('update:modelValue', selectId)
|
||||
this.$emit('change', selectId, e)
|
||||
},
|
||||
handleClose() {
|
||||
this.selectShow = false
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.yunzhupaas-organize-select {
|
||||
width: 100%;
|
||||
}
|
||||
</style>
|
||||
447
components/yunzhupaas/Parser/Item.vue
Normal file
447
components/yunzhupaas/Parser/Item.vue
Normal file
@@ -0,0 +1,447 @@
|
||||
<template>
|
||||
<YunzhupaasText v-if="config.yunzhupaasKey=='text'" :content="item.content" :textStyle="item.textStyle" />
|
||||
<YunzhupaasGroupTitle v-else-if="config.yunzhupaasKey=='groupTitle'" :content="item.content"
|
||||
:content-position="item.contentPosition" :helpMessage="item.helpMessage" @groupIcon="clickIcon(item)" />
|
||||
<YunzhupaasDivider v-else-if="config.yunzhupaasKey=='divider'" :content="item.content" />
|
||||
<view class="yunzhupaas-card" v-else-if="config.yunzhupaasKey==='card'||config.yunzhupaasKey==='row'">
|
||||
<view class="yunzhupaas-card-cap u-line-1 u-flex" v-if="item.header" @click="clickIcon(item)">
|
||||
{{item.header}}
|
||||
<u-icon :name="config.tipLabel? 'question-circle-fill':''" class="u-m-l-10" color="#a0acb7" />
|
||||
</view>
|
||||
<template v-for="(child, index) in config.children" :key="child.__config__.renderKey">
|
||||
<item v-if="!child.__config__.noShow&& child.__config__.isVisibility" :itemData="child"
|
||||
:ref="child.__vModel__?child.__vModel__: 'ref'+item.__config__.formId" :formConf="formConf"
|
||||
:formData="formData" @input="setValue" @clickIcon='clickIcon' @clickFun="onChildClick"
|
||||
@collapse-change="onChildCollapseChange" @tab-change='onChildTabChange' />
|
||||
</template>
|
||||
</view>
|
||||
<!-- 步骤条 -->
|
||||
<view v-else-if="config.yunzhupaasKey==='steps'">
|
||||
<view class="step-container">
|
||||
<u-steps :list="config.children" :mode="item.simple ? 'dot' :'number'" name="title"
|
||||
@change="onStepChange($event,item)" :current="stepCurrent">
|
||||
</u-steps>
|
||||
</view>
|
||||
<view v-for="(it,i) in config.children" :key='i'>
|
||||
<view v-show="i == stepCurrent">
|
||||
<template v-for="(child, index) in it.__config__.children" :key="child.__config__.renderKey">
|
||||
<item v-if="!child.__config__.noShow&& child.__config__.isVisibility" :itemData="child"
|
||||
:formConf="formConf" :formData="formData"
|
||||
:ref="child.__vModel__?child.__vModel__: 'ref'+item.__config__.formId" @input="setValue"
|
||||
@clickIcon='clickIcon' @clickFun="onChildClick" @collapse-change="onChildCollapseChange" />
|
||||
</template>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="yunzhupaas-tab" v-else-if="config.yunzhupaasKey==='tab'">
|
||||
<u-tabs is-scroll :list="config.children" name="title" v-model="tabCurrent" @change="onTabChange"
|
||||
:key="tabKey" />
|
||||
<view v-for="(it,i) in config.children" :key='i'>
|
||||
<view v-show="i == tabCurrent">
|
||||
<template v-for="(child, index) in it.__config__.children" :key="child.__config__.renderKey">
|
||||
<item v-if="!child.__config__.noShow&& child.__config__.isVisibility" :itemData="child"
|
||||
:formConf="formConf" :formData="formData"
|
||||
:ref="child.__vModel__?child.__vModel__: 'ref'+item.__config__.formId" @input="setValue"
|
||||
@clickIcon='clickIcon' @clickFun="onChildClick" @collapse-change="onChildCollapseChange"
|
||||
@tab-change='onChildTabChange' />
|
||||
</template>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view v-else-if="config.yunzhupaasKey==='collapse'">
|
||||
<u-collapse ref="collapseRef" :head-style="{'padding-left':'20rpx'}" :accordion="item.accordion">
|
||||
<u-collapse-item v-for="(it, i) in config.children" :key="i" :title="it.title"
|
||||
:open="config.active.indexOf(it.name)>-1" @change="onCollapseChange">
|
||||
<template v-for="(child, index) in it.__config__.children" :key="child.__config__.renderKey">
|
||||
<item v-if="!child.__config__.noShow&& child.__config__.isVisibility" :itemData="child"
|
||||
:formConf="formConf" :formData="formData"
|
||||
:ref="child.__vModel__?child.__vModel__: 'ref'+item.__config__.formId" @input="setValue"
|
||||
@clickIcon='clickIcon' @clickFun="onChildClick" @collapse-change="onChildCollapseChange"
|
||||
@tab-change='onChildTabChange' />
|
||||
</template>
|
||||
</u-collapse-item>
|
||||
</u-collapse>
|
||||
</view>
|
||||
<view v-else-if="config.yunzhupaasKey==='table'">
|
||||
<child-table v-if="config.isVisibility" v-model="value" :config="item" :ref="item.__vModel__"
|
||||
:formData='formData' @input="setValue" />
|
||||
</view>
|
||||
<u-form-item v-else-if="config.yunzhupaasKey=='popupSelect' || config.yunzhupaasKey=='relationForm'" :label=" realLabel"
|
||||
class="popup-select" :prop="item.__vModel__" :required="config.required" :label-width="labelWidth"
|
||||
:left-icon="leftIcon" :left-icon-style="{'color':'#a8aaaf'}" @clickIcon="clickIcon(item)">
|
||||
<!-- 弹窗选择 -->
|
||||
<YunzhupaasPopupSelect v-if="config.yunzhupaasKey=='popupSelect'" v-model="value" :placeholder="item.placeholder"
|
||||
:disabled="item.disabled" :interfaceId="item.interfaceId" :formData="formData"
|
||||
:templateJson="item.templateJson" :columnOptions="item.columnOptions" :extraOptions="item.extraOptions"
|
||||
:relationField="item.relationField" :propsValue="item.propsValue" :hasPage="item.hasPage"
|
||||
:pageSize="item.pageSize"
|
||||
:vModel="config.tableName ? item.__vModel__ + '_yunzhupaasTable_' + config.tableName + (config.isSubTable ? '0' : '1') : config.__vModel__"
|
||||
:popupTitle="item.popupTitle" @change="onChange" />
|
||||
<!-- 关联表单 -->
|
||||
<YunzhupaasRelationForm v-if="config.yunzhupaasKey=='relationForm'" v-model="value" :placeholder="item.placeholder"
|
||||
:disabled="item.disabled" :modelId="item.modelId" :columnOptions="item.columnOptions"
|
||||
:extraOptions="item.extraOptions" :relationField="item.relationField" :hasPage="item.hasPage"
|
||||
:pageSize="item.pageSize" :queryType="item.queryType"
|
||||
:vModel="config.tableName ? item.__vModel__ + '_yunzhupaasTable_' + config.tableName + (config.isSubTable ? '0' : '1') : item.__vModel__"
|
||||
:popupTitle="item.popupTitle" @change="onChange" :propsValue="item.propsValue" />
|
||||
</u-form-item>
|
||||
<u-form-item v-else :label=" realLabel" :prop="item.__vModel__" :required="config.required"
|
||||
:label-width="labelWidth" :left-icon="leftIcon" :left-icon-style="{'color':'#a8aaaf'}"
|
||||
@clickIcon="clickIcon(item)">
|
||||
<YunzhupaasInput v-if="config.yunzhupaasKey=='input'" v-model="value" :showPassword="item.showPassword"
|
||||
:placeholder="item.placeholder" :maxlength="item.maxlength" :showCount="item.showCount"
|
||||
:disabled="item.disabled" :clearable='item.clearable' :useScan="item.useScan"
|
||||
:addonBefore="item.addonBefore" :addonAfter="item.addonAfter" @change="onChange" @blur="onBlur" />
|
||||
<YunzhupaasTextarea v-if="config.yunzhupaasKey=='textarea'" v-model="value" :placeholder="item.placeholder"
|
||||
:maxlength="item.maxlength" :showCount="item.showCount" :disabled="item.disabled"
|
||||
:clearable='item.clearable' @change="onChange" @blur="onBlur" />
|
||||
<!--数字输入步进器-->
|
||||
<YunzhupaasInputNumber v-if="config.yunzhupaasKey=='inputNumber'" v-model="value" :step='item.step'
|
||||
:max='item.max||999999999999999' :min='item.min||-999999999999999' :disabled="item.disabled"
|
||||
:placeholder="item.placeholder" :isAmountChinese="item.isAmountChinese" :thousands="item.thousands"
|
||||
:addonAfter="item.addonAfter" :addonBefore="item.addonBefore" :controls="item.controls"
|
||||
:precision="item.precision" @change="onChange" @blur="onBlur" />
|
||||
<!-- 开关-->
|
||||
<YunzhupaasSwitch v-if="config.yunzhupaasKey=='switch'" v-model="value" :disabled="item.disabled" @change="onChange" />
|
||||
<!-- 单选框组 -->
|
||||
<YunzhupaasRadio v-if="config.yunzhupaasKey=='radio'" v-model="value" :options="item.options" :props="item.props"
|
||||
:disabled="item.disabled" :direction='item.direction' @change="onChange" />
|
||||
<!-- 多选框组 -->
|
||||
<YunzhupaasCheckbox v-if="config.yunzhupaasKey=='checkbox'" v-model="value" :options="item.options" :props="item.props"
|
||||
:disabled="item.disabled" :direction='item.direction' @change="onChange" />
|
||||
<!-- 下拉选择 -->
|
||||
<YunzhupaasSelect v-if="config.yunzhupaasKey=='select'" v-model="value" :placeholder="item.placeholder"
|
||||
:options="item.options" :props="item.props" :multiple="item.multiple" :disabled="item.disabled"
|
||||
@change="onChange" :filterable="item.filterable" />
|
||||
<!-- 级联选择 -->
|
||||
<YunzhupaasCascader v-if="config.yunzhupaasKey=='cascader'" v-model="value" :placeholder="item.placeholder"
|
||||
:options="item.options" :props="item.props" :disabled="item.disabled" :multiple="item.multiple"
|
||||
:filterable='item.filterable' :clearable='item.clearable' :showAllLevels="item.showAllLevels"
|
||||
@change="onChange" />
|
||||
<YunzhupaasDatePicker v-if="config.yunzhupaasKey=='datePicker'" v-model="value" :placeholder="item.placeholder"
|
||||
:disabled="item.disabled" :format="item.format" :startTime="item.startTime" :endTime='item.endTime'
|
||||
@change="onChange" />
|
||||
<YunzhupaasTimePicker v-if="config.yunzhupaasKey=='timePicker'" v-model="value" :placeholder="item.placeholder"
|
||||
:disabled="item.disabled" :format="item.format" :startTime="item.startTime" :endTime='item.endTime'
|
||||
@change="onChange" />
|
||||
<!-- #ifndef APP-HARMONY -->
|
||||
<YunzhupaasUploadFile v-if="config.yunzhupaasKey=='uploadFile'" v-model="value" :disabled="item.disabled"
|
||||
:limit="item.limit" :sizeUnit="item.sizeUnit" :fileSize="item.fileSize" :pathType="item.pathType"
|
||||
:isAccount="item.isAccount" :folder="item.folder" :accept="item.accept" :tipText="item.tipText"
|
||||
@change="onChange" :sortRule="item.sortRule" :timeFormat="item.timeFormat" />
|
||||
<!-- #endif -->
|
||||
<!-- 图片上传 -->
|
||||
<YunzhupaasUploadImg v-if="config.yunzhupaasKey=='uploadImg'" v-model="value" :disabled="item.disabled" :limit="item.limit"
|
||||
:sizeUnit="item.sizeUnit" :fileSize="item.fileSize" :pathType="item.pathType" :isAccount="item.isAccount"
|
||||
:folder="item.folder" :tipText="item.tipText" @change="onChange" :sortRule="item.sortRule"
|
||||
:timeFormat="item.timeFormat" />
|
||||
<!-- 颜色选择 -->
|
||||
<YunzhupaasColorPicker v-if="config.yunzhupaasKey=='colorPicker'" v-model="value" :colorFormat="item.colorFormat"
|
||||
:disabled="item.disabled" @change="onChange" />
|
||||
<YunzhupaasRate v-if="config.yunzhupaasKey=='rate'" v-model="value" :max="item.count" :allowHalf="item.allowHalf"
|
||||
:disabled="item.disabled" @change="onChange" />
|
||||
<YunzhupaasSlider v-if="config.yunzhupaasKey=='slider'" v-model="value" :step="item.step" :min="item.min" :max="item.max"
|
||||
:disabled="item.disabled" @change="onChange" />
|
||||
<YunzhupaasBarcode v-if="config.yunzhupaasKey=='barcode'" :staticText="item.staticText" :width="item.width"
|
||||
:height="item.height" :format="item.format" :dataType="item.dataType" :lineColor="item.lineColor"
|
||||
:background="item.background" :relationField="item.relationField" :formData="formData" />
|
||||
<YunzhupaasQrcode v-if="config.yunzhupaasKey=='qrcode'" :staticText="item.staticText" :width="item.width"
|
||||
:dataType="item.dataType" :colorDark="item.colorDark" :colorLight="item.colorLight"
|
||||
:relationField="item.relationField" :formData="formData" />
|
||||
<YunzhupaasOrganizeSelect v-if="config.yunzhupaasKey=='organizeSelect'" v-model="value" :multiple="item.multiple"
|
||||
:placeholder="item.placeholder" :disabled="item.disabled" :ableIds="item.ableIds"
|
||||
:selectType="item.selectType" @change="onChange" />
|
||||
<YunzhupaasDepSelect v-if="config.yunzhupaasKey=='depSelect'" v-model="value" :multiple="item.multiple"
|
||||
:placeholder="item.placeholder" :disabled="item.disabled" :ableIds="item.ableIds"
|
||||
:selectType="item.selectType" @change="onChange" />
|
||||
<YunzhupaasPosSelect v-if="config.yunzhupaasKey=='posSelect'" v-model="value" :multiple="item.multiple"
|
||||
:placeholder="item.placeholder" :disabled="item.disabled" :ableIds="item.ableIds"
|
||||
:selectType="item.selectType" @change="onChange" />
|
||||
<YunzhupaasUserSelect v-if="config.yunzhupaasKey=='userSelect'" v-model="value" :multiple="item.multiple"
|
||||
:placeholder="item.placeholder" :disabled="item.disabled" :selectType="item.selectType"
|
||||
:ableIds="item.ableIds" :clearable="item.clearable" :ableRelationIds="item.ableRelationIds"
|
||||
@change="onChange" />
|
||||
<YunzhupaasUsersSelect v-if="config.yunzhupaasKey=='usersSelect'" v-model="value" :multiple="item.multiple"
|
||||
:placeholder="item.placeholder" :disabled="item.disabled" :selectType="item.selectType"
|
||||
:ableIds="item.ableIds" :clearable="item.clearable" @change="onChange" />
|
||||
<YunzhupaasRoleSelect v-if="config.yunzhupaasKey=='roleSelect'" v-model="value" :vModel='item.__vModel__'
|
||||
:multiple="item.multiple" :disabled="item.disabled" :placeholder="item.placeholder" :ableIds="item.ableIds"
|
||||
:selectType="item.selectType" @change="onChange" />
|
||||
<YunzhupaasGroupSelect v-if="config.yunzhupaasKey=='groupSelect'" v-model="value" :vModel='item.__vModel__'
|
||||
:multiple="item.multiple" :disabled="item.disabled" :ableIds="item.ableIds" :selectType="item.selectType"
|
||||
:placeholder="item.placeholder" @change="onChange" />
|
||||
<!-- 下拉树形 -->
|
||||
<YunzhupaasTreeSelect v-if="config.yunzhupaasKey=='treeSelect'" v-model="value" :options="item.options" :props="item.props"
|
||||
:multiple="item.multiple" :placeholder="item.placeholder" :disabled="item.disabled"
|
||||
:filterable="item.filterable" @change="onChange" />
|
||||
<YunzhupaasAutoComplete v-if="config.yunzhupaasKey=='autoComplete'" v-model="value" :disabled="item.disabled"
|
||||
:interfaceName="item.interfaceName" :placeholder="item.placeholder" :interfaceId="item.interfaceId"
|
||||
:total="item.total" :templateJson="item.templateJson" :formData='formData'
|
||||
:relationField="item.relationField" :propsValue="item.propsValue" :clearable='item.clearable'
|
||||
@change="onChange" />
|
||||
<YunzhupaasAreaSelect v-if="config.yunzhupaasKey=='areaSelect'" v-model="value" :placeholder="item.placeholder"
|
||||
:level="item.level" :disabled="item.disabled" :multiple="item.multiple" @change="onChange" />
|
||||
<YunzhupaasRelationFormAttr v-if="config.yunzhupaasKey=='relationFormAttr'" v-model="value" :showField="item.showField"
|
||||
:relationField="item.relationField" :isStorage='item.isStorage' @change="onChange" />
|
||||
<!-- 下拉表格 -->
|
||||
<YunzhupaasPopupSelect v-if="config.yunzhupaasKey=='popupTableSelect'" v-model="value" :placeholder="item.placeholder"
|
||||
:disabled="item.disabled" :interfaceId="item.interfaceId" :formData="formData"
|
||||
:templateJson="item.templateJson" :columnOptions="item.columnOptions" :relationField="item.relationField"
|
||||
:propsValue="item.propsValue" :hasPage="item.hasPage" :pageSize="item.pageSize"
|
||||
:vModel="config.tableName ? item.__vModel__ + '_yunzhupaasTable_' + config.tableName + (config.isSubTable ? '0' : '1') : config.__vModel__"
|
||||
:popupTitle="item.popupTitle" :multiple="item.multiple" @change="onChange" />
|
||||
<YunzhupaasPopupAttr v-if="config.yunzhupaasKey=='popupAttr'" v-model="value" :showField="item.showField"
|
||||
:relationField="item.relationField" :isStorage='item.isStorage' @change="onChange" />
|
||||
<!-- 计算公式 -->
|
||||
<YunzhupaasCalculate v-if="config.yunzhupaasKey=='calculate'" v-model="value" :expression='item.expression'
|
||||
:vModel='item.__vModel__' :config='item.__config__' :formData='formData' :precision="item.precision"
|
||||
:isAmountChinese="item.isAmountChinese" :thousands="item.thousands" :roundType="item.roundType" />
|
||||
<!-- 签名 -->
|
||||
<YunzhupaasSign v-if="config.yunzhupaasKey=='sign'" v-model="value" :disabled="item.disabled" :fieldKey="item.__vModel__"
|
||||
@change="onChange" :isInvoke="item.isInvoke" />
|
||||
<!-- 签章 -->
|
||||
<YunzhupaasSignature v-if="config.yunzhupaasKey=='signature'" v-model="value" :disabled="item.disabled" @change="onChange"
|
||||
:ableIds="item.ableIds" />
|
||||
<YunzhupaasLocation v-if="config.yunzhupaasKey=='location'" v-model="value" :autoLocation="item.autoLocation"
|
||||
:adjustmentScope="item.adjustmentScope" :enableLocationScope="item.enableLocationScope"
|
||||
:enableDesktopLocation="item.enableDesktopLocation" :locationScope="item.locationScope"
|
||||
:disabled="item.disabled" :clearable='item.clearable' @change="onChange" />
|
||||
<YunzhupaasOpenData v-if="isSystem" v-model="value" :type="item.type" :showLevel="item.showLevel" />
|
||||
<YunzhupaasInput v-if="config.yunzhupaasKey==='modifyUser'||config.yunzhupaasKey==='modifyTime'" v-model="value"
|
||||
placeholder="系统自动生成" disabled />
|
||||
<!--start labelwidth=0-->
|
||||
<YunzhupaasLink v-if="config.yunzhupaasKey=='link'" :content="item.content" :href="item.href" :target='item.target'
|
||||
:textStyle="item.textStyle" @click="onClick" />
|
||||
<!-- 富文本 -->
|
||||
<YunzhupaasEditor v-if="config.yunzhupaasKey=='editor'" v-model="value" :disabled="item.disabled"
|
||||
:placeholder="item.placeholder" />
|
||||
<YunzhupaasButton v-if="config.yunzhupaasKey=='button'" :buttonText="item.buttonText" :align="item.align" :type="item.type"
|
||||
:disabled="item.disabled" @click="onClick($event)" />
|
||||
<YunzhupaasAlert v-if="config.yunzhupaasKey=='alert'" :type="item.type" :title="item.title" :tagIcon='item.tagIcon'
|
||||
:showIcon="item.showIcon" :closable="item.closable" :description="item.description"
|
||||
:closeText="item.closeText" />
|
||||
<!--end labelwidth=0-->
|
||||
</u-form-item>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import childTable from './childTable.vue'
|
||||
// #ifdef MP
|
||||
import Item from './Item.vue' //兼容小程序
|
||||
// #endif
|
||||
const systemList = ['createUser', 'createTime', 'currOrganize', 'currDept', 'currPosition', 'billRule']
|
||||
const specialList = ['link', 'editor', 'button', 'alert']
|
||||
export default {
|
||||
name: 'Item',
|
||||
inject: ["parameter"],
|
||||
emits: ['input', 'clickIcon', 'clickFun', 'collapseChange', 'tab-change'],
|
||||
components: {
|
||||
childTable,
|
||||
// #ifdef MP
|
||||
Item
|
||||
// #endif
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
value: undefined,
|
||||
tabCurrent: 0,
|
||||
stepCurrent: 0,
|
||||
tabKey: +new Date(),
|
||||
extraObj: {}
|
||||
}
|
||||
},
|
||||
props: {
|
||||
itemData: {
|
||||
type: Object,
|
||||
required: true
|
||||
},
|
||||
formConf: {
|
||||
type: Object,
|
||||
required: true
|
||||
},
|
||||
formData: {
|
||||
type: Object,
|
||||
required: true
|
||||
},
|
||||
},
|
||||
computed: {
|
||||
item() {
|
||||
const item = uni.$u.deepClone(this.itemData)
|
||||
this.initI18n(item)
|
||||
return item
|
||||
},
|
||||
config() {
|
||||
return this.item.__config__
|
||||
},
|
||||
isSystem() {
|
||||
return systemList.indexOf(this.config.yunzhupaasKey) > -1
|
||||
},
|
||||
labelWidth() {
|
||||
if (specialList.indexOf(this.config.yunzhupaasKey) > -1) return 0
|
||||
return this.config.labelWidth ? this.config.labelWidth * 1.5 : undefined
|
||||
},
|
||||
label() {
|
||||
return this.config.showLabel && specialList.indexOf(this.config.yunzhupaasKey) < 0 ? this.config.label : ''
|
||||
},
|
||||
realLabel() {
|
||||
return this.label ? (this.label + (this.formConf.labelSuffix || '')) : ''
|
||||
},
|
||||
leftIcon() {
|
||||
return this.config.tipLabel && this.label && this.config.showLabel ? "question-circle-fill" : ""
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
value(val) {
|
||||
this.item.__config__.defaultValue = val
|
||||
this.$emit('input', this.item)
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.initData()
|
||||
},
|
||||
mounted() {
|
||||
if (this.config.yunzhupaasKey === 'collapse') {
|
||||
uni.$on('initCollapse', () => {
|
||||
this.$refs.collapseRef && this.$refs.collapseRef.init()
|
||||
})
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
initI18n(item) {
|
||||
const config = item.__config__
|
||||
if (item.placeholderI18nCode) item.placeholder = this.$t(item.placeholderI18nCode);
|
||||
if (config.tipLabelI18nCode) config.tipLabel = this.$t(config.tipLabelI18nCode)
|
||||
if (item.__config__.label && item.__config__.labelI18nCode) item.__config__.label = this.$t(item.__config__
|
||||
.labelI18nCode);
|
||||
if (item.__config__.tipLabel && item.__config__.tipLabelI18nCode) item.__config__.tipLabel = this.$t(item
|
||||
.__config__.tipLabelI18nCode);
|
||||
if (['groupTitle', 'divider', 'link', 'text'].includes(config.yunzhupaasKey)) {
|
||||
if (item.contentI18nCode) item.content = this.$t(item.contentI18nCode);
|
||||
if (item.helpMessageI18nCode) item.helpMessage = this.$t(item.helpMessageI18nCode);
|
||||
}
|
||||
if (config.yunzhupaasKey === 'button' && item.buttonTextI18nCode) item.buttonText = this.$t(item
|
||||
.buttonTextI18nCode);
|
||||
if (config.yunzhupaasKey === 'alert') {
|
||||
if (item.titleI18nCode) item.title = this.$t(item.titleI18nCode);
|
||||
if (item.descriptionI18nCode) item.description = this.$t(item.descriptionI18nCode);
|
||||
if (item.closeTextI18nCode) item.closeText = this.$t(item.closeTextI18nCode);
|
||||
}
|
||||
if (config.yunzhupaasKey === 'card') {
|
||||
if (item.headerI18nCode) item.header = this.$t(item.headerI18nCode);
|
||||
}
|
||||
if (['tab', 'collapse', 'steps'].includes(config.yunzhupaasKey)) {
|
||||
if (config.children && config.children.length) {
|
||||
for (let i = 0; i < config.children.length; i++) {
|
||||
if (config.children[i].titleI18nCode) config.children[i].title =
|
||||
this.$t(config.children[i].titleI18nCode);
|
||||
}
|
||||
}
|
||||
if (item.headerI18nCode) item.header = this.$t(item.headerI18nCode);
|
||||
}
|
||||
if (config.yunzhupaasKey === 'table') {
|
||||
if (config.children && config.children.length) {
|
||||
for (let i = 0; i < config.children.length; i++) {
|
||||
this.initI18n(config.children[i])
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
onStepChange(index, item) {
|
||||
if (this.stepCurrent === index) return
|
||||
item.__config__.active = index
|
||||
this.stepCurrent = index
|
||||
this.$nextTick(() => {
|
||||
uni.$emit('updateCode')
|
||||
uni.$emit('initCollapse')
|
||||
})
|
||||
},
|
||||
initData() {
|
||||
if (this.config.yunzhupaasKey === 'steps') this.stepCurrent = this.config.active
|
||||
if (this.config.yunzhupaasKey != 'tab') return this.value = this.config.defaultValue
|
||||
for (var i = 0; i < this.config.children.length; i++) {
|
||||
if (this.config.active == this.config.children[i].name) {
|
||||
this.tabCurrent = i
|
||||
break
|
||||
}
|
||||
}
|
||||
},
|
||||
onBlur(val) {
|
||||
this.setScriptFunc(val, this.item, 'blur')
|
||||
},
|
||||
onChange(val, data) {
|
||||
this.extraObj = data
|
||||
this.$nextTick(() => {
|
||||
this.setScriptFunc(data || val, this.item)
|
||||
})
|
||||
if (['popupSelect', 'relationForm'].includes(this.item.__config__.yunzhupaasKey)) {
|
||||
this.setTransferFormData(data || val, this.item.__config__, this.item.__config__.yunzhupaasKey)
|
||||
}
|
||||
this.$nextTick(() => {
|
||||
uni.$emit('subChange', this.item, data || val)
|
||||
})
|
||||
},
|
||||
setScriptFunc(val, data, type = 'change') {
|
||||
if (data && data.on && data.on[type]) {
|
||||
const func = this.yunzhupaas.getScriptFunc(data.on[type]);
|
||||
if (!func) return
|
||||
func.call(this, {
|
||||
data: val,
|
||||
...this.parameter
|
||||
})
|
||||
}
|
||||
},
|
||||
setTransferFormData(data, config, yunzhupaasKey) {
|
||||
if (!config.transferList.length) return;
|
||||
for (let index = 0; index < config.transferList.length; index++) {
|
||||
const element = config.transferList[index];
|
||||
this.parameter.setFormData(element.sourceValue, data[element.targetField]);
|
||||
}
|
||||
},
|
||||
onTabChange(index) {
|
||||
if (this.tabCurrent === index) return
|
||||
this.tabCurrent = index;
|
||||
const id = this.item.__config__.children[index].name
|
||||
this.$emit('tab-change', this.item, id)
|
||||
this.$nextTick(() => {
|
||||
uni.$emit('updateCode')
|
||||
uni.$emit('initCollapse')
|
||||
})
|
||||
},
|
||||
onChildTabChange(item, id) {
|
||||
this.$emit('tab-change', item, id)
|
||||
},
|
||||
onCollapseChange(data) {
|
||||
this.$emit('collapse-change', this.item, data)
|
||||
this.$nextTick(() => {
|
||||
uni.$emit('initCollapse')
|
||||
})
|
||||
},
|
||||
onChildCollapseChange(item, id) {
|
||||
this.$emit('collapse-change', item, id)
|
||||
},
|
||||
setValue(item, data) {
|
||||
this.$emit('input', item, data)
|
||||
},
|
||||
onClick(e) {
|
||||
this.$emit('clickFun', this.item, e || '')
|
||||
},
|
||||
onChildClick(e, item) {
|
||||
this.$emit('clickFun', item, e || '')
|
||||
},
|
||||
clickIcon(e) {
|
||||
this.$emit('clickIcon', e)
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.form-item-box {
|
||||
padding: 0 20rpx;
|
||||
}
|
||||
|
||||
.popup-select {
|
||||
::v-deep .u-form-item--left {
|
||||
align-items: flex-start !important;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
1078
components/yunzhupaas/Parser/childTable.vue
Normal file
1078
components/yunzhupaas/Parser/childTable.vue
Normal file
File diff suppressed because it is too large
Load Diff
895
components/yunzhupaas/Parser/index.vue
Normal file
895
components/yunzhupaas/Parser/index.vue
Normal file
@@ -0,0 +1,895 @@
|
||||
<template>
|
||||
<u-form class="yunzhupaas-wrap-form" ref="dataForm" :rules="rules" :model="formData" :errorType="['toast']"
|
||||
:label-position="formConf.labelPosition==='top'?'top':'left'"
|
||||
:label-width="formConf.labelWidth?formConf.labelWidth*1.5:150"
|
||||
:label-align="formConf.labelPosition==='right'?'right':'left'" :class="formClass+' '+formConfCopy.className">
|
||||
<view v-for="(item, index) in formConfCopy.fields" :key="item.__config__.renderKey">
|
||||
<Item v-if="!item.__config__.noShow && item.__config__.isVisibility" :itemData="item" :formConf="formConf"
|
||||
:formData="formData" :ref="'ref'+item.__config__.formId" :class="item.__config__.className"
|
||||
@clickIcon='clickIcon' @clickFun="onClick" @collapse-change="onCollapseChange" @tab-change="onTabChange"
|
||||
@input="setValue" />
|
||||
</view>
|
||||
<u-modal v-model="showTipsModal" width='70%' border-radius="16" :content-style="contentStyle"
|
||||
:content="tipsContent" :titleStyle="titleStyle" :title="tipsTitle" :confirm-style="confirmStyle"
|
||||
:confirm-text="$t('common.okText')" />
|
||||
</u-form>
|
||||
</template>
|
||||
<script>
|
||||
import Item from './Item'
|
||||
import {
|
||||
getDataInterfaceRes,
|
||||
getDictionaryDataSelector
|
||||
} from '@/api/common'
|
||||
const dyOptionsList = ['radio', 'checkbox', 'select', 'cascader', 'treeSelect']
|
||||
export default {
|
||||
components: {
|
||||
Item
|
||||
},
|
||||
props: {
|
||||
formConf: {
|
||||
type: Object,
|
||||
required: true
|
||||
},
|
||||
loading: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
isShortLink: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
},
|
||||
data() {
|
||||
const data = {
|
||||
formClass: 'form-' + this.yunzhupaas.idGenerator(),
|
||||
formConfCopy: this.$u.deepClone(this.formConf),
|
||||
formData: {},
|
||||
rules: {},
|
||||
options: {},
|
||||
tableRefs: {},
|
||||
relations: {},
|
||||
refList: [],
|
||||
contentStyle: {
|
||||
fontSize: '28rpx',
|
||||
padding: '20rpx',
|
||||
lineHeight: '44rpx',
|
||||
textAlign: 'left'
|
||||
},
|
||||
titleStyle: {
|
||||
padding: '20rpx'
|
||||
},
|
||||
confirmStyle: {
|
||||
height: '80rpx',
|
||||
lineHeight: '80rpx',
|
||||
},
|
||||
tipsContent: '',
|
||||
tipsTitle: this.$t('common.tipTitle'),
|
||||
showTipsModal: false
|
||||
}
|
||||
this.beforeInit(data.formConfCopy.fields)
|
||||
this.initRelationForm(data.formConfCopy.fields)
|
||||
this.initFormData(data.formConfCopy.fields, data.formData, data.tableRefs)
|
||||
this.buildRules(this.$u.deepClone(data.formConfCopy.fields), data.rules)
|
||||
this.buildOptions(data.formConfCopy.fields, data.options, data.formData)
|
||||
this.buildRelations(data.formConfCopy.fields, data.relations)
|
||||
this.$nextTick(() => {
|
||||
this.onLoadFunc(data.formConfCopy)
|
||||
this.getRefList()
|
||||
})
|
||||
return data
|
||||
},
|
||||
provide() {
|
||||
return {
|
||||
parameter: this.parameter,
|
||||
relations: this.relations,
|
||||
isShortLink: this.isShortLink
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
parameter() {
|
||||
const oldFormData = this.formConfCopy.formData ? this.formConfCopy.formData : {}
|
||||
this.formData.id = oldFormData.id || null
|
||||
this.formData.flowId = oldFormData.flowId || ''
|
||||
return {
|
||||
formData: this.formData,
|
||||
setFormData: this.setFormData,
|
||||
setShowOrHide: this.setShowOrHide,
|
||||
setRequired: this.setRequired,
|
||||
setDisabled: this.setDisabled,
|
||||
onlineUtils: this.yunzhupaas.onlineUtils,
|
||||
}
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.$refs.dataForm.setRules(this.rules);
|
||||
this.initRelationData()
|
||||
uni.$on('subChange', (field) => {
|
||||
this.handleRelation(field.__vModel__)
|
||||
})
|
||||
this.initCss(this.formConfCopy)
|
||||
},
|
||||
methods: {
|
||||
beforeInit(fields) {
|
||||
const loop = (list) => {
|
||||
for (var index = 0; index < list.length; index++) {
|
||||
const config = list[index].__config__
|
||||
if (config.children && config.children.length) loop(config.children)
|
||||
if (config.yunzhupaasKey == 'tableGrid') {
|
||||
let newList = []
|
||||
for (var i = 0; i < config.children.length; i++) {
|
||||
let element = config.children[i]
|
||||
for (var j = 0; j < element.__config__.children.length; j++) {
|
||||
let item = element.__config__.children[j]
|
||||
newList.push(...item.__config__.children)
|
||||
}
|
||||
}
|
||||
list.splice(index, 1, ...newList)
|
||||
}
|
||||
}
|
||||
}
|
||||
loop(fields)
|
||||
},
|
||||
initRelationForm(componentList) {
|
||||
componentList.forEach(cur => {
|
||||
const config = cur.__config__
|
||||
if (config.yunzhupaasKey == 'relationFormAttr' || config.yunzhupaasKey == 'popupAttr') {
|
||||
const relationKey = cur.relationField.split("_yunzhupaasTable_")[0]
|
||||
componentList.forEach(item => {
|
||||
const noVisibility = Array.isArray(item.__config__.visibility) && !item
|
||||
.__config__.visibility.includes('app')
|
||||
if ((relationKey == item.__vModel__) && (noVisibility || !!item.__config__
|
||||
.noShow) && !cur.__vModel__) {
|
||||
cur.__config__.noShow = true
|
||||
}
|
||||
})
|
||||
}
|
||||
if (cur.__config__.children && cur.__config__.children.length) this.initRelationForm(cur
|
||||
.__config__.children)
|
||||
})
|
||||
},
|
||||
initFormData(componentList, formData, tableRefs) {
|
||||
componentList.forEach(cur => {
|
||||
const config = cur.__config__
|
||||
if (cur.__vModel__) {
|
||||
formData[cur.__vModel__] = config.defaultValue
|
||||
if (cur.__config__.yunzhupaasKey == 'table' && !cur.__config__.noShow) {
|
||||
tableRefs[cur.__vModel__] = cur
|
||||
}
|
||||
}
|
||||
if (config.children && cur.__config__.yunzhupaasKey !== 'table') {
|
||||
this.initFormData(config.children, formData, tableRefs)
|
||||
}
|
||||
})
|
||||
},
|
||||
buildOptions(componentList, data, formData) {
|
||||
componentList.forEach(cur => {
|
||||
const config = cur.__config__
|
||||
if (dyOptionsList.indexOf(config.yunzhupaasKey) > -1) {
|
||||
if (config.dataType === 'dictionary' && config.dictionaryType) {
|
||||
cur.options = []
|
||||
getDictionaryDataSelector(config.dictionaryType).then(res => {
|
||||
cur.options = res.data.list || []
|
||||
data[cur.__vModel__ + 'Options'] = cur.options
|
||||
this.setFieldOptions(cur.__vModel__, cur.options)
|
||||
this.$nextTick(() => {
|
||||
uni.$emit("initCollapse")
|
||||
})
|
||||
})
|
||||
} else if (config.dataType === 'dynamic' && config.propsUrl) {
|
||||
cur.options = []
|
||||
let query = {
|
||||
paramList: this.yunzhupaas.getParamList(config.templateJson, formData),
|
||||
}
|
||||
getDataInterfaceRes(config.propsUrl, query).then(res => {
|
||||
cur.options = Array.isArray(res.data) ? res.data : []
|
||||
data[cur.__vModel__ + 'Options'] = cur.options
|
||||
this.setFieldOptions(cur.__vModel__, cur.options)
|
||||
uni.$emit("initCollapse")
|
||||
})
|
||||
} else {
|
||||
data[cur.__vModel__ + 'Options'] = cur.options
|
||||
}
|
||||
}
|
||||
if (config.children && config.yunzhupaasKey !== 'table') this.buildOptions(config.children, data,
|
||||
formData)
|
||||
})
|
||||
},
|
||||
buildRules(componentList, rules) {
|
||||
componentList.forEach(cur => {
|
||||
const config = cur.__config__
|
||||
const yunzhupaasKey = config.yunzhupaasKey
|
||||
const useNumList = ['inputNumber', 'switch', 'datePicker', 'rate', 'slider', 'calculate']
|
||||
const useArrayList = ['select', 'depSelect', 'posSelect', 'userSelect', 'usersSelect',
|
||||
'treeSelect', 'popupTableSelect'
|
||||
]
|
||||
config.regList = !config.regList ? [] : config.regList
|
||||
if (config.required) {
|
||||
const label = config.labelI18nCode ?
|
||||
this.$t(config.labelI18nCode, config.label) : config.label;
|
||||
let requiredItem = {
|
||||
required: config.required,
|
||||
message: `${label} ${this.$t('sys.validate.textRequiredSuffix')}`
|
||||
};
|
||||
config.regList.push(requiredItem)
|
||||
}
|
||||
const rule = config.regList.map(item => {
|
||||
if (item.pattern) {
|
||||
item.pattern = item.pattern.toString()
|
||||
let start = item.pattern.indexOf('/')
|
||||
let stop = item.pattern.lastIndexOf('/')
|
||||
let str = item.pattern.substring(start + 1, stop)
|
||||
let reg = new RegExp(str)
|
||||
item.pattern = reg
|
||||
}
|
||||
item.trigger = config.trigger || 'change, blur'
|
||||
if (Array.isArray(config.defaultValue)) item.type = 'array'
|
||||
if (useNumList.includes(yunzhupaasKey)) item.type = 'number'
|
||||
if (useArrayList.includes(yunzhupaasKey) && cur.multiple) item.type = 'array'
|
||||
if (yunzhupaasKey === 'organizeSelect' || yunzhupaasKey === 'areaSelect' || yunzhupaasKey ===
|
||||
'checkbox' || yunzhupaasKey === 'cascader') item.type = 'array'
|
||||
|
||||
if (yunzhupaasKey === 'relationForm' || yunzhupaasKey === 'popupSelect') {
|
||||
item.type = 'any',
|
||||
item.validator = (rule, value, callback) => {
|
||||
if (value || value === 0) {
|
||||
callback();
|
||||
} else {
|
||||
callback(new Error(config.label + '不能为空'));
|
||||
}
|
||||
}
|
||||
}
|
||||
if (item.messageI18nCode) {
|
||||
item.message = this.$t(item.messageI18nCode, item.message);
|
||||
}
|
||||
return item
|
||||
})
|
||||
if (rule.length) rules[cur.__vModel__] = rule
|
||||
if (config.children && yunzhupaasKey !== 'table') this.buildRules(this.$u.deepClone(config.children),
|
||||
rules)
|
||||
})
|
||||
},
|
||||
buildRelations(componentList, relations) {
|
||||
componentList.forEach(cur => {
|
||||
const config = cur.__config__
|
||||
const vModel = cur.__vModel__
|
||||
const selectType = ['dep', 'pos', 'role', 'group']
|
||||
if (config.yunzhupaasKey === 'userSelect' && selectType.includes(cur.selectType)) {
|
||||
if (cur.relationField) {
|
||||
let item = {
|
||||
...cur,
|
||||
realVModel: config.isSubTable ? config.parentVModel + '-' + vModel : vModel,
|
||||
opType: 'setUserOptions'
|
||||
}
|
||||
if (relations.hasOwnProperty(cur.relationField)) {
|
||||
let boo = relations[cur.relationField].some(o => o.realVModel === cur.realVModel)
|
||||
if (!boo) relations[cur.relationField].push(item)
|
||||
} else {
|
||||
relations[cur.relationField] = [item]
|
||||
}
|
||||
}
|
||||
}
|
||||
if (dyOptionsList.indexOf(config.yunzhupaasKey) > -1 && config.dataType === 'dynamic' && config
|
||||
.templateJson && config.templateJson.length) {
|
||||
for (let i = 0; i < config.templateJson.length; i++) {
|
||||
const e = config.templateJson[i];
|
||||
if (e.relationField) {
|
||||
let item = {
|
||||
...cur,
|
||||
realVModel: config.isSubTable ? config.parentVModel + '-' + vModel :
|
||||
vModel,
|
||||
opType: 'setOptions'
|
||||
}
|
||||
if (relations.hasOwnProperty(e.relationField)) {
|
||||
let boo = relations[e.relationField].some(o => o.realVModel === cur
|
||||
.realVModel)
|
||||
if (!boo) relations[e.relationField].push(item)
|
||||
} else {
|
||||
relations[e.relationField] = [item]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (config.yunzhupaasKey === 'datePicker') {
|
||||
if (config.startTimeRule) {
|
||||
let startTimeValue = Number(config.startTimeValue)
|
||||
if (config.startTimeType == 1) {
|
||||
cur.startTime = startTimeValue
|
||||
} else if (config.startTimeType == 3) {
|
||||
cur.startTime = new Date().getTime()
|
||||
} else {
|
||||
if (config.startTimeType == 4) {
|
||||
if (config.startTimeTarget == 1) cur.startTime = new Date(new Date()
|
||||
.setFullYear((new Date().getFullYear() - startTimeValue))).getTime()
|
||||
if (config.startTimeTarget == 2) cur.startTime = new Date(new Date().setMonth((
|
||||
new Date().getMonth() - startTimeValue))).getTime()
|
||||
if (config.startTimeTarget == 3) cur.startTime = new Date(new Date().setDate((
|
||||
new Date().getDate() - startTimeValue))).getTime()
|
||||
} else {
|
||||
if (config.startTimeTarget == 1) cur.startTime = new Date(new Date()
|
||||
.setFullYear((new Date().getFullYear() + startTimeValue))).getTime()
|
||||
if (config.startTimeTarget == 2) cur.startTime = new Date(new Date().setMonth((
|
||||
new Date().getMonth() + startTimeValue))).getTime()
|
||||
if (config.startTimeTarget == 3) cur.startTime = new Date(new Date().setDate((
|
||||
new Date().getDate() + startTimeValue))).getTime()
|
||||
}
|
||||
}
|
||||
}
|
||||
if (config.endTimeRule) {
|
||||
let endTimeValue = Number(config.endTimeValue)
|
||||
if (config.endTimeType == 1) {
|
||||
cur.endTime = endTimeValue
|
||||
} else if (config.endTimeType == 3) {
|
||||
cur.endTime = new Date().getTime()
|
||||
} else {
|
||||
if (config.endTimeType == 4) {
|
||||
if (config.endTimeTarget == 1) cur.endTime = new Date(new Date()
|
||||
.setFullYear((new Date().getFullYear() - endTimeValue))).getTime()
|
||||
if (config.endTimeTarget == 2) cur.endTime = new Date(new Date().setMonth((
|
||||
new Date().getMonth() - endTimeValue))).getTime()
|
||||
if (config.endTimeTarget == 3) cur.endTime = new Date(new Date().setDate((
|
||||
new Date().getDate() - endTimeValue))).getTime()
|
||||
} else {
|
||||
if (config.endTimeTarget == 1) cur.endTime = new Date(new Date()
|
||||
.setFullYear((new Date().getFullYear() + endTimeValue))).getTime()
|
||||
if (config.endTimeTarget == 2) cur.endTime = new Date(new Date().setMonth((
|
||||
new Date().getMonth() + endTimeValue))).getTime()
|
||||
if (config.endTimeTarget == 3) {
|
||||
cur.endTime = new Date(new Date().setDate((new Date().getDate() +
|
||||
endTimeValue))).getTime()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (cur.__config__.startRelationField) {
|
||||
let item = {
|
||||
...cur,
|
||||
realVModel: cur.__config__.isSubTable ? cur.__config__.parentVModel + '-' + cur
|
||||
.__vModel__ : cur.__vModel__,
|
||||
opType: 'setDate'
|
||||
}
|
||||
if (relations.hasOwnProperty(cur.__config__.startRelationField)) {
|
||||
let boo = relations[cur.__config__.startRelationField].some(o => o.realVModel ===
|
||||
cur.realVModel)
|
||||
if (!boo) {
|
||||
relations[cur.__config__.startRelationField].push(item)
|
||||
}
|
||||
} else {
|
||||
relations[cur.__config__.startRelationField] = [item]
|
||||
}
|
||||
}
|
||||
if (cur.__config__.endRelationField) {
|
||||
let item = {
|
||||
...cur,
|
||||
realVModel: cur.__config__.isSubTable ? cur.__config__.parentVModel + '-' + cur
|
||||
.__vModel__ : cur.__vModel__,
|
||||
opType: 'setDate'
|
||||
}
|
||||
if (relations.hasOwnProperty(cur.__config__.endRelationField)) {
|
||||
let boo = relations[cur.__config__.endRelationField].some(o => o.realVModel === cur
|
||||
.realVModel)
|
||||
if (!boo) {
|
||||
relations[cur.__config__.endRelationField].push(item)
|
||||
}
|
||||
} else {
|
||||
relations[cur.__config__.endRelationField] = [item]
|
||||
}
|
||||
}
|
||||
}
|
||||
if (config.yunzhupaasKey === 'timePicker') {
|
||||
let format = cur.format === 'HH:mm' ? 'HH:mm:00' : cur.format
|
||||
if (config.startTimeRule) {
|
||||
let startTime = ''
|
||||
if (config.startTimeType == 1) {
|
||||
cur.startTime = config.startTimeValue || '00:00:00'
|
||||
if (cur.startTime.split(':').length == 3) {
|
||||
cur.startTime = cur.startTime
|
||||
} else {
|
||||
cur.startTime = cur.startTime + ':00'
|
||||
}
|
||||
} else if (config.startTimeType == 3) {
|
||||
cur.startTime = this.yunzhupaas.toDate(new Date(), format)
|
||||
} else {
|
||||
let startTimeValue = Number(config.startTimeValue)
|
||||
if (config.startTimeType == 4) {
|
||||
if (config.startTimeTarget == 1) startTime = new Date(new Date().setHours((
|
||||
new Date().getHours() - startTimeValue))).getTime()
|
||||
if (config.startTimeTarget == 2) startTime = new Date(new Date()
|
||||
.setMinutes((new Date().getMinutes() - startTimeValue))).getTime()
|
||||
if (config.startTimeTarget == 3) startTime = new Date(new Date()
|
||||
.setSeconds((new Date().getSeconds() - startTimeValue))).getTime()
|
||||
} else {
|
||||
if (config.startTimeTarget == 1) startTime = new Date(new Date().setHours((
|
||||
new Date().getHours() + startTimeValue))).getTime()
|
||||
if (config.startTimeTarget == 2) startTime = new Date(new Date()
|
||||
.setMinutes((new Date().getMinutes() + startTimeValue)))
|
||||
.getTime()
|
||||
if (config.startTimeTarget == 3) startTime = new Date(new Date()
|
||||
.setSeconds((new Date().getSeconds() + startTimeValue))).getTime()
|
||||
}
|
||||
cur.startTime = this.$u.timeFormat(startTime, 'hh:MM:ss')
|
||||
}
|
||||
}
|
||||
if (config.endTimeRule) {
|
||||
let endTime = ''
|
||||
if (config.endTimeType == 1) {
|
||||
cur.endTime = config.endTimeValue || '23:59:59'
|
||||
if (cur.endTime.split(':').length == 3) {
|
||||
cur.endTime = cur.endTime
|
||||
} else {
|
||||
cur.endTime = cur.endTime + ':00'
|
||||
}
|
||||
} else if (config.endTimeType == 3) {
|
||||
cur.endTime = this.yunzhupaas.toDate(new Date(), format)
|
||||
} else {
|
||||
let endTimeValue = Number(config.endTimeValue)
|
||||
if (config.endTimeType == 4) {
|
||||
if (config.endTimeTarget == 1) {
|
||||
endTime = new Date(new Date().setHours((new Date().getHours() -
|
||||
endTimeValue))).getTime()
|
||||
}
|
||||
if (config.endTimeTarget == 2) {
|
||||
endTime = new Date(new Date().setMinutes((new Date().getMinutes() -
|
||||
endTimeValue))).getTime()
|
||||
}
|
||||
if (config.endTimeTarget == 3) {
|
||||
endTime = new Date(new Date().setSeconds((new Date().getSeconds() -
|
||||
endTimeValue))).getTime()
|
||||
}
|
||||
} else {
|
||||
if (config.endTimeTarget == 1) {
|
||||
endTime = new Date(new Date().setHours((new Date().getHours() +
|
||||
endTimeValue))).getTime()
|
||||
}
|
||||
if (config.endTimeTarget == 2) {
|
||||
endTime = new Date(new Date().setMinutes((new Date().getMinutes() +
|
||||
endTimeValue))).getTime()
|
||||
}
|
||||
if (config.endTimeTarget == 3) {
|
||||
endTime = new Date(new Date().setSeconds((new Date().getSeconds() +
|
||||
endTimeValue))).getTime()
|
||||
}
|
||||
}
|
||||
cur.endTime = this.$u.timeFormat(endTime, 'hh:MM:ss')
|
||||
}
|
||||
}
|
||||
if (cur.__config__.startRelationField) {
|
||||
let item = {
|
||||
...cur,
|
||||
realVModel: cur.__config__.isSubTable ? cur.__config__.parentVModel + '-' + cur
|
||||
.__vModel__ : cur.__vModel__,
|
||||
opType: 'setTime'
|
||||
}
|
||||
if (relations.hasOwnProperty(cur.__config__.startRelationField)) {
|
||||
let boo = relations[cur.__config__.startRelationField].some(o => o.realVModel ===
|
||||
cur.realVModel)
|
||||
if (!boo) {
|
||||
relations[cur.__config__.startRelationField].push(item)
|
||||
}
|
||||
} else {
|
||||
relations[cur.__config__.startRelationField] = [item]
|
||||
}
|
||||
}
|
||||
if (cur.__config__.endRelationField) {
|
||||
let item = {
|
||||
...cur,
|
||||
realVModel: cur.__config__.isSubTable ? cur.__config__.parentVModel + '-' + cur
|
||||
.__vModel__ : cur.__vModel__,
|
||||
opType: 'setTime'
|
||||
}
|
||||
if (relations.hasOwnProperty(cur.__config__.endRelationField)) {
|
||||
let boo = relations[cur.__config__.endRelationField].some(o => o.realVModel === cur
|
||||
.realVModel)
|
||||
if (!boo) {
|
||||
relations[cur.__config__.endRelationField].push(item)
|
||||
}
|
||||
} else {
|
||||
relations[cur.__config__.endRelationField] = [item]
|
||||
}
|
||||
}
|
||||
}
|
||||
if (config.yunzhupaasKey === 'popupSelect' && cur.templateJson && cur.templateJson.length) {
|
||||
for (let i = 0; i < cur.templateJson.length; i++) {
|
||||
const e = cur.templateJson[i];
|
||||
if (e.relationField) {
|
||||
let item = {
|
||||
...cur,
|
||||
realVModel: cur.__config__.isSubTable ? cur.__config__.parentVModel +
|
||||
'-' + cur.__vModel__ : cur.__vModel__,
|
||||
opType: 'setPopupOptions'
|
||||
}
|
||||
if (relations.hasOwnProperty(e.relationField)) {
|
||||
let boo = relations[e.relationField].some(o => o.realVModel === cur
|
||||
.realVModel)
|
||||
if (!boo) {
|
||||
relations[e.relationField].push(item)
|
||||
}
|
||||
} else {
|
||||
relations[e.relationField] = [item]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (config.children) this.buildRelations(config.children, relations)
|
||||
})
|
||||
},
|
||||
onLoadFunc(formConfCopy) {
|
||||
if (!formConfCopy || !formConfCopy.funcs || !formConfCopy.funcs.onLoad) return
|
||||
const onLoadFunc = this.yunzhupaas.getScriptFunc(formConfCopy.funcs.onLoad)
|
||||
if (!onLoadFunc) return
|
||||
onLoadFunc(this.parameter)
|
||||
},
|
||||
initRelationData() {
|
||||
const handleRelationFun = (list) => {
|
||||
list.forEach(cur => {
|
||||
const config = cur.__config__
|
||||
this.handleDefaultRelation(cur.__vModel__)
|
||||
if (config.children) handleRelationFun(config.children)
|
||||
})
|
||||
}
|
||||
handleRelationFun(this.formConfCopy.fields)
|
||||
},
|
||||
initCss(formCopy) {
|
||||
// #ifdef H5
|
||||
if (!formCopy.classJson) return
|
||||
if (document.getElementById('styleId')) document.getElementById('styleId').remove()
|
||||
let head = document.getElementsByTagName('head')[0]
|
||||
let style = document.createElement('style')
|
||||
style.type = 'text/css'
|
||||
style.id = 'styleId'
|
||||
style.innerText = this.buildCSS(formCopy.classJson)
|
||||
head.appendChild(style)
|
||||
//#endif
|
||||
},
|
||||
buildCSS(str) {
|
||||
str = str.trim();
|
||||
let newStr = '';
|
||||
let cut = str.split('}');
|
||||
cut.forEach(item => {
|
||||
if (item) {
|
||||
item = '.' + this.formClass + ' ' + item + '}';
|
||||
newStr += item;
|
||||
}
|
||||
});
|
||||
return newStr;
|
||||
},
|
||||
handleRelation(field) {
|
||||
if (!field) return
|
||||
const currRelations = this.relations
|
||||
for (let key in currRelations) {
|
||||
if (key === field) {
|
||||
for (let i = 0; i < currRelations[key].length; i++) {
|
||||
const e = currRelations[key][i];
|
||||
let vModel = e.realVModel || e.__vModel__
|
||||
const config = e.__config__
|
||||
const yunzhupaasKey = config.yunzhupaasKey
|
||||
let defaultValue = ''
|
||||
if (['checkbox', 'cascader'].includes(yunzhupaasKey) || (['select', 'treeSelect', 'popupSelect',
|
||||
'popupTableSelect', 'userSelect'
|
||||
].includes(yunzhupaasKey) && e.multiple)) {
|
||||
defaultValue = []
|
||||
}
|
||||
if (vModel.includes('-')) { // 子表字段
|
||||
const tableVModel = vModel.split('-')[0]
|
||||
uni.$emit('handleRelation', e, defaultValue, true)
|
||||
} else {
|
||||
this.setFormData(vModel, defaultValue)
|
||||
if (e.opType === 'setOptions') {
|
||||
let query = {
|
||||
paramList: this.yunzhupaas.getParamList(config.templateJson, this.formData)
|
||||
}
|
||||
getDataInterfaceRes(config.propsUrl, query).then(res => {
|
||||
let realData = res.data || []
|
||||
this.setFieldOptions(vModel, realData)
|
||||
uni.$emit("initCollapse")
|
||||
})
|
||||
}
|
||||
if (e.opType === 'setUserOptions') {
|
||||
let value = this.formData[e.relationField] || []
|
||||
this.comSet('ableRelationIds', vModel, Array.isArray(value) ? value : [value])
|
||||
}
|
||||
if (e.opType === 'setDate' || e.opType === 'setTime') {
|
||||
let startTime = ''
|
||||
let endTime = ''
|
||||
if (config.startTimeType == 2) {
|
||||
startTime = this.formData[config.startRelationField] || 0
|
||||
if (e.opType === 'setTime') {
|
||||
startTime = this.formData[config.startRelationField] ||
|
||||
'00:00:00'
|
||||
if (startTime && (startTime.split(':').length == 3)) {
|
||||
startTime = startTime
|
||||
} else {
|
||||
startTime = startTime + ':00'
|
||||
}
|
||||
}
|
||||
} else {
|
||||
startTime = e.startTime
|
||||
}
|
||||
if (config.endTimeType == 2) {
|
||||
endTime = this.formData[config.endRelationField] || 0
|
||||
if (e.opType === 'setTime') {
|
||||
endTime = this.formData[config.endRelationField] ||
|
||||
'00:00:00'
|
||||
if (endTime && (endTime.split(':').length == 3)) {
|
||||
endTime = endTime
|
||||
} else {
|
||||
endTime = endTime + ':00'
|
||||
}
|
||||
}
|
||||
} else {
|
||||
endTime = e.endTime
|
||||
}
|
||||
this.comSet('startTime', vModel, startTime)
|
||||
this.comSet('endTime', vModel, endTime)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
handleDefaultRelation(field) {
|
||||
if (!field) return
|
||||
const currRelations = this.relations
|
||||
for (let key in currRelations) {
|
||||
if (key === field) {
|
||||
for (let i = 0; i < currRelations[key].length; i++) {
|
||||
const e = currRelations[key][i];
|
||||
let vModel = e.realVModel || e.__vModel__
|
||||
const config = e.__config__
|
||||
let defaultValue = ''
|
||||
if (vModel.includes('-')) { // 子表字段
|
||||
const tableVModel = vModel.split('-')[0]
|
||||
uni.$emit('handleRelation', e, defaultValue)
|
||||
} else {
|
||||
if (e.opType === 'setUserOptions') {
|
||||
let value = this.formData[e.relationField] || []
|
||||
this.comSet('ableRelationIds', e.__vModel__, Array.isArray(value) ? value : [value])
|
||||
}
|
||||
if (e.opType === 'setDate' || e.opType === 'setTime') {
|
||||
let startTime = ''
|
||||
let endTime = ''
|
||||
if (config.startTimeType == 2) {
|
||||
startTime = this.formData[config.startRelationField] || 0
|
||||
if (e.opType === 'setTime') {
|
||||
startTime = this.formData[config.startRelationField] ||
|
||||
'00:00:00'
|
||||
if (startTime && (startTime.split(':').length == 3)) {
|
||||
startTime = startTime
|
||||
} else {
|
||||
startTime = startTime + ':00'
|
||||
}
|
||||
}
|
||||
} else {
|
||||
startTime = e.startTime
|
||||
}
|
||||
if (config.endTimeType == 2) {
|
||||
endTime = this.formData[config.endRelationField] || 0
|
||||
if (e.opType === 'setTime') {
|
||||
endTime = this.formData[config.endRelationField] ||
|
||||
'23:59:59'
|
||||
if (endTime && (endTime.split(':').length == 3)) {
|
||||
endTime = endTime
|
||||
} else {
|
||||
endTime = endTime + ':00'
|
||||
}
|
||||
}
|
||||
} else {
|
||||
endTime = e.endTime
|
||||
}
|
||||
this.comSet('startTime', e.__vModel__, startTime)
|
||||
this.comSet('endTime', e.__vModel__, endTime)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
onChange(field) {
|
||||
this.handleRelation(field.__vModel__)
|
||||
},
|
||||
setValue(item) {
|
||||
if (item.__vModel__) {
|
||||
this.$set(this.formData, item.__vModel__, item.__config__.defaultValue)
|
||||
}
|
||||
},
|
||||
setFormData(prop, value) {
|
||||
if (!prop || this.formData[prop] === value) return;
|
||||
const isChildTable = prop.indexOf('.') > -1
|
||||
if (isChildTable) {
|
||||
const list = prop.split('.')
|
||||
for (let i = 0; i < this.refList.length; i++) {
|
||||
const item = this.refList[i]
|
||||
if (item[0] == list[0]) {
|
||||
const tableRef = Array.isArray(item[1]) ? item[1][0] : item[1]
|
||||
tableRef.setTableFormData(list[1], value)
|
||||
break
|
||||
}
|
||||
}
|
||||
} else {
|
||||
this.comSet('defaultValue', prop, value)
|
||||
this.formData[prop] = value
|
||||
}
|
||||
this.handleRelation(prop)
|
||||
},
|
||||
setShowOrHide(prop, value) {
|
||||
const newVal = !!value
|
||||
const isChildTable = prop.indexOf('.') > -1
|
||||
if (!isChildTable) {
|
||||
this.comSet('noShow', prop, !newVal)
|
||||
}
|
||||
},
|
||||
setRequired(prop, value) {
|
||||
const newVal = !!value
|
||||
const isChildTable = prop.indexOf('.') > -1
|
||||
if (!isChildTable) {
|
||||
this.comSet('required', prop, newVal)
|
||||
this.rules = {}
|
||||
this.buildRules(this.$u.deepClone(this.formConfCopy.fields), this.rules)
|
||||
this.$refs.dataForm.setRules(this.rules);
|
||||
}
|
||||
},
|
||||
setDisabled(prop, value) {
|
||||
const newVal = !!value
|
||||
const isChildTable = prop.indexOf('.') > -1
|
||||
if (!isChildTable) {
|
||||
this.comSet('disabled', prop, newVal)
|
||||
}
|
||||
},
|
||||
setFieldOptions(prop, value) {
|
||||
const newVal = Array.isArray(value) ? value : []
|
||||
const isChildTable = prop.indexOf('.') > -1
|
||||
if (!isChildTable) {
|
||||
this.comSet('options', prop, newVal)
|
||||
}
|
||||
},
|
||||
comSet(field, prop, value) {
|
||||
if (!prop) return
|
||||
const loop = list => {
|
||||
for (let i = 0; i < list.length; i++) {
|
||||
let item = list[i]
|
||||
const config = item.__config__
|
||||
if (item.__vModel__ && item.__vModel__ === prop) {
|
||||
config.defaultValue = this.formData[prop]
|
||||
switch (field) {
|
||||
case 'disabled':
|
||||
item[field] = value
|
||||
break;
|
||||
case 'ableRelationIds':
|
||||
this.$set(item, field, value)
|
||||
case 'options':
|
||||
if (dyOptionsList.indexOf(config.yunzhupaasKey) > -1) item.options = value
|
||||
break;
|
||||
case 'startTime':
|
||||
this.$set(item, field, value)
|
||||
break;
|
||||
case 'endTime':
|
||||
this.$set(item, field, value)
|
||||
break;
|
||||
default:
|
||||
config[field] = value
|
||||
this.setValue(item)
|
||||
break;
|
||||
}
|
||||
config.renderKey = +new Date() + item.__vModel__
|
||||
break;
|
||||
}
|
||||
if (config && config.yunzhupaasKey !== 'table' && config.children && Array.isArray(config
|
||||
.children)) loop(config.children)
|
||||
}
|
||||
}
|
||||
loop(this.formConfCopy.fields)
|
||||
},
|
||||
submitForm() {
|
||||
try {
|
||||
this.beforeSubmit().then(() => {
|
||||
this.submit()
|
||||
})
|
||||
} catch (e) {
|
||||
this.submit()
|
||||
}
|
||||
},
|
||||
submit() {
|
||||
this.$refs.dataForm.validate(valid => {
|
||||
if (!valid) return
|
||||
if (!this.checkTableData()) return
|
||||
this.$emit('submit', this.formData, this.afterSubmit)
|
||||
});
|
||||
},
|
||||
beforeSubmit() {
|
||||
if (!this.formConfCopy || !this.formConfCopy.funcs || !this.formConfCopy.funcs.beforeSubmit) return Promise
|
||||
.resolve()
|
||||
const func = this.yunzhupaas.getScriptFunc(this.formConfCopy.funcs.beforeSubmit)
|
||||
if (!func) return Promise.resolve()
|
||||
return func(this.parameter)
|
||||
},
|
||||
afterSubmit() {
|
||||
if (!this.formConfCopy || !this.formConfCopy.funcs || !this.formConfCopy.funcs.afterSubmit) return
|
||||
const func = this.yunzhupaas.getScriptFunc(this.formConfCopy.funcs.afterSubmit)
|
||||
if (!func) return
|
||||
func(this.parameter)
|
||||
},
|
||||
// 子表必填验证,子表赋值
|
||||
checkTableData() {
|
||||
this.getRefList()
|
||||
let valid = true
|
||||
for (var i = 0; i < Object.keys(this.tableRefs).length; i++) {
|
||||
const vModel = Object.keys(this.tableRefs)[i]
|
||||
const config = this.tableRefs[vModel].__config__
|
||||
if (!config.isVisibility || config.noShow) continue
|
||||
let tableRef = null
|
||||
for (let i = 0; i < this.refList.length; i++) {
|
||||
const item = this.refList[i]
|
||||
if (item[0] === vModel) {
|
||||
tableRef = Array.isArray(item[1]) ? item[1][0] : item[1]
|
||||
break
|
||||
}
|
||||
}
|
||||
if (!tableRef) continue
|
||||
const res = (tableRef && tableRef.$refs && tableRef.$refs[vModel] ? tableRef.$refs[vModel] : tableRef)
|
||||
.submit() || false;
|
||||
res ? (this.formData[vModel] = res) : (valid = false)
|
||||
}
|
||||
return valid
|
||||
},
|
||||
//获取子表实例ref
|
||||
getRefList() {
|
||||
this.refList = []
|
||||
const refList = this.$refs || []
|
||||
const loop = (list) => {
|
||||
for (var i = 0; i < list.length; i++) {
|
||||
const refs = list[i].$refs
|
||||
if (Array.isArray(refs)) {
|
||||
loop(refs)
|
||||
} else {
|
||||
if (Object.values(refs).length) {
|
||||
for (var k in refs) {
|
||||
if (Array.isArray(refs[k])) {
|
||||
loop(refs[k])
|
||||
} else {
|
||||
this.refList.push([k, refs[k]])
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
for (var i in refList) {
|
||||
const item = refList[i]
|
||||
if (Array.isArray(item)) loop(item)
|
||||
}
|
||||
},
|
||||
clickIcon(e) {
|
||||
if (!e) return
|
||||
if (!e.__config__.tipLabel && !e.helpMessage) return
|
||||
this.tipsContent = e.helpMessage || e.__config__.tipLabel
|
||||
this.tipsTitle = e.__config__.label
|
||||
if (e.__config__.yunzhupaasKey === 'card') this.tipsTitle = e.header
|
||||
if (e.__config__.yunzhupaasKey === 'groupTitle') this.tipsTitle = e.content
|
||||
this.showTipsModal = true
|
||||
},
|
||||
onBlur(item, data) {
|
||||
this.setValue(item)
|
||||
this.setScriptFunc(data, item, 'blur')
|
||||
},
|
||||
onTabChange(item, data) {
|
||||
this.setScriptFunc(data, item, 'tabClick')
|
||||
},
|
||||
onClick(item, data) {
|
||||
this.setScriptFunc(data, item, 'click')
|
||||
},
|
||||
onCollapseChange(item, data) {
|
||||
this.setScriptFunc(data, item)
|
||||
},
|
||||
setScriptFunc(val, data, type = 'change') {
|
||||
if (data && data.on && data.on[type]) {
|
||||
const func = this.yunzhupaas.getScriptFunc(data.on[type]);
|
||||
if (!func) return
|
||||
func.call(this, {
|
||||
data: val,
|
||||
...this.parameter
|
||||
})
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
</script>
|
||||
112
components/yunzhupaas/Parser/mixin.js
Normal file
112
components/yunzhupaas/Parser/mixin.js
Normal file
@@ -0,0 +1,112 @@
|
||||
import {
|
||||
getDataInterfaceRes
|
||||
} from '@/api/common'
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
ids: [],
|
||||
selectItems: []
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
checkboxChange(e, item) {
|
||||
this.$nextTick(() => {
|
||||
if (e.value) {
|
||||
this.selectItems.push(item)
|
||||
} else {
|
||||
const i = this.selectItems.findIndex(o => !o.checked)
|
||||
this.selectItems.splice(i, 1)
|
||||
}
|
||||
})
|
||||
},
|
||||
openSelectDialog(item) {
|
||||
let actionConfig = item.actionConfig
|
||||
const data = {
|
||||
actionConfig,
|
||||
formData: this.formData,
|
||||
tableVmodel: this.config.__vModel__
|
||||
}
|
||||
if (item.actionType == 1) return uni.navigateTo({
|
||||
url: '/pages/apply/tableLinkage/index?data=' + JSON.stringify(data)
|
||||
})
|
||||
if (!this.tableFormData.some(item => item.checked)) return this.$u.toast('至少选中一条数据');
|
||||
if (item.actionType == 2) {
|
||||
if (actionConfig.executeType == 2) {
|
||||
this.handleScriptFunc(actionConfig)
|
||||
} else {
|
||||
this.handleInterface(actionConfig)
|
||||
}
|
||||
}
|
||||
},
|
||||
//自定义按钮JS操作
|
||||
handleScriptFunc(item) {
|
||||
let data = this.selectItems.map(child => {
|
||||
let obj = {};
|
||||
child.forEach(item => {
|
||||
obj[item.__vModel__] = item.value;
|
||||
});
|
||||
return obj;
|
||||
});
|
||||
const parameter = {
|
||||
data,
|
||||
refresh: this.initData,
|
||||
onlineUtils: this.yunzhupaas.onlineUtils,
|
||||
}
|
||||
const func = this.yunzhupaas.getScriptFunc.call(this, item.executeFunc)
|
||||
if (!func) return
|
||||
func.call(this, parameter)
|
||||
},
|
||||
//自定义按钮接口操作
|
||||
handleInterface(item) {
|
||||
let data = this.selectItems.flatMap(child => {
|
||||
return child.map(item => ({
|
||||
[item.__vModel__]: item.value
|
||||
}));
|
||||
});
|
||||
const handlerInterface = (data) => {
|
||||
let query = {
|
||||
paramList: this.getBatchParamList(item.executeTemplateJson, data) || [],
|
||||
}
|
||||
getDataInterfaceRes(item.executeInterfaceId, query).then(res => {
|
||||
uni.showToast({
|
||||
title: res.msg,
|
||||
icon: 'none'
|
||||
})
|
||||
})
|
||||
}
|
||||
if (!item.executeUseConfirm) return handlerInterface(data)
|
||||
uni.showModal({
|
||||
title: this.$t('common.tipTitle'),
|
||||
content: item.executeConfirmTitle || '确认执行此操作?',
|
||||
showCancel: true,
|
||||
confirmText: '确定',
|
||||
success: function(res) {
|
||||
if (res.confirm) {
|
||||
handlerInterface(data)
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
getBatchParamList(templateJson, data) {
|
||||
if (!templateJson || !templateJson.length) return [];
|
||||
for (let i = 0; i < templateJson.length; i++) {
|
||||
const e = templateJson[i];
|
||||
let defaultValue = [];
|
||||
if (e.sourceType === 1 && data.length) {
|
||||
data.forEach(o => {
|
||||
if (o.hasOwnProperty(e.relationField)) {
|
||||
defaultValue.push(o[e.relationField]);
|
||||
}
|
||||
});
|
||||
}
|
||||
e.defaultValue = defaultValue;
|
||||
if (e.sourceType === 4 && e.relationField === '@formId' && data.id !== undefined) {
|
||||
e.defaultValue = [data.id];
|
||||
} else if (e.sourceType !== 1) {
|
||||
e.defaultValue = [];
|
||||
}
|
||||
}
|
||||
return templateJson;
|
||||
}
|
||||
}
|
||||
}
|
||||
55
components/yunzhupaas/PopupAttr/index.vue
Normal file
55
components/yunzhupaas/PopupAttr/index.vue
Normal file
@@ -0,0 +1,55 @@
|
||||
<template>
|
||||
<YunzhupaasRelationFormAttr v-model="value" :showField="showField" :relationField="relationField" :isStorage='isStorage'
|
||||
:type="type" @change="onChange" />
|
||||
</template>
|
||||
<script>
|
||||
import RelationFormAttr from '../RelationFormAttr/index.vue'
|
||||
export default {
|
||||
name: 'yunzhupaas-popup-attr',
|
||||
inheritAttrs: false,
|
||||
props: {
|
||||
showField: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
relationField: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
type: {
|
||||
type: String,
|
||||
default: 'popupAttr'
|
||||
},
|
||||
isStorage: {
|
||||
type: Number,
|
||||
default: 0
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
value: '',
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
modelValue: {
|
||||
immediate: true,
|
||||
handler(val) {
|
||||
this.value = val
|
||||
}
|
||||
},
|
||||
value(val) {
|
||||
this.$emit('update:modelValue', val)
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
onChange(val) {
|
||||
this.$emit('change', val)
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.yunzhupaas-relation-attr {
|
||||
width: 100%;
|
||||
}
|
||||
</style>
|
||||
199
components/yunzhupaas/PopupSelect/index.vue
Normal file
199
components/yunzhupaas/PopupSelect/index.vue
Normal file
@@ -0,0 +1,199 @@
|
||||
<template>
|
||||
<view class="yunzhupaas-popup-select">
|
||||
<selectBox v-model="innerValue" :placeholder="placeholder" @openSelect="openSelect"></selectBox>
|
||||
<DisplayList :extraObj="extraObj" :extraOptions="extraOptions"
|
||||
v-if="Object.keys(extraObj).length && innerValue">
|
||||
</DisplayList>
|
||||
</view>
|
||||
</template>
|
||||
<script>
|
||||
import DisplayList from '@/components/displayList'
|
||||
import selectBox from '@/components/selectBox'
|
||||
import {
|
||||
getDataInterfaceDataInfoByIds
|
||||
} from '@/api/common.js'
|
||||
import {
|
||||
useBaseStore
|
||||
} from '@/store/modules/base'
|
||||
const baseStore = useBaseStore()
|
||||
export default {
|
||||
name: 'yunzhupaas-popup-select',
|
||||
components: {
|
||||
DisplayList,
|
||||
selectBox
|
||||
},
|
||||
props: {
|
||||
modelValue: {
|
||||
default: ''
|
||||
},
|
||||
formType: {
|
||||
type: String,
|
||||
default: 'select'
|
||||
},
|
||||
placeholder: {
|
||||
type: String,
|
||||
default: '请选择'
|
||||
},
|
||||
disabled: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
columnOptions: {
|
||||
type: Array,
|
||||
default: () => []
|
||||
},
|
||||
extraOptions: {
|
||||
type: Array,
|
||||
default: () => []
|
||||
},
|
||||
relationField: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
propsValue: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
popupTitle: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
interfaceId: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
hasPage: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
pageSize: {
|
||||
type: Number,
|
||||
default: 100000
|
||||
},
|
||||
vModel: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
rowIndex: {
|
||||
default: null
|
||||
},
|
||||
formData: {
|
||||
type: Object
|
||||
},
|
||||
templateJson: {
|
||||
type: Array,
|
||||
default: () => []
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
selectShow: false,
|
||||
innerValue: '',
|
||||
defaultValue: '',
|
||||
current: null,
|
||||
defaultOptions: [],
|
||||
firstVal: '',
|
||||
firstId: 0,
|
||||
selectData: [],
|
||||
extraObj: {}
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
modelValue(val) {
|
||||
this.setDefault()
|
||||
},
|
||||
},
|
||||
created() {
|
||||
uni.$on('popConfirm', (subVal, innerValue, list, selectData) => {
|
||||
this.confirm(subVal, innerValue, list, selectData)
|
||||
})
|
||||
this.setDefault()
|
||||
},
|
||||
methods: {
|
||||
setDefault() {
|
||||
if (this.modelValue) {
|
||||
if (!this.interfaceId) return
|
||||
let query = {
|
||||
ids: [this.modelValue],
|
||||
interfaceId: this.interfaceId,
|
||||
propsValue: this.propsValue,
|
||||
relationField: this.relationField,
|
||||
paramList: this.getParamList()
|
||||
}
|
||||
getDataInterfaceDataInfoByIds(this.interfaceId, query).then(res => {
|
||||
const data = res.data && res.data.length ? res.data[0] : {};
|
||||
this.extraObj = data
|
||||
this.innerValue = data[this.relationField]
|
||||
if (!this.vModel) return
|
||||
let relationData = baseStore.relationData
|
||||
relationData[this.vModel] = data
|
||||
baseStore.updateRelationData(relationData)
|
||||
})
|
||||
} else {
|
||||
this.innerValue = ''
|
||||
if (!this.vModel) return
|
||||
let relationData = baseStore.relationData
|
||||
relationData[this.vModel] = {}
|
||||
baseStore.updateRelationData(relationData)
|
||||
}
|
||||
},
|
||||
getParamList() {
|
||||
let templateJson = this.templateJson
|
||||
if (!this.formData) return templateJson
|
||||
for (let i = 0; i < templateJson.length; i++) {
|
||||
if (templateJson[i].relationField && templateJson[i].sourceType == 1) {
|
||||
if (templateJson[i].relationField.includes('-')) {
|
||||
let tableVModel = templateJson[i].relationField.split('-')[0]
|
||||
let childVModel = templateJson[i].relationField.split('-')[1]
|
||||
templateJson[i].defaultValue = this.formData[tableVModel] && this.formData[tableVModel][this
|
||||
.rowIndex
|
||||
] && this.formData[tableVModel][this.rowIndex][childVModel] || ''
|
||||
} else {
|
||||
templateJson[i].defaultValue = this.formData[templateJson[i].relationField] || ''
|
||||
}
|
||||
}
|
||||
}
|
||||
return templateJson
|
||||
},
|
||||
openSelect() {
|
||||
if (this.disabled) return
|
||||
const pageSize = this.hasPage ? this.pageSize : 100000
|
||||
let data = {
|
||||
columnOptions: this.columnOptions,
|
||||
relationField: this.relationField,
|
||||
type: 'popup',
|
||||
propsValue: this.propsValue,
|
||||
modelId: this.interfaceId,
|
||||
hasPage: this.hasPage,
|
||||
pageSize,
|
||||
id: [this.modelValue],
|
||||
vModel: this.vModel,
|
||||
popupTitle: this.popupTitle || '选择数据',
|
||||
innerValue: this.innerValue,
|
||||
paramList: this.getParamList(),
|
||||
selectData: this.selectData
|
||||
}
|
||||
uni.navigateTo({
|
||||
url: '/pages/apply/popSelect/index?data=' + encodeURIComponent(JSON.stringify(data))
|
||||
})
|
||||
},
|
||||
confirm(subVal, innerValue, vModel, selectData) {
|
||||
if (vModel === this.vModel) {
|
||||
this.firstVal = innerValue;
|
||||
this.firstId = subVal;
|
||||
this.innerValue = innerValue;
|
||||
this.extraObj = selectData
|
||||
this.$emit('update:modelValue', subVal)
|
||||
this.$emit('change', subVal, selectData)
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.yunzhupaas-popup-select {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
</style>
|
||||
176
components/yunzhupaas/PosSelect/Tree.vue
Normal file
176
components/yunzhupaas/PosSelect/Tree.vue
Normal file
@@ -0,0 +1,176 @@
|
||||
<template>
|
||||
<u-popup class="yunzhupaas-tree-select-popup" mode="right" :popup="false" v-model="showPopup" length="auto"
|
||||
:z-index="uZIndex" width="100%" @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">{{title}}</view>
|
||||
</view>
|
||||
<view class="yunzhupaas-tree-select-search">
|
||||
<u-search :placeholder="$t('app.apply.pleaseKeyword')" v-model="keyword" height="72"
|
||||
:show-action="false" @change="handleSearch" 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 selectList" :key="index"
|
||||
:text="!!list.lastFullName?list.lastFullName:list.fullName" 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"
|
||||
@node-click="handleNodeClick" :props="realProps" :show-node-icon="true" :show-radio="false"
|
||||
:filter-node-method="filterNode" :highlight-current="true" />
|
||||
</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'
|
||||
}
|
||||
import {
|
||||
getDepartmentSelector
|
||||
} from '@/api/common.js'
|
||||
export default {
|
||||
props: {
|
||||
options: {
|
||||
type: Array,
|
||||
default () {
|
||||
return [];
|
||||
}
|
||||
},
|
||||
selectedData: {
|
||||
type: Array,
|
||||
default () {
|
||||
return [];
|
||||
}
|
||||
},
|
||||
ids: {
|
||||
default: ''
|
||||
},
|
||||
title: {
|
||||
default: '选择'
|
||||
},
|
||||
modelValue: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
zIndex: {
|
||||
type: [String, Number],
|
||||
default: 0
|
||||
},
|
||||
props: {
|
||||
type: Object,
|
||||
default: () => ({
|
||||
label: 'fullName',
|
||||
value: 'id',
|
||||
icon: 'icon',
|
||||
children: 'children',
|
||||
isLeaf: 'isLeaf'
|
||||
})
|
||||
},
|
||||
multiple: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
moving: false,
|
||||
selectList: [],
|
||||
selectListId: [],
|
||||
newListId: [],
|
||||
keyword: '',
|
||||
showPopup: false
|
||||
};
|
||||
},
|
||||
watch: {
|
||||
// 在select弹起的时候,重新初始化所有数据
|
||||
modelValue: {
|
||||
handler(val) {
|
||||
this.showPopup = val
|
||||
if (val) setTimeout(() => this.init(), 10);
|
||||
},
|
||||
immediate: true
|
||||
},
|
||||
},
|
||||
computed: {
|
||||
uZIndex() {
|
||||
return this.zIndex ? this.zIndex : this.$u.zIndex.popup;
|
||||
},
|
||||
realProps() {
|
||||
return {
|
||||
...defaultProps,
|
||||
...this.props
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
init() {
|
||||
this.keyword = ""
|
||||
this.selectListId = JSON.parse(JSON.stringify(this.ids))
|
||||
if (!Array.isArray(this.ids)) this.selectListId = []
|
||||
this.selectList = JSON.parse(JSON.stringify(this.selectedData))
|
||||
},
|
||||
handleNodeClick(obj) {
|
||||
if (obj.data.type != 'position') return
|
||||
let isExist = false;
|
||||
if (!this.multiple) {
|
||||
this.selectList = [];
|
||||
this.selectListId = [];
|
||||
}
|
||||
for (var i = 0; i < this.selectList.length; i++) {
|
||||
if (this.selectList[i].id == obj.data.id) {
|
||||
isExist = true;
|
||||
break;
|
||||
}
|
||||
};
|
||||
!isExist && this.selectList.push(obj.data);
|
||||
!isExist && this.selectListId.push(obj.data[this.props.value]);
|
||||
},
|
||||
delSelect(index) {
|
||||
this.selectList.splice(index, 1);
|
||||
this.selectListId.splice(index, 1);
|
||||
},
|
||||
setCheckAll() {
|
||||
this.selectListId = [];
|
||||
this.selectList = [];
|
||||
this.$refs.tree.setCheckAll(false);
|
||||
},
|
||||
filterNode(value, data) {
|
||||
if (!value) return true;
|
||||
return data[this.realProps.label].indexOf(value) !== -1;
|
||||
},
|
||||
handleSearch(val) {
|
||||
this.$refs.tree && this.$refs.tree.filter(val)
|
||||
},
|
||||
handleConfirm() {
|
||||
this.$emit('confirm', this.selectList, this.selectListId);
|
||||
this.close();
|
||||
},
|
||||
close() {
|
||||
this.$emit('close', false);
|
||||
},
|
||||
}
|
||||
};
|
||||
</script>
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user