初始提交

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

View File

@@ -0,0 +1,59 @@
<template>
<u-alert-tips class="jnpf-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: 'jnpf-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">
.jnpf-alert {
width: 100%;
min-height: 72rpx;
}
</style>

View File

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

View File

@@ -0,0 +1,113 @@
<template>
<view class="jnpf-area-select">
<selectBox v-model="innerValue" :disabled='disabled' :placeholder="placeholder" @openSelect="openSelect"
:select-open="selectShow" >
</selectBox>
<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 selectBox from '@/components/selectBox'
import {
getProvinceSelectorInfoList
} from '@/api/common.js'
export default {
name: 'jnpf-area-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
},
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>
.jnpf-area-select {
width: 100%;
}
</style>

View File

@@ -0,0 +1,203 @@
<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>
<JnpfEmpty v-if="showList.length<1"></JnpfEmpty>
</u-popup>
</view>
</template>
<script>
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
},
showPopup: false,
value: '',
showList: [],
timer: ''
}
},
methods: {
init(val) {
this.showPopup = true
this.value = val
this.getDataInterfaceList()
},
getDataInterfaceList() {
this.showList = []
const paramList = this.getParamList()
let query = {
interfaceId: this.interfaceId,
relationField: this.relationField,
pageSize: 10000,
paramList
}
getPopSelect(this.interfaceId, query).then(res => {
let list = JSON.parse(JSON.stringify(res.data.list)) || []
if (list.length) list = this.unique(list, this.relationField)
this.showList = list.splice(0, this.total)
})
},
unique(arr, attrName) {
const res = new Map();
// 根据对象的某个属性值去重
return arr.filter(o => !res.has(o[attrName]) && res.set(o[attrName], 1));
},
getParamList() {
let templateJson = this.templateJson
for (let i = 0; i < templateJson.length; i++) {
if (templateJson[i].relationField && this.formData && templateJson[i].sourceType == 1) {
if (templateJson[i].relationField.includes('-')) {
let tableVModel = templateJson[i].relationField.split('-')[0]
let childVModel = templateJson[i].relationField.split('-')[1]
templateJson[i].defaultValue = this.formData[tableVModel] && this.formData[tableVModel][this
.rowIndex
] && this.formData[tableVModel][this.rowIndex][childVModel] || ''
} else {
templateJson[i].defaultValue = this.formData[templateJson[i].relationField] || ''
}
}
if (templateJson[i].relationField == '@keyword') templateJson[i].defaultValue = this.value
}
return templateJson
},
onInput(e) {
this.value = e
this.$emit('confirm', this.value);
this.timer && clearTimeout(this.timer);
this.timer = setTimeout(() => {
this.list = [];
this.getDataInterfaceList()
}, 300);
},
close() {
this.showPopup = false
},
selectThisItem(item) {
this.value = item[this.relationField];
this.$emit('confirm', this.value);
this.close()
}
}
}
</script>
<style lang="scss">
.search-popup-v {
.search-popup-b {
height: 158rpx;
.search-popup-h {
padding: 0 20rpx;
border-bottom: 1rpx solid #cbcbcb;
position: fixed;
width: 100%;
background-color: #fff;
z-index: 9;
text-align: center;
.search-popup-h-txt {
height: 86rpx;
width: 100%;
padding: 15rpx 0;
text-align: center;
line-height: 54rpx;
box-sizing: border-box;
font-size: 32rpx;
font-weight: 700;
letter-spacing: 2rpx;
.search-popup-h-icon {
float: right;
margin-top: 12rpx;
}
}
}
}
.search-popup-item {
width: 100%;
height: 100%;
z-index: 9997;
}
.search-notData {
width: 100%;
height: calc(100% - 160rpx);
background-color: #fff;
.notData-box {
width: 100%;
height: 100%;
justify-content: center;
align-items: center;
.notData-inner {
width: 280rpx;
height: 340rpx;
align-items: center;
.iconImg {
width: 100%;
height: 100%;
}
.notData-inner-text {
padding: 30rpx 0;
color: #909399;
}
}
}
}
}
</style>

View File

@@ -0,0 +1,139 @@
<template>
<view class="jnpf-auto-complete">
<selectBox v-model="innerValue" :disabled='disabled' :placeholder="placeholder" @openSelect="showSearch"
>
</selectBox>
<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';
import selectBox from '@/components/selectBox'
export default {
name: 'jnpf-auto-complete',
components: {
SearchForm,
selectBox
},
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">
.jnpf-auto-complete {
width: 100%;
.str-auto-complete-container {
width: 549rpx;
height: 360px;
border-radius: 8rpx;
box-shadow: 0rpx 0rpx 12rpx #dfe3e9;
position: absolute;
z-index: 9997;
background: #fff;
top: 94rpx;
left: 0;
right: 0;
overflow-y: scroll;
.str-auto-complete-mask {
width: 100%;
height: calc(100% - 90rpx);
position: fixed;
left: 0;
top: 0;
bottom: 0;
right: 0;
z-index: 9999;
}
.str-auto-complete-item {
position: relative;
padding: 10rpx;
z-index: 9999
}
}
.auto-complete-b {
width: 549rpx;
height: 360px;
z-index: 999;
position: absolute;
background-color: #fff;
border: 1px solid red;
top: 94rpx;
left: 0;
right: 0;
}
}
</style>

View File

@@ -0,0 +1,116 @@
<template>
<tki-barcode class="jnpf-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: 'jnpf-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>
.jnpf-barcode {
width: 100%;
overflow: hidden;
margin-bottom: -20rpx;
}
</style>

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -0,0 +1,60 @@
<template>
<view :class="'jnpf-button jnpf-button-'+align">
<u-button :custom-style="customStyle" :type="realType" :disabled="disabled"
@click="onClick">{{buttonText}}</u-button>
</view>
</template>
<script>
export default {
name: 'jnpf-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>
.jnpf-button {
width: 100%;
&.jnpf-button-left {
text-align: left;
}
&.jnpf-button-center {
text-align: center;
}
&.jnpf-button-right {
text-align: right;
}
}
</style>

View File

@@ -0,0 +1,303 @@
<template>
<view class="jnpf-calculation jnpf-calculation-right">
<view class="u-flex ">
<u-input input-align='right' v-model="innerValue" disabled placeholder='' />
<span class="unit" v-if="type === 2">{{ unitObj[dateCalConfig?.dateUnit] }}</span>
</view>
<view class="tips" v-if="isAmountChinese">{{rmbText}}</view>
</view>
</template>
<script>
import {
dayjs
} from '@/uni_modules/iRainna-dayjs/js_sdk/dayjs.min.js'
/**
* 中缀转后缀(逆波兰 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: 'jnpf-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
},
dateCalConfig: Object,
type: {
default: 1,
type: Number,
},
},
data() {
return {
innerValue: '',
RPN_EXP: toRPN(mergeNumberOfExps(this.expression)),
rmbText: '',
subValue: 0,
unitObj: {
d: '天',
h: '时',
M: '月',
m: '分',
s: '秒',
Y: '年',
},
startTime: new Date(),
endTime: new Date(),
}
},
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() {
if (this.type === 2) {
if (this.dateCalConfig?.startTimeType == 1) this.startTime = this.dateCalConfig.startTimeValue;
if (this.dateCalConfig?.startTimeType == 2) this.startTime = this.getFormVal(this.dateCalConfig
.startRelationField);
let endTime = new Date();
if (this.dateCalConfig?.endTimeType == 1) this.endTime = this.dateCalConfig.endTimeValue;
if (this.dateCalConfig?.endTimeType == 2) this.endTime = this.getFormVal(this.dateCalConfig
.endRelationField);
this.innerValue = this.calDateDiff(this.startTime, this.endTime, this.dateCalConfig?.dateUnit);
this.$emit('update:modelValue', this.innerValue)
} else {
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.jnpf.getAmountChinese(Number(this.subValue) || 0)
this.$emit('update:modelValue', this.subValue)
if (this.thousands) this.innerValue = this.numFormat(this.innerValue)
}
},
calDateDiff(startDate, endDate, unit) {
if (!startDate || !endDate) return '';
const start = dayjs(startDate);
let end = dayjs(endDate);
if (end.hour() === 0 && end.minute() === 0 && end.second() === 0 && this.dateCalConfig?.dateFormat ===
2) {
end = end.endOf('d');
}
const diff = end.diff(start, unit == 'Y' ? 'y' : unit, true);
const data = !!diff || diff === 0 ? this.getRoundValue(diff) : '';
return data;
},
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>
.jnpf-calculation {
width: 100%;
&.jnpf-calculation-right {
text-align: right;
}
.tips {
color: #999999;
line-height: 40rpx;
}
.unit {
padding-left: 10rpx;
}
}
</style>

View File

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

View File

@@ -0,0 +1,151 @@
<template>
<view class="jnpf-cascader">
<selectBox v-model="innerValue" :disabled='disabled' :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: 'jnpf-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>
.jnpf-cascader {
width: 100%;
}
</style>

View File

@@ -0,0 +1,97 @@
<template>
<u-checkbox-group class="jnpf-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]"
:class="{'jnpf-checkbox-disabled':disabled}">
{{item[props.label]}}
</u-checkbox>
</u-checkbox-group>
</template>
<script>
export default {
name: 'jnpf-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>
<style lang="scss" scoped>
:deep(.u-checkbox__icon-wrap--square) {
border-color: #D9D9D9 !important;
}
.jnpf-checkbox-disabled {
:deep(.u-checkbox__icon-wrap--disabled) {
background-color: #E6E6E6 !important;
border-color: #D9D9D9 !important;
}
}
</style>

View File

@@ -0,0 +1,129 @@
<template>
<view class="jnpf-color-picker">
<view class="color-box" :class="{'color-disabled':disabled}" @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: 'jnpf-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">
.jnpf-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;
&.color-disabled {
background-color: #E6E6E6 !important;
border-color: #D9D9D9 !important;
}
.colorVal {
width: 48rpx;
height: 48rpx;
border: 1px solid #999;
border-radius: 6rpx;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
background-color: #fff;
.colorVal-inner {
width: 100%;
height: 100%;
color: #c7c7c7;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
text-align: center;
}
}
}
}
</style>

View File

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

View File

@@ -0,0 +1,221 @@
<template>
<view class="jnpf-calculation jnpf-calculation-right">
<u-input input-align='right' :modelValue="jnpf.toDate(innerValue, format)" disabled placeholder='' />
</view>
</template>
<script>
import {
dayjs
} from '@/uni_modules/iRainna-dayjs/js_sdk/dayjs.min.js'
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: 'jnpf-date-calculation',
props: {
modelValue: {
type: [String, Number],
default: ''
},
expression: {
type: Array,
default: []
},
formData: {
type: Object,
default: {}
},
rowIndex: {
type: [String, Number],
default: ''
},
startRelationField: String,
startTimeValue: [String, Number],
startTimeType: {
default: 1,
type: Number,
},
format: {
default: 'yyyy-MM-dd',
type: String,
},
},
data() {
return {
innerValue: '',
startTime: new Date(),
}
},
computed: {
getExp() {
return mergeNumberOfExps(this.expression)
},
},
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: {
/**
* 计算表达式
*/
execRPN() {
const temp = this.getExp.map(t => typeof t === 'object' ? this.getFormVal(t.__vModel__) : t)
if (this.startTimeType == 1) this.startTime = this.startTimeValue;
if (this.startTimeType == 2) this.startTime = this.getFormVal(this.startRelationField);
this.innerValue = this.calcDate(this.startTime, this.getDateInfo(temp));
this.$emit('update:modelValue', this.innerValue)
},
getDateInfo(exp) {
let days = 0;
let months = 0;
let years = 0;
let hours = 0;
let minutes = 0;
let seconds = 0;
for (let i = 0; i < exp.length; i += 3) {
const sign = exp[i];
const value = Number.parseInt(exp[i + 1], 10);
const unit = exp[i + 2];
const factor = sign === '+' ? 1 : -1;
switch (unit) {
case 'd': {
days += factor * value;
break;
}
case 'h': {
hours += factor * value;
break;
}
case 'M': {
months += factor * value;
break;
}
case 'm': {
minutes += factor * value;
break;
}
case 's': {
seconds += factor * value;
break;
}
case 'Y': {
years += factor * value;
break;
}
}
}
return {
days,
hours,
minutes,
months,
seconds,
years
};
},
calcDate(date, change) {
if (!date) return '';
const newDate = new Date(date);
newDate.setFullYear(newDate.getFullYear() + change.years);
newDate.setMonth(newDate.getMonth() + change.months);
newDate.setDate(newDate.getDate() + change.days);
newDate.setHours(newDate.getHours() + change.hours);
newDate.setMinutes(newDate.getMinutes() + change.minutes);
newDate.setSeconds(newDate.getSeconds() + change.seconds);
return dayjs(newDate).startOf(this.jnpf.getDateTimeUnit(this.format)).valueOf();
},
/**
* 获取指定组件的值
*/
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>
.jnpf-calculation {
width: 100%;
&.jnpf-calculation-right {
text-align: right;
}
.tips {
color: #999999;
line-height: 40rpx;
}
.unit {
padding-left: 10rpx;
}
}
</style>

View File

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

View File

@@ -0,0 +1,210 @@
<template>
<view class="jnpf-date-time">
<selectBox v-model="innerValue" :disabled='disabled' :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: 'jnpf-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: {
handler(val) {
this.setDefault()
},
immediate: true,
deep: true
},
startTime(val) {
this.setMode()
},
endTime(val) {
this.setMode()
}
},
created() {
this.setMode()
},
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(Number(this.modelValue), this.formatObj[this.format])
this.defaultTime = this.$u.timeFormat(Number(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>
.jnpf-date-time {
width: 100%;
}
</style>

View File

@@ -0,0 +1,141 @@
<template>
<view class="jnpf-date-range">
<JnpfDatePicker v-if="type=='date'" v-model="startValue" placeholder="开始日期" :disabled="disabled"
inputType="text" scene="searchList" :format="format" @change="change" :defaultTime="startDefaultTime"
selectType='start' :key="key" ref="dateTime" />
<JnpfTimePicker v-else v-model="startValue" 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>
<JnpfDatePicker v-if="type=='date'" v-model="endValue" placeholder="结束日期" :disabled="disabled" inputType="text"
scene="searchList" :format="format" @change="change" :defaultTime="endDefaultTime" selectType='end'
:key="key+1" ref="dateTime" />
<JnpfTimePicker v-else v-model="endValue" placeholder="结束时间" :disabled="disabled" inputType="text"
scene="searchList" :format="format" @change="change" :defaultTime="endDefaultTime" selectType='end'
:key="key+1" ref="dateTime" />
</view>
</template>
<script>
const DEFAULT_FORMAT = 'yyyy-mm-dd hh:MM:ss';
export default {
name: 'jnpf-date-range',
props: {
modelValue: {
type: [Array, String],
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) {
// 当 modelValue 是有效数组时,更新本地状态
this.startValue = val[0];
this.endValue = val[1];
this.$set(this.datetimerangeObj, 'start', val[0]);
this.$set(this.datetimerangeObj, 'end', val[1]);
} else {
// 清空本地状态
this.startValue = '';
this.endValue = '';
this.datetimerangeObj = {};
this.datetimerange = [];
// 仅当 val 不是空数组时,才触发更新
if (!Array.isArray(val) || val.length !== 0) {
this.$emit('update:modelValue', []);
}
}
},
immediate: true,
deep: true
}
},
methods: {
change(e, type) {
this.datetimerange = [];
this.$set(this.datetimerangeObj, type, e || '');
// 始终使用开始时间作为参考时间
const startValue = this.datetimerangeObj.start;
this.setDefaultTime(startValue);
this.handleValue();
},
setDefaultTime(value) {
this.$refs.dateTime.defaultTime = this.type === 'time' ? value : this.$u.timeFormat(value, DEFAULT_FORMAT);
},
handleValue() {
const {
start,
end
} = this.datetimerangeObj;
this.datetimerange = [start, end];
if (this.shouldValidate()) {
if (start > end) {
this.handleInvalidRange();
return;
}
}
this.emitUpdate();
},
shouldValidate() {
return this.datetimerangeObj.start && this.datetimerangeObj.end;
},
handleInvalidRange() {
this.$u.toast('开始时间不能大于结束时间');
this.clearValues();
},
clearValues() {
setTimeout(() => {
this.startValue = "";
this.endValue = "";
this.datetimerangeObj = {};
this.datetimerange = [];
this.emitUpdate();
this.refreshComponent();
}, 500);
},
emitUpdate() {
this.$emit('update:modelValue', this.datetimerange);
},
refreshComponent() {
this.key = +new Date();
}
}
}
</script>

View File

@@ -0,0 +1,13 @@
<template>
<u-divider half-width="200" height="80">{{content}}</u-divider>
</template>
<script>
export default {
name: 'jnpf-divider',
props: {
content: {
default: ''
}
},
}
</script>

Binary file not shown.

File diff suppressed because one or more lines are too long

Binary file not shown.

View File

@@ -0,0 +1,274 @@
<template>
<view class="jnpf-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" :class="{'ql-disabled':disabled}" :placeholder="placeholder"
showImgSize showImgToolbar showImgResize @statuschange="onStatusChange" :read-only="disabled"
@ready="onEditorReady" @input="getValue">
</editor>
</view>
</template>
<view v-else class="editor-box">
<mp-html :content="modelValue" />
</view>
</view>
</template>
<script>
export default {
name: 'jnpf-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: 'jnpf-editor-' + this.jnpf.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;
}
.jnpf-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-disabled {
color: #9B9B9B !important;
}
}
.ql-active {
color: #06c;
}
}
</style>

View File

@@ -0,0 +1,63 @@
<template>
<view class="jnpf-empty" :style="{'z-index':zIndex}">
<view class="u-flex-col jnpf-empty-inner">
<image :src="getImageUrl" class="jnpf-empty-inner-img"></image>
<text class="jnpf-empty-inner-text">{{description||$t('common.noData')}}</text>
</view>
</view>
</template>
<script>
import resources from '@/libs/resources'
export default {
name: 'jnpf-empty',
props: {
zIndex: {
type: [String, Number],
default: 999
},
image: {
type: String,
default: ''
},
description: {
type: String,
default: ''
},
},
data() {
return {
icon: resources.message.nodata,
}
},
computed: {
getImageUrl() {
return this.image || this.icon
}
}
}
</script>
<style lang="scss">
.jnpf-empty {
display: flex;
justify-content: center;
align-items: center;
.jnpf-empty-inner {
width: 154px;
height: 170px;
align-items: center;
.jnpf-empty-inner-text {
padding: 30rpx 0;
color: #909399;
}
.jnpf-empty-inner-img {
width: 100%;
height: 100%;
}
}
}
</style>

View File

@@ -0,0 +1,160 @@
<template>
<u-popup class="jnpf-tree-select-popup" mode="right" v-model="showPopup" @close="close" :z-index="uZIndex"
width="100%">
<view class="jnpf-tree-select-body">
<view class="jnpf-tree-select-title">
<text class="icon-ym icon-ym-report-icon-preview-pagePre backIcon" @tap="close()"></text>
<view class="title">分组选择</view>
</view>
<view class="jnpf-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="jnpf-tree-selected">
<view class="jnpf-tree-selected-head">
<view>{{$t('component.jnpf.common.selected')}}({{selectedList.length||0}})</view>
<view v-if="multiple" class="clear-btn" @click="removeAll">
{{$t('component.jnpf.common.clearAll')}}
</view>
</view>
<view class="jnpf-tree-selected-box">
<scroll-view scroll-y="true" class="select-list">
<u-tag closeable @close="handleRemove(index)" v-for="(item,index) in selectedList" :key="index"
:text="item.fullName" class="u-selectTag" />
</scroll-view>
</view>
</view>
<view class="jnpf-tree-selected-line"></view>
<view class="jnpf-tree-selected-tabs">
<view class="tab-item tab-item-active">用户组</view>
</view>
<view class="jnpf-tree-select-tree">
<scroll-view :scroll-y="true" style="height: 100%">
<view class="jnpf-selcet-list" v-if="options.length">
<view class="jnpf-selcet-cell" v-for="item in options" :key="item.id"
@click.stop="handleNodeClick(item)">
<view class="jnpf-selcet-cell-action">
<lyCheckbox :type="multiple ? 'checkbox' : 'radio'"
:checked="selectedIds.includes(item.id)" />
</view>
<view class="jnpf-selcet-cell-name">
{{item.fullName}}
</view>
</view>
</view>
<Empty class="h-full" v-else />
</scroll-view>
</view>
<!-- 底部按钮 -->
<view class="jnpf-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>
import lyCheckbox from '@/components/ly-tree/components/ly-checkbox.vue';
import Empty from '../Empty/index.vue'
export default {
components: {
lyCheckbox,
Empty
},
props: {
getOptions: {
type: Function,
},
selectedData: {
type: Array,
default: () => []
},
// 通过双向绑定控制组件的弹出与收起
modelValue: {
type: Boolean,
default: false
},
// 弹出的z-index值
zIndex: {
type: [String, Number],
default: 99999
},
multiple: {
type: Boolean,
default: false
}
},
data() {
return {
moving: false,
selectedList: [],
selectedIds: [],
keyword: '',
showPopup: false,
options: [],
cacheData: [],
};
},
watch: {
modelValue: {
handler(val) {
this.showPopup = val
if (val) setTimeout(() => this.init(), 10);
},
immediate: true
},
selectedList: {
handler(val) {
this.selectedIds = val.map((o) => o.id);
},
deep: true
},
},
computed: {
uZIndex() {
// 如果用户有传递z-index值优先使用
return this.zIndex ? this.zIndex : this.$u.zIndex.popup;
},
},
methods: {
init() {
this.keyword = ''
this.selectedList = JSON.parse(JSON.stringify(this.selectedData))
if (this.getOptions) {
this.getOptions().then(res => {
this.options = res || []
this.cacheData = res || []
})
} else {
this.options = []
this.cacheData = []
}
},
handleNodeClick(data) {
const index = this.selectedList.findIndex((o) => o.id === data.id);
if (index !== -1) return this.selectedList.splice(index, 1);
this.multiple ? this.selectedList.push(data) : (this.selectedList = [data]);
},
handleRemove(index) {
this.selectedList.splice(index, 1);
},
removeAll() {
this.selectedList = [];
},
handleConfirm() {
this.$emit('confirm', this.selectedList, this.selectedIds);
this.close();
},
close() {
this.$emit('close');
},
handleSearch(val) {
this.options = this.cacheData.filter((o) => o.fullName.includes(val));
},
}
};
</script>

View File

@@ -0,0 +1,136 @@
<template>
<view class="jnpf-group-select w-full">
<selectBox v-model="innerValue" :placeholder="placeholder" @openSelect="openSelect" :select-open="selectShow"
:disabled="disabled">
</selectBox>
<SelectPopup v-model="selectShow" :getOptions="getOptions" :multiple="multiple" :selectedData="selectedData"
@close="handleClose" @confirm="handleConfirm" />
</view>
</template>
<script>
import SelectPopup from './SelectPopup';
import selectBox from '@/components/selectBox'
import {
useBaseStore
} from '@/store/modules/base'
import {
getGroupCondition
} from '@/api/common'
const baseStore = useBaseStore()
export default {
name: 'jnpf-group-select',
components: {
SelectPopup,
selectBox
},
props: {
modelValue: {
default: ''
},
placeholder: {
type: String,
default: '请选择'
},
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: [],
}
},
watch: {
modelValue: {
handler() {
this.setDefault()
},
immediate: true
},
allList: {
handler() {
this.setDefault()
},
deep: true,
},
},
created() {
this.initData()
},
methods: {
async initData() {
this.allList = await baseStore.getGroupList()
},
setDefault() {
if (!this.modelValue || !this.modelValue.length) return this.setNullValue();
let 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]) {
selectedData.push(this.allList[j])
break inner
}
}
}
this.selectedData = selectedData
this.innerValue = this.selectedData.map(o => o.fullName).join();
},
getOptions() {
return new Promise((resolve, reject) => {
if (this.selectType === 'custom') {
const query = {
ids: this.ableIds
}
getGroupCondition(query).then(res => {
resolve(res.data || [])
}).catch(error => {
reject(error)
})
} else {
baseStore.getGroupList().then(res => {
resolve(res || [])
})
}
})
},
setNullValue() {
this.innerValue = '';
this.selectedData = [];
},
openSelect() {
if (this.disabled) return
this.selectShow = true
},
handleConfirm(selectedData, selectedIds) {
if (!this.multiple) {
this.$emit('update:modelValue', selectedIds[0])
this.$emit('change', selectedIds[0], selectedData[0])
} else {
this.$emit('update:modelValue', selectedIds)
this.$emit('change', selectedIds, selectedData)
}
},
handleClose() {
this.selectShow = false
}
}
}
</script>

View File

@@ -0,0 +1,40 @@
<template>
<view class="jnpf-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: 'jnpf-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>
.jnpf-group-title {
width: 100%;
color: #333333;
font-size: 32rpx;
line-height: 70rpx;
margin: 0;
padding: 0 20rpx;
}
</style>

View File

@@ -0,0 +1,234 @@
<template>
<view class="jnpf-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" :class="{'input-disabled':disabled}" />
</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,disabled:disabled }"
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: 'jnpf-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">
.jnpf-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-disabled {
:deep(.uni-input-placeholder) {
color: #9B9B9B !important;
}
:deep(.uni-input-input) {
color: #9B9B9B !important;
}
}
}
.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;
}
&.disabled {
background-color: #ebedf0;
}
&.ellipsis {
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}
&.detail-text-left {
text-align: left;
}
}
}
</style>

View 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
};
}

View File

@@ -0,0 +1,260 @@
<template>
<view class="jnpf-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" :class="{'input-disabled':disabled}"
: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?jnpf.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: 'jnpf-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) {
if (val == null || val == undefined) return;
this.setValue(val)
},
immediate: true
},
getChineseName(val) {
uni.$emit('initCollapse')
}
},
computed: {
getChineseName() {
if (!this.isAmountChinese || (!this.getNumberValue && this.getNumberValue !== 0)) return ""
return this.jnpf.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.jnpf.thousandsFormat(this.innerValue)
},
onChange() {
this.setValue(this.innerValue)
this.$nextTick(() => {
this.emitValueChanges(this.innerValue)
})
},
emitValueChanges(value) {
// 统一事件触发逻辑
this.$emit('update:modelValue', value)
this.$emit('change', value)
},
onInputChange() {
this.$nextTick(() => {
if (this.innerValue == null || this.innerValue == undefined) return;
if (this.innerValue < this.min || this.innerValue > this.max) return;
this.emitValueChanges(this.innerValue)
})
},
onNumberBlur() {
this.key = +new Date()
this.setValue(this.innerValue)
this.$emit('blur', this.innerValue)
},
onBlur(val) {
this.setValue(this.getNumberValue)
this.$nextTick(() => {
if (this.getNumberValue > this.min && this.getNumberValue < this.max) return;
this.$emit('blur', this.getNumberValue)
this.emitValueChanges(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>
.jnpf-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-disabled {
:deep(.uni-input-placeholder) {
color: #9B9B9B !important;
}
:deep(.uni-input-input) {
color: #9B9B9B !important;
}
}
.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>

View File

@@ -0,0 +1,62 @@
<template>
<view class="jnpf-link" :style="textStyle" @click="handleClick()">
<text>{{content}}</text>
</view>
</template>
<script>
export default {
name: 'jnpf-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>
.jnpf-link {
width: 100%;
color: #1890ff;
text-align: right;
}
</style>

View File

@@ -0,0 +1,274 @@
<template>
<view class="jnpf-location">
<u-button class="jnpf-location-btn" :class="{'jnpf-location-disabled':disabled}" @click="handleLocation"
v-if="!detailed" size="mini">
<u-icon class="jnpf-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" :class="{'disabled':disabled}">{{ 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: 'jnpf-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
},
buttonText: {
type: String,
default: '添加定位'
}
},
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.jnpf.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.jnpf.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">
.jnpf-location {
width: 100%;
display: flex;
flex-wrap: wrap;
justify-content: flex-end;
.jnpf-location-btn {
margin: unset;
&.jnpf-location-disabled {
background-color: #E6E6E6 !important;
border-color: #D9D9D9 !important;
color: #9B9B9B !important;
}
.jnpf-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;
&.disabled {
color: #9B9B9B !important;
}
}
}
.location-card-actions {
color: rgb(135, 143, 149);
cursor: pointer;
flex-shrink: 0;
}
}
.errTitle {
color: $u-type-error
}
}
</style>

View File

@@ -0,0 +1,76 @@
<template>
<view class="jnpf-num-range">
<u-input input-align='right' v-model="min" :placeholder="$t('component.jnpf.numberRange.min')" type="number" @blur="onblur($event,'min')" />
<text class="separator">-</text>
<u-input input-align='right' v-model="max" :placeholder="$t('component.jnpf.numberRange.max')" type="number" @blur="onblur($event,'max')" />
</view>
</template>
<script>
export default {
name: 'jnpf-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>
.jnpf-num-range {
width: 100%;
display: flex;
justify-content: space-between;
align-items: center;
.separator {
margin: 0 20rpx;
flex-shrink: 0;
}
}
</style>

View File

@@ -0,0 +1,54 @@
<template>
<u-input input-align='right' :modelValue="modelValue" placeholder="系统自动生成" disabled />
</template>
<script>
export default {
name: 'jnpf-open-data',
props: {
modelValue: {
type: String,
default: ''
},
/**
* currUser - 当前用户
* currTime - 当前时间
* currOrganize - 所属组织
* currPosition - 所属岗位
*/
type: {
type: String,
default: ''
},
},
data() {
return {
innerValue: '',
userInfo: ''
}
},
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.userInfo.organizeList?.length) {
const list = this.userInfo.organizeList.map((o) => o.treeName);
this.innerValue = list.join(',');
}
if (this.type === 'currPosition' && this.userInfo.positionList?.length) {
const list = this.userInfo.positionList.map((o) => o.treeName);
this.innerValue = list.join(',');
}
}
}
}
</script>

View File

@@ -0,0 +1,297 @@
<template>
<u-popup class="jnpf-tree-select-popup" mode="right" v-model="showPopup" width="100%" @close="close">
<view class="jnpf-tree-select-body">
<view class="jnpf-tree-select-title">
<text class="icon-ym icon-ym-report-icon-preview-pagePre backIcon" @tap="close()"></text>
<view class="title">组织选择</view>
</view>
<view class="jnpf-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="jnpf-tree-selected">
<view class="jnpf-tree-selected-head">
<view>{{$t('component.jnpf.common.selected')}}({{selectedList.length||0}})</view>
<view v-if="multiple" class="clear-btn" @click="setCheckAll">
{{$t('component.jnpf.common.clearAll')}}
</view>
</view>
<view class="jnpf-tree-selected-box">
<scroll-view scroll-y="true" class="select-list">
<u-tag closeable @close="delSelect(index)" v-for="(item,index) in selectedList" :key="index"
:text="item.orgNameTree" class="u-selectTag" />
</scroll-view>
</view>
</view>
<view class="jnpf-tree-selected-line"></view>
<view class="jnpf-tree-selected-tabs">
<view class="tab-item" :class="{'tab-item-active':activeKey==='1'}" @click="toggloActive('1')">组织构架
</view>
<view class="tab-item" :class="{'tab-item-active':activeKey==='2'}" @click="toggloActive('2')"
v-if="selectType === 'all'">
当前组织
</view>
</view>
<view class="jnpf-tree-select-tree">
<scroll-view :scroll-y="true" style="height: 100%" v-if="activeKey==='1' && !hasPage">
<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 show-node-icon @node-click="handleTreeNodeClick"
:show-checkbox="multiple" :show-radio="!multiple" :expandOnClickNode="false"
:checkOnClickNode="true" :expandOnCheckNode="false" checkStrictly 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="handleTreeNodeClick" :show-checkbox="multiple" :show-radio="!multiple"
:expandOnClickNode="false" :checkOnClickNode="true" :expandOnCheckNode="false" checkStrictly />
</scroll-view>
<scroll-view :scroll-y="true" style="height: 100%" :refresher-enabled="false" :refresher-threshold="100"
:scroll-with-animation='true' :refresher-triggered="triggered" @scrolltolower="handleScrollToLower"
v-if="activeKey==='2'|| (activeKey==='1' && hasPage)">
<view class="jnpf-selcet-list" v-if="list.length">
<view class="jnpf-selcet-cell" v-for="item in list" :key="item.id"
@click.stop="handleNodeClick(item)">
<view class="jnpf-selcet-cell-action">
<lyCheckbox :type="multiple ? 'checkbox' : 'radio'"
:checked="selectedIds.includes(item.id)" />
</view>
<view class="jnpf-selcet-cell-name">
{{item.orgNameTree}}
</view>
</view>
</view>
<Empty class="h-full" v-else />
</scroll-view>
</view>
<!-- 底部按钮 -->
<view class="jnpf-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>
import {
getOrgByOrganizeCondition,
getOrganizeSelector
} from '@/api/common'
import lyCheckbox from '@/components/ly-tree/components/ly-checkbox.vue';
import Empty from '../Empty/index.vue'
const defaultProps = {
label: 'fullName',
value: 'id',
icon: 'icon',
children: 'children'
}
export default {
props: {
selectedData: {
type: Array,
default: () => []
},
ableIds: {
type: Array,
default: () => []
},
selectType: {
type: String,
default: 'all'
},
// 通过双向绑定控制组件的弹出与收起
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
}
},
components: {
lyCheckbox,
Empty
},
data() {
return {
moving: false,
selectedList: [],
selectedIds: [],
keyword: '',
showPopup: false,
options: [],
lazyOptions: [],
activeKey: '1',
hasPage: false,
pagination: {
hasPage: 1,
currentPage: 1,
pageSize: 20
},
triggered: false,
finish: false,
list: []
};
},
watch: {
// 在select弹起的时候重新初始化所有数据
modelValue: {
handler(val) {
this.showPopup = val
if (!val) this.activeKey = ''
if (val) setTimeout(() => this.init(), 10);
},
immediate: true
},
selectedList: {
handler(val) {
this.selectedIds = val.map((o) => o.id);
this.$refs.tree && this.$refs.tree.setCheckedKeys(this.selectedIds)
},
deep: true
},
},
computed: {
uZIndex() {
// 如果用户有传递z-index值优先使用
return this.zIndex ? this.zIndex : this.$u.zIndex.popup;
},
realProps() {
return {
...defaultProps,
...this.props
}
},
getCurrOrgList() {
const userInfo = uni.getStorageSync('userInfo') || {}
const list = (userInfo.organizeList || []).map((o) => ({
...o,
orgNameTree: o.treeName
}))
return list
}
},
methods: {
init() {
this.keyword = ""
this.hasPage = 0
this.activeKey = '1'
this.finish = false
this.pagination.currentPage = 1
this.$nextTick(() => {
this.triggered = true
})
this.selectedList = JSON.parse(JSON.stringify(this.selectedData))
if (this.selectType !== 'all') this.getConditionOptions()
},
getConditionOptions() {
if (!this.ableIds.length) return
const query = {
ids: this.ableIds
}
getOrgByOrganizeCondition(query).then(res => {
this.options = res.data.list || []
this.$refs.tree && this.$refs.tree.setCheckedKeys(this.selectedIds)
})
},
filterNode(value, data) {
if (!value) return true;
return data[this.realProps.label].indexOf(value) !== -1;
},
loadNode(node, resolve) {
const id = node.key || '0'
const data = {
keyword: '',
parentId: id
}
getOrganizeSelector(data).then(res => {
resolve(res.data?.list)
this.$refs.tree && this.$refs.tree.setCheckedKeys(this.selectedIds)
})
},
handleScrollToLower() {
if (this.finish || this.activeKey === '2') return
this.getTreeData()
},
getTreeData() {
let data = {
keyword: this.keyword,
parentId: '0',
...this.pagination
}
getOrganizeSelector(data).then(res => {
const list = res.data.list || []
if (list.length < this.pagination.pageSize) this.finish = true;
this.list = this.list.concat(list);
this.pagination.currentPage++
})
},
onTreeCheck(item) {
this.handleTreeNodeClick(item);
},
handleTreeNodeClick(item) {
const data = item.data
this.handleNodeClick(data)
},
handleNodeClick(data) {
const index = this.selectedList.findIndex((o) => o.id === data.id);
if (index !== -1) return this.selectedList.splice(index, 1);
this.multiple ? this.selectedList.push(data) : (this.selectedList = [data]);
},
delSelect(index) {
this.selectedList.splice(index, 1);
},
setCheckAll() {
this.selectedIds = []
this.selectedList = []
},
handleConfirm() {
this.$emit('confirm', this.selectedList, this.selectedIds);
this.close();
},
close() {
this.$emit('close', false);
},
toggloActive(key) {
if (this.activeKey === key) return
this.keyword = ''
this.$nextTick(() => {
this.activeKey = key
if (this.activeKey === '2') this.list = this.getCurrOrgList
})
},
handleSearch(val) {
this.keyword = val
if (this.selectType !== 'all') return this.$refs.tree && this.$refs.tree.filter(val)
this.hasPage = !!val
this.list = []
if (this.activeKey != '1') this.activeKey = '1'
this.$nextTick(() => {
if (this.keyword) {
this.pagination.currentPage = 1
this.finish = false
this.$u.debounce(this.getTreeData, 300)
}
})
},
}
};
</script>

View File

@@ -0,0 +1,97 @@
<template>
<view class="jnpf-organize-select w-full">
<selectBox v-model="innerValue" :placeholder="placeholder" @openSelect="openSelect" :select-open="selectShow"
:disabled="disabled" />
<SelectPopup v-model="selectShow" :multiple="multiple" :selectedData="selectedData" @close="handleClose"
@confirm="handleConfirm" :selectType="selectType" :ableIds="ableIds" />
</view>
</template>
<script>
import SelectPopup from './SelectPopup';
import selectBox from '@/components/selectBox'
import {
getOrgSelectedList
} from '@/api/common'
export default {
name: 'jnpf-organize-select',
components: {
SelectPopup,
selectBox
},
props: {
modelValue: {
default: ''
},
placeholder: {
type: String,
default: '请选择'
},
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: [],
}
},
watch: {
modelValue: {
handler() {
this.setDefault()
},
immediate: true
},
},
methods: {
setDefault() {
if (!this.modelValue || !this.modelValue.length) return this.setNullValue();
const ids = this.multiple ? this.modelValue : [this.modelValue];
getOrgSelectedList({
ids
}).then((res) => {
if (!this.modelValue || !this.modelValue.length) return this.setNullValue();
const selectedData = res.data.list || []
this.selectedData = selectedData
this.innerValue = this.selectedData.map(o => o.orgNameTree).join();
});
},
setNullValue() {
this.innerValue = '';
this.selectedData = [];
},
openSelect() {
if (this.disabled) return
this.selectShow = true
},
handleConfirm(selectedData, selectedIds) {
if (!this.multiple) {
this.$emit('update:modelValue', selectedIds[0])
this.$emit('change', selectedIds[0], selectedData[0])
} else {
this.$emit('update:modelValue', selectedIds)
this.$emit('change', selectedIds, selectedData)
}
},
handleClose() {
this.selectShow = false
}
}
}
</script>

View File

@@ -0,0 +1,455 @@
<template>
<JnpfText v-if="config.jnpfKey=='text'" :content="item.content" :textStyle="item.textStyle" />
<JnpfGroupTitle v-else-if="config.jnpfKey=='groupTitle'" :content="item.content"
:content-position="item.contentPosition" :helpMessage="item.helpMessage" @groupIcon="clickIcon(item)" />
<JnpfDivider v-else-if="config.jnpfKey=='divider'" :content="item.content" />
<view class="jnpf-card" v-else-if="config.jnpfKey==='card'||config.jnpfKey==='row'">
<view class="jnpf-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.jnpfKey==='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="jnpf-tab" v-else-if="config.jnpfKey==='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.jnpfKey==='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 && 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.jnpfKey==='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.jnpfKey=='popupSelect' || config.jnpfKey=='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)">
<!-- 弹窗选择 -->
<JnpfPopupSelect v-if="config.jnpfKey=='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__ + '_jnpfTable_' + config.tableName + (config.isSubTable ? '0' : '1') : config.__vModel__"
:popupTitle="item.popupTitle" @change="onChange" />
<!-- 关联表单 -->
<JnpfRelationForm v-if="config.jnpfKey=='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__ + '_jnpfTable_' + 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)">
<JnpfInput v-if="config.jnpfKey=='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" />
<JnpfTextarea v-if="config.jnpfKey=='textarea'" v-model="value" :placeholder="item.placeholder"
:maxlength="item.maxlength" :showCount="item.showCount" :disabled="item.disabled"
:clearable='item.clearable' @change="onChange" @blur="onBlur" />
<!--数字输入步进器-->
<JnpfInputNumber v-if="config.jnpfKey=='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" />
<!-- 开关-->
<JnpfSwitch v-if="config.jnpfKey=='switch'" v-model="value" :disabled="item.disabled" @change="onChange" />
<!-- 单选框组 -->
<JnpfRadio v-if="config.jnpfKey=='radio'" v-model="value" :options="item.options" :props="item.props"
:disabled="item.disabled" :direction='item.direction' @change="onChange" />
<!-- 多选框组 -->
<JnpfCheckbox v-if="config.jnpfKey=='checkbox'" v-model="value" :options="item.options" :props="item.props"
:disabled="item.disabled" :direction='item.direction' @change="onChange" />
<!-- 下拉选择 -->
<JnpfSelect v-if="config.jnpfKey=='select'" v-model="value" :placeholder="item.placeholder"
:options="item.options" :props="item.props" :multiple="item.multiple" :disabled="item.disabled"
@change="onChange" :filterable="item.filterable" />
<!-- 级联选择 -->
<JnpfCascader v-if="config.jnpfKey=='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" />
<JnpfDatePicker v-if="config.jnpfKey=='datePicker'" v-model="value" :placeholder="item.placeholder"
:disabled="item.disabled" :format="item.format" :startTime="item.startTime" :endTime='item.endTime'
@change="onChange" />
<JnpfTimePicker v-if="config.jnpfKey=='timePicker'" v-model="value" :placeholder="item.placeholder"
:disabled="item.disabled" :format="item.format" :startTime="item.startTime" :endTime='item.endTime'
@change="onChange" />
<!-- #ifndef APP-HARMONY -->
<JnpfUploadFile v-if="config.jnpfKey=='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" :buttonText='item.buttonText' />
<!-- #endif -->
<!-- #ifdef APP-HARMONY -->
<JnpfUploadFileH v-if="config.jnpfKey=='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" :buttonText='item.buttonText' />
<!-- #endif -->
<!-- 图片上传 -->
<JnpfUploadImg v-if="config.jnpfKey=='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" :buttonText='item.buttonText' />
<!-- 颜色选择 -->
<JnpfColorPicker v-if="config.jnpfKey=='colorPicker'" v-model="value" :colorFormat="item.colorFormat"
:disabled="item.disabled" @change="onChange" />
<JnpfRate v-if="config.jnpfKey=='rate'" v-model="value" :max="item.count" :allowHalf="item.allowHalf"
:disabled="item.disabled" @change="onChange" />
<JnpfSlider v-if="config.jnpfKey=='slider'" v-model="value" :step="item.step" :min="item.min" :max="item.max"
:disabled="item.disabled" @change="onChange" />
<JnpfBarcode v-if="config.jnpfKey=='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" />
<JnpfQrcode v-if="config.jnpfKey=='qrcode'" :staticText="item.staticText" :width="item.width"
:dataType="item.dataType" :colorDark="item.colorDark" :colorLight="item.colorLight"
:relationField="item.relationField" :formData="formData" />
<JnpfOrganizeSelect v-if="config.jnpfKey=='organizeSelect'" v-model="value" :multiple="item.multiple"
:placeholder="item.placeholder" :disabled="item.disabled" :ableIds="item.ableIds"
:selectType="item.selectType" @change="onChange" />
<JnpfPosSelect v-if="config.jnpfKey=='posSelect'" v-model="value" :multiple="item.multiple"
:placeholder="item.placeholder" :disabled="item.disabled" :ableIds="item.ableIds"
:selectType="item.selectType" @change="onChange" />
<JnpfUserSelect v-if="config.jnpfKey=='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" />
<JnpfUsersSelect v-if="config.jnpfKey=='usersSelect'" v-model="value" :placeholder="item.placeholder"
:disabled="item.disabled" :clearable="item.clearable" @change="onChange" />
<JnpfRoleSelect v-if="config.jnpfKey=='roleSelect'" v-model="value" :vModel='item.__vModel__'
:multiple="item.multiple" :disabled="item.disabled" :placeholder="item.placeholder" :ableIds="item.ableIds"
:selectType="item.selectType" @change="onChange" />
<JnpfGroupSelect v-if="config.jnpfKey=='groupSelect'" v-model="value" :vModel='item.__vModel__'
:multiple="item.multiple" :disabled="item.disabled" :ableIds="item.ableIds" :selectType="item.selectType"
:placeholder="item.placeholder" @change="onChange" />
<!-- 下拉树形 -->
<JnpfTreeSelect v-if="config.jnpfKey=='treeSelect'" v-model="value" :options="item.options" :props="item.props"
:multiple="item.multiple" :placeholder="item.placeholder" :disabled="item.disabled"
:filterable="item.filterable" @change="onChange" />
<JnpfAutoComplete v-if="config.jnpfKey=='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" />
<JnpfAreaSelect v-if="config.jnpfKey=='areaSelect'" v-model="value" :placeholder="item.placeholder"
:level="item.level" :disabled="item.disabled" :multiple="item.multiple" @change="onChange" />
<JnpfRelationFormAttr v-if="config.jnpfKey=='relationFormAttr'" v-model="value" :showField="item.showField"
:relationField="item.relationField" :isStorage='item.isStorage' @change="onChange" />
<!-- 下拉表格 -->
<JnpfPopupSelect v-if="config.jnpfKey=='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__ + '_jnpfTable_' + config.tableName + (config.isSubTable ? '0' : '1') : config.__vModel__"
:popupTitle="item.popupTitle" :multiple="item.multiple" @change="onChange" />
<JnpfPopupAttr v-if="config.jnpfKey=='popupAttr'" v-model="value" :showField="item.showField"
:relationField="item.relationField" :isStorage='item.isStorage' @change="onChange" />
<!-- 计算公式 -->
<JnpfCalculate v-if="config.jnpfKey=='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"
:dateCalConfig="item.dateCalConfig" :type="item.type" />
<!-- 日期计算公式 -->
<JnpfDateCalculate v-if="config.jnpfKey=='dateCalculate'" v-model="value" :expression='item.expression'
:vModel='item.__vModel__' :config='item.__config__' :formData='formData'
:startRelationField="item.startRelationField" :startTimeValue="item.startTimeValue"
:startTimeType="item.startTimeType" :format="item.format" />
<!-- 签名 -->
<JnpfSign v-if="config.jnpfKey=='sign'" v-model="value" :disabled="item.disabled" :fieldKey="item.__vModel__"
@change="onChange" :isInvoke="item.isInvoke" />
<!-- 签章 -->
<JnpfSignature v-if="config.jnpfKey=='signature'" v-model="value" :disabled="item.disabled" @change="onChange"
:ableIds="item.ableIds" />
<JnpfLocation v-if="config.jnpfKey=='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" />
<JnpfOpenData v-if="isSystem" v-model="value" :type="item.type" :showLevel="item.showLevel" />
<JnpfInput v-if="config.jnpfKey==='modifyUser'||config.jnpfKey==='modifyTime'" v-model="value"
placeholder="系统自动生成" disabled />
<!--start labelwidth=0-->
<JnpfLink v-if="config.jnpfKey=='link'" :content="item.content" :href="item.href" :target='item.target'
:textStyle="item.textStyle" @click="onClick" />
<!-- 富文本 -->
<JnpfEditor v-if="config.jnpfKey=='editor'" v-model="value" :disabled="item.disabled"
:placeholder="item.placeholder" />
<JnpfButton v-if="config.jnpfKey=='button'" :buttonText="item.buttonText" :align="item.align" :type="item.type"
:disabled="item.disabled" @click="onClick($event)" />
<JnpfAlert v-if="config.jnpfKey=='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', 'currPosition', 'billRule']
const specialList = ['link', 'editor', 'button', 'alert']
export default {
name: 'Item',
inject: ["parameter"],
emits: ['input', 'clickIcon', 'clickFun', 'collapseChange', 'tab-change', 'onCollapseChange'],
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.jnpfKey) > -1
},
labelWidth() {
if (specialList.indexOf(this.config.jnpfKey) > -1) return 0
return this.config.labelWidth ? this.config.labelWidth * 1.5 : undefined
},
label() {
return this.config.showLabel && specialList.indexOf(this.config.jnpfKey) < 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.jnpfKey === '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.jnpfKey)) {
if (item.contentI18nCode) item.content = this.$t(item.contentI18nCode);
if (item.helpMessageI18nCode) item.helpMessage = this.$t(item.helpMessageI18nCode);
}
if (config.jnpfKey === 'button' && item.buttonTextI18nCode) item.buttonText = this.$t(item
.buttonTextI18nCode);
if (config.jnpfKey === '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.jnpfKey === 'card') {
if (item.headerI18nCode) item.header = this.$t(item.headerI18nCode);
}
if (['tab', 'collapse', 'steps'].includes(config.jnpfKey)) {
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.jnpfKey === '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.jnpfKey === 'steps') this.stepCurrent = this.config.active
if (this.config.jnpfKey != '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__.jnpfKey)) {
this.setTransferFormData(data || val, this.item.__config__, this.item.__config__.jnpfKey)
}
this.$nextTick(() => {
uni.$emit('subChange', this.item, data || val)
})
},
setScriptFunc(val, data, type = 'change') {
if (data && data.on && data.on[type]) {
const func = this.jnpf.getScriptFunc(data.on[type]);
if (!func) return
func.call(this, {
data: val,
...this.parameter
})
}
},
setTransferFormData(data, config, jnpfKey) {
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>

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,765 @@
<template>
<u-form class="jnpf-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.jnpf.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.jnpf.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.jnpfKey == '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.jnpfKey == 'relationFormAttr' || config.jnpfKey == 'popupAttr') {
const relationKey = cur.relationField.split("_jnpfTable_")[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__.jnpfKey == 'table' && !cur.__config__.noShow) {
tableRefs[cur.__vModel__] = cur
}
}
if (config.children && cur.__config__.jnpfKey !== 'table') {
this.initFormData(config.children, formData, tableRefs)
}
})
},
buildOptions(componentList, data, formData) {
componentList.forEach(cur => {
const config = cur.__config__
if (dyOptionsList.indexOf(config.jnpfKey) > -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.jnpf.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.jnpfKey !== 'table') this.buildOptions(config.children, data,
formData)
})
},
buildRules(componentList, rules) {
componentList.forEach(cur => {
const config = cur.__config__
const jnpfKey = config.jnpfKey
const useNumList = ['inputNumber', 'switch', 'datePicker', 'rate', 'slider', 'calculate']
const useArrayList = ['select', 'posSelect', 'userSelect', 'treeSelect', 'popupTableSelect',
'organizeSelect'
]
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(jnpfKey)) item.type = 'number'
if (useArrayList.includes(jnpfKey) && cur.multiple) item.type = 'array'
if (jnpfKey === 'usersSelect' || jnpfKey === 'areaSelect' || jnpfKey ===
'checkbox' || jnpfKey === 'cascader') item.type = 'array'
if (jnpfKey === 'relationForm' || jnpfKey === 'popupSelect' || jnpfKey ===
'select' || jnpfKey === 'radio' || jnpfKey === 'treeSelect') {
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 && jnpfKey !== 'table') this.buildRules(this.$u.deepClone(config.children),
rules)
})
},
/**
* cur 对象
* relationField 关联的数据项
* relations 包含所有相关的配置信息
* opType 类型
**/
addRelationItem(cur, relationField, relations, opType) {
let realVModel = cur.__config__.isSubTable ? `${cur.__config__.parentVModel}-${cur.__vModel__}` : cur
.__vModel__;
let item = {
...cur,
realVModel,
opType
};
if (relations.hasOwnProperty(relationField)) {
if (!relations[relationField].some(o => o.realVModel === item.realVModel)) {
relations[relationField].push(item);
}
} else {
relations[relationField] = [item];
}
},
/**
* config 对象
* type 开始或者结束类型
* target 目标字段
* value 开始或者结束时间值
**/
processTimeRule(config, type, target, value) {
let time;
switch (type) {
case 1:
return value || (type === 'startTime' ? '00:00:00' : '23:59:59');
case 3:
return this.jnpf.toDate(new Date(), config.format === 'HH:mm' ? 'HH:mm:00' : config.format);
default:
let offset = Number(value);
if (target === 1) {
time = new Date().setHours(type === 4 ? new Date().getHours() - offset : new Date()
.getHours() + offset);
} else if (target === 2) {
time = new Date().setMinutes(type === 4 ? new Date().getMinutes() - offset : new Date()
.getMinutes() + offset);
} else if (target === 3) {
time = new Date().setSeconds(type === 4 ? new Date().getSeconds() - offset : new Date()
.getSeconds() + offset);
}
return this.$u.timeFormat(time, 'hh:MM:ss');
}
},
/**
* type 开始或者结束类型
* target 目标字段
* value 开始或者结束时间值
**/
calculateDateOffset(type, value, target) {
let date = new Date();
switch (type) {
case 1:
return Number(value);
case 3:
return date.getTime();
default:
let offset = Number(value);
if (target === 1) {
date.setFullYear(date.getFullYear() + (type === 4 ? -offset : offset));
} else if (target === 2) {
date.setMonth(date.getMonth() + (type === 4 ? -offset : offset));
} else if (target === 3) {
date.setDate(date.getDate() + (type === 4 ? -offset : offset));
}
return date.getTime();
}
},
buildRelations(componentList, relations) {
const selectType = ['org', 'pos', 'role', 'group'];
componentList.forEach(cur => {
const config = cur.__config__;
const vModel = cur.__vModel__;
if (config.jnpfKey === 'userSelect' && selectType.includes(cur.selectType)) {
if (cur.relationField) this.addRelationItem(cur, cur.relationField, relations,
'setUserOptions');
}
if (dyOptionsList.indexOf(config.jnpfKey) > -1 && config.dataType === 'dynamic' && config
.templateJson && config.templateJson.length) {
config.templateJson.forEach(e => {
if (e.relationField) this.addRelationItem(cur, e.relationField, relations,
'setOptions');
});
}
if (config.jnpfKey === 'datePicker') {
if (config.startTimeRule) cur.startTime = this.calculateDateOffset(config.startTimeType,
config.startTimeValue, config.startTimeTarget);
if (config.endTimeRule) cur.endTime = this.calculateDateOffset(config.endTimeType,
config.endTimeValue, config.endTimeTarget);
if (config.startRelationField) this.addRelationItem(cur, config.startRelationField,
relations, 'setDate');
if (config.endRelationField) this.addRelationItem(cur, config.endRelationField, relations,
'setDate');
}
if (config.jnpfKey === 'timePicker') {
if (config.startTimeRule) cur.startTime = this.processTimeRule(config,
config.startTimeType, config.startTimeTarget, config.startTimeValue);
if (config.endTimeRule) cur.endTime = this.processTimeRule(config, config.endTimeType,
config.endTimeTarget, config.endTimeValue);
if (config.startRelationField) this.addRelationItem(cur, config.startRelationField,
relations, 'setTime');
if (config.endRelationField) this.addRelationItem(cur, config.endRelationField, relations,
'setTime');
}
if (config.jnpfKey === 'popupSelect' && cur.templateJson && cur.templateJson.length) {
cur.templateJson.forEach(e => {
if (e.relationField) this.addRelationItem(cur, e.relationField, relations,
'setPopupOptions');
});
}
if (config.children) this.buildRelations(config.children, relations);
});
},
onLoadFunc(formConfCopy) {
if (!formConfCopy || !formConfCopy.funcs || !formConfCopy.funcs.onLoad) return
const onLoadFunc = this.jnpf.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 jnpfKey = config.jnpfKey
let defaultValue = ''
if (['checkbox', 'cascader'].includes(jnpfKey) || (['select', 'treeSelect', 'popupSelect',
'popupTableSelect', 'userSelect'
].includes(jnpfKey) && 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.jnpf.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.jnpfKey) > -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.jnpfKey !== '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.jnpf.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.jnpf.getScriptFunc(this.formConfCopy.funcs.afterSubmit)
if (!func) return
func(this.parameter)
},
// 子表必填验证,子表赋值
checkTableData() {
this.getRefList();
let isValid = true;
for (const vModel in this.tableRefs) {
const config = this.tableRefs[vModel].__config__;
if (!config.isVisibility || config.noShow) continue;
const tableRef = this.findTableRef(vModel);
if (!tableRef) continue;
const submitResult = this.getTableSubmitResult(tableRef, vModel);
if (submitResult) {
this.formData[vModel] = submitResult;
} else {
isValid = false;
}
}
return isValid;
},
findTableRef(vModel) {
for (const item of this.refList) {
if (item[0] === vModel) {
return Array.isArray(item[1]) ? item[1][0] : item[1];
}
}
return null;
},
getTableSubmitResult(tableRef, vModel) {
const refToSubmit = tableRef.$refs && tableRef.$refs[vModel] ? tableRef.$refs[vModel] : tableRef;
return refToSubmit.submit ? refToSubmit.submit() : false;
},
//获取子表实例ref
getRefList() {
this.refList = [];
const refList = this.$refs || [];
const loopRefs = (refs) => {
if (!refs) return
for (const key in refs) {
const ref = refs[key];
if (Array.isArray(ref)) {
ref.forEach(item => loopRefs(item));
} else {
this.refList.push([key, ref]);
}
}
};
if (Array.isArray(refList)) {
refList.forEach(item => loopRefs(item));
} else {
loopRefs(refList);
}
},
clickIcon(e) {
if (!e?.__config__) return;
const {
tipLabel,
label: configLabel,
jnpfKey
} = e.__config__;
const {
helpMessage
} = e;
if (!tipLabel && !helpMessage) return;
this.tipsContent = helpMessage || tipLabel;
this.tipsTitle =
jnpfKey === 'card' ? e.header :
jnpfKey === 'groupTitle' ? e.content :
configLabel;
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.jnpf.getScriptFunc(data.on[type]);
if (!func) return
func.call(this, {
data: val,
...this.parameter
})
}
},
}
}
</script>

View File

@@ -0,0 +1,121 @@
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) {
if (this.checkNumLimit()) return;
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.jnpf.onlineUtils,
}
const func = this.jnpf.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;
},
// 校验限制条数
checkNumLimit() {
if (this.config.isNumLimit && this.tableFormData.length >= this.config.numLimit) {
this.$u.toast(`${this.config.__config__.label}超出条数限制`);
return true;
}
return false;
}
}
}

View File

@@ -0,0 +1,55 @@
<template>
<JnpfRelationFormAttr v-model="value" :showField="showField" :relationField="relationField" :isStorage='isStorage'
:type="type" @change="onChange" />
</template>
<script>
import RelationFormAttr from '../RelationFormAttr/index.vue'
export default {
name: 'jnpf-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>
.jnpf-relation-attr {
width: 100%;
}
</style>

View File

@@ -0,0 +1,220 @@
<template>
<view class="jnpf-popup-select">
<selectBox v-model="innerValue" :disabled='disabled' :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: 'jnpf-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: () => []
},
multiple: {
type: Boolean,
default: false
}
},
data() {
return {
selectShow: false,
innerValue: '',
defaultValue: '',
current: null,
defaultOptions: [],
firstVal: '',
firstId: 0,
selectData: [],
extraObj: {}
}
},
watch: {
modelValue(val) {
this.setDefault()
},
},
created() {
uni.$on('confirm', (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.multiple ? this.modelValue : [this.modelValue],
interfaceId: this.interfaceId,
propsValue: this.propsValue,
relationField: this.relationField,
paramList: this.getParamList()
}
getDataInterfaceDataInfoByIds(this.interfaceId, query).then(res => {
if (this.multiple) {
this.selectData = res.data || []
let label = []
this.selectData.forEach((o, i) => {
for (let j = 0; j < query.ids.length; j++) {
if (query.ids[j] == o[this.propsValue]) {
if (!!o[this.relationField]) label.push(o[this.relationField])
}
}
})
this.innerValue = label.length == 1 ? label[0] : label.join(',')
} else {
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.multiple ? [this.modelValue] : this.modelValue,
vModel: this.vModel,
popupTitle: this.popupTitle || '选择数据',
innerValue: this.innerValue,
paramList: this.getParamList(),
multiple: this.multiple,
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">
.jnpf-popup-select {
width: 100%;
height: 100%;
}
</style>

View File

@@ -0,0 +1,304 @@
<template>
<u-popup class="jnpf-tree-select-popup" mode="right" v-model="showPopup" width="100%" @close="close">
<view class="jnpf-tree-select-body">
<view class="jnpf-tree-select-title">
<text class="icon-ym icon-ym-report-icon-preview-pagePre backIcon" @tap="close()"></text>
<view class="title">岗位选择</view>
</view>
<view class="jnpf-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="jnpf-tree-selected">
<view class="jnpf-tree-selected-head">
<view>{{$t('component.jnpf.common.selected')}}({{selectedList.length||0}})</view>
<view v-if="multiple" class="clear-btn" @click="setCheckAll">
{{$t('component.jnpf.common.clearAll')}}
</view>
</view>
<view class="jnpf-tree-selected-box">
<scroll-view scroll-y="true" class="select-list">
<u-tag closeable @close="delSelect(index)" v-for="(item,index) in selectedList" :key="index"
:text="item.orgNameTree" class="u-selectTag" />
</scroll-view>
</view>
</view>
<view class="jnpf-tree-selected-line"></view>
<view class="jnpf-tree-selected-tabs">
<view class="tab-item" :class="{'tab-item-active':activeKey==='1'}" @click="toggloActive('1')">岗位
</view>
<view class="tab-item" :class="{'tab-item-active':activeKey==='2'}" @click="toggloActive('2')"
v-if="selectType === 'all'">
当前岗位
</view>
</view>
<view class="jnpf-tree-select-tree">
<scroll-view :scroll-y="true" style="height: 100%" v-if="activeKey==='1' && !hasPage">
<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 show-node-icon @node-click="handleTreeNodeClick"
:show-checkbox="multiple" :show-radio="!multiple" :expandOnClickNode="false"
:checkOnClickNode="true" :expandOnCheckNode="false" checkStrictly 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="handleTreeNodeClick" :show-checkbox="multiple" :show-radio="!multiple"
:expandOnClickNode="false" :checkOnClickNode="true" :expandOnCheckNode="false" checkStrictly />
</scroll-view>
<scroll-view :scroll-y="true" style="height: 100%" :refresher-enabled="false" :refresher-threshold="100"
:scroll-with-animation='true' :refresher-triggered="triggered" @scrolltolower="handleScrollToLower"
v-else>
<view class="jnpf-selcet-list" v-if="list.length">
<view class="jnpf-selcet-cell" v-for="item in list" :key="item.id"
@click.stop="handleNodeClick(item)">
<view class="jnpf-selcet-cell-action">
<lyCheckbox :type="multiple ? 'checkbox' : 'radio'"
:checked="selectedIds.includes(item.id)" />
</view>
<view class="jnpf-selcet-cell-name">
{{item.orgNameTree}}
</view>
</view>
</view>
<Empty class="h-full" v-else />
</scroll-view>
</view>
<!-- 底部按钮 -->
<view class="jnpf-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>
import {
getPositionByCondition,
getOrgAndPosSelector,
getPositionSelector
} from '@/api/common'
import lyCheckbox from '@/components/ly-tree/components/ly-checkbox.vue';
import Empty from '../Empty/index.vue'
const defaultProps = {
label: 'fullName',
value: 'id',
icon: 'icon',
children: 'children'
}
export default {
props: {
selectedData: {
type: Array,
default: () => []
},
ableIds: {
type: Array,
default: () => []
},
selectType: {
type: String,
default: 'all'
},
// 通过双向绑定控制组件的弹出与收起
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
}
},
components: {
lyCheckbox,
Empty
},
data() {
return {
moving: false,
selectedList: [],
selectedIds: [],
keyword: '',
showPopup: false,
options: [],
lazyOptions: [],
activeKey: '1',
hasPage: false,
pagination: {
hasPage: 1,
currentPage: 1,
pageSize: 20
},
triggered: false,
finish: false,
list: [],
};
},
watch: {
// 在select弹起的时候重新初始化所有数据
modelValue: {
handler(val) {
this.showPopup = val
if (!val) this.activeKey = ''
if (val) setTimeout(() => this.init(), 10);
},
immediate: true
},
selectedList: {
handler(val) {
this.selectedIds = val.map((o) => o.id);
this.$refs.tree && this.$refs.tree.setCheckedKeys(this.selectedIds)
},
deep: true
},
},
computed: {
uZIndex() {
// 如果用户有传递z-index值优先使用
return this.zIndex ? this.zIndex : this.$u.zIndex.popup;
},
realProps() {
return {
...defaultProps,
...this.props
}
},
getCurrPosList() {
const userInfo = uni.getStorageSync('userInfo') || {}
const list = (userInfo.positionList || []).map((o) => ({
...o,
orgNameTree: o.treeName
}))
return list
}
},
methods: {
init() {
this.keyword = ""
this.hasPage = 0
this.activeKey = '1'
this.finish = false
this.pagination.currentPage = 1
this.$nextTick(() => {
this.triggered = true
})
this.selectedList = JSON.parse(JSON.stringify(this.selectedData))
if (this.selectType !== 'all') this.getConditionOptions()
},
getConditionOptions() {
if (!this.ableIds.length) return
const query = {
ids: this.ableIds
}
getPositionByCondition(query).then(res => {
this.options = res.data.list || []
this.$refs.tree && this.$refs.tree.setCheckedKeys(this.selectedIds)
})
},
filterNode(value, data) {
if (!value) return true;
return data[this.realProps.label].indexOf(value) !== -1;
},
loadNode(node, resolve) {
const id = node.key || '0'
const type = node?.data?.type || 'organize'
const data = {
id,
type
}
getOrgAndPosSelector(data).then(res => {
const list = (res.data?.list || []).map(o => ({
...o,
disabled: o.type !== 'position'
}))
resolve(list)
this.$refs.tree && this.$refs.tree.setCheckedKeys(this.selectedIds)
})
},
handleScrollToLower() {
if (this.finish || this.activeKey === '2') return
this.getTreeData()
},
getTreeData() {
let data = {
keyword: this.keyword,
parentId: '0',
...this.pagination
}
getPositionSelector(data).then(res => {
const list = res.data.list || []
if (list.length < this.pagination.pageSize) this.finish = true;
this.list = this.list.concat(list);
this.pagination.currentPage++
})
},
onTreeCheck(item) {
this.handleTreeNodeClick(item);
},
handleTreeNodeClick(item) {
const data = item.data
if (this.selectType === 'all' && data.type !== 'position') return
this.handleNodeClick(data)
},
handleNodeClick(data) {
const index = this.selectedList.findIndex((o) => o.id === data.id);
if (index !== -1) return this.selectedList.splice(index, 1);
this.multiple ? this.selectedList.push(data) : (this.selectedList = [data]);
},
delSelect(index) {
this.selectedList.splice(index, 1);
},
setCheckAll() {
this.selectedIds = []
this.selectedList = []
},
handleConfirm() {
this.$emit('confirm', this.selectedList, this.selectedIds);
this.close();
},
close() {
this.$emit('close', false);
},
toggloActive(key) {
if (this.activeKey === key) return
this.keyword = ''
this.$nextTick(() => {
this.activeKey = key
if (this.activeKey === '2') this.list = this.getCurrPosList
})
},
handleSearch(val) {
this.keyword = val
if (this.selectType !== 'all') return this.$refs.tree && this.$refs.tree.filter(val)
this.hasPage = !!val
this.list = []
if (this.activeKey != '1') this.activeKey = '1'
this.$nextTick(() => {
if (this.keyword) {
this.pagination.currentPage = 1
this.finish = false
this.$u.debounce(this.getTreeData, 300)
}
})
},
}
};
</script>

View File

@@ -0,0 +1,97 @@
<template>
<view class="jnpf-pos-select w-full">
<selectBox v-model="innerValue" :placeholder="placeholder" @openSelect="openSelect" :select-open="selectShow"
:disabled="disabled" />
<SelectPopup v-model="selectShow" :multiple="multiple" :selectedData="selectedData" @close="handleClose"
@confirm="handleConfirm" :selectType="selectType" :ableIds="ableIds" />
</view>
</template>
<script>
import SelectPopup from './SelectPopup';
import selectBox from '@/components/selectBox'
import {
getPositionSelectedList
} from '@/api/common'
export default {
name: 'jnpf-pos-select',
components: {
SelectPopup,
selectBox
},
props: {
modelValue: {
default: ''
},
placeholder: {
type: String,
default: '请选择'
},
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: [],
}
},
watch: {
modelValue: {
handler() {
this.setDefault()
},
immediate: true
},
},
methods: {
setDefault() {
if (!this.modelValue || !this.modelValue.length) return this.setNullValue();
const ids = this.multiple ? this.modelValue : [this.modelValue];
getPositionSelectedList({
ids
}).then((res) => {
if (!this.modelValue || !this.modelValue.length) return this.setNullValue();
const selectedData = res.data.list || []
this.selectedData = selectedData
this.innerValue = this.selectedData.map(o => o.orgNameTree).join();
});
},
setNullValue() {
this.innerValue = '';
this.selectedData = [];
},
openSelect() {
if (this.disabled) return
this.selectShow = true
},
handleConfirm(selectedData, selectedIds) {
if (!this.multiple) {
this.$emit('update:modelValue', selectedIds[0])
this.$emit('change', selectedIds[0], selectedData[0])
} else {
this.$emit('update:modelValue', selectedIds)
this.$emit('change', selectedIds, selectedData)
}
},
handleClose() {
this.selectShow = false
}
}
}
</script>

View File

@@ -0,0 +1,115 @@
<template>
<tki-qrcode class="jnpf-qrcode" v-if="qrcode&&showQrcode" ref="qrcode" :cid="cid" :val="qrcode" :size="width*2"
:background="colorLight" :foreground="colorDark" onval loadMake :showLoading="false" />
</template>
<script>
import tkiQrcode from "./tki-qrcode/tki-qrcode.vue"
let unique = 0
export default {
name: 'qrcode',
props: {
dataType: {
type: String,
default: 'static'
},
colorLight: {
type: String,
default: "#fff"
},
colorDark: {
type: String,
default: "#000"
},
relationField: {
type: String,
default: ''
},
formData: {
type: Object
},
width: {
type: Number,
default: 200
},
staticText: {
type: String,
default: ''
}
},
components: {
tkiQrcode
},
computed: {
qrcode() {
if (this.dataType === 'static') {
return this.staticText
} else if (this.dataType === 'relation') {
return this.relationText?.toString()
} else {
if (this.formData && this.dynamicModelExtra && this.dynamicModelExtra.id && this.dynamicModelExtra
.modelId) {
const json = {
t: 'DFD',
id: this.dynamicModelExtra.id,
mid: this.dynamicModelExtra.modelId,
mt: this.dynamicModelExtra.type,
fid: this.dynamicModelExtra.flowId || '',
pid: this.dynamicModelExtra.processId || '',
ftid: this.dynamicModelExtra.taskId || '',
opt: this.dynamicModelExtra.opType
}
return JSON.stringify(json)
}
return ''
}
},
dynamicModelExtra() {
return uni.getStorageSync('dynamicModelExtra') || null
}
},
data() {
return {
cid: '',
relationText: "",
showQrcode: false
}
},
mounted() {
this.cid = this.uuid()
this.showQrcode = true
uni.$on('updateCode', () => {
this.showQrcode = false
this.$nextTick(() => {
this.showQrcode = true
})
})
},
watch: {
formData: {
handler(val) {
const relationValue = val[this.relationField] || val[this.relationField] === 0 || val[this
.relationField] === false ? val[this.relationField] : ''
if (val && this.dataType === 'relation' && this.relationField) this.relationText = relationValue
},
deep: true,
immediate: true
},
},
methods: {
uuid() {
const time = Date.now()
const random = Math.floor(Math.random() * 1000000000)
unique++
return 'qrcode_' + random + unique + String(time)
}
},
}
</script>
<style lang="scss" scoped>
.jnpf-qrcode {
width: 100%;
overflow: hidden;
margin-bottom: -20rpx;
}
</style>

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,217 @@
<template xlang="wxml" minapp="mpvue">
<view class="tki-qrcode">
<!-- #ifndef MP-ALIPAY -->
<canvas class="tki-qrcode-canvas" :canvas-id="cid" :style="{width:cpSize+'px',height:cpSize+'px'}" />
<!-- #endif -->
<!-- #ifdef MP-ALIPAY -->
<canvas :id="cid" :width="cpSize" :height="cpSize" class="tki-qrcode-canvas" />
<!-- #endif -->
<image v-show="show" :src="result" :style="{width:cpSize+'px',height:cpSize+'px'}" />
</view>
</template>
<script>
import QRCode from "./qrcode.js"
let qrcode
export default {
name: "tki-qrcode",
props: {
cid: {
type: String,
default: 'tki-qrcode-canvas'
},
size: {
type: Number,
default: 200
},
unit: {
type: String,
default: 'upx'
},
show: {
type: Boolean,
default: true
},
val: {
type: String,
default: ''
},
background: {
type: String,
default: '#ffffff'
},
foreground: {
type: String,
default: '#000000'
},
pdground: {
type: String,
default: '#000000'
},
icon: {
type: String,
default: ''
},
iconSize: {
type: Number,
default: 40
},
lv: {
type: Number,
default: 3
},
onval: {
type: Boolean,
default: false
},
loadMake: {
type: Boolean,
default: false
},
usingComponents: {
type: Boolean,
default: true
},
showLoading: {
type: Boolean,
default: true
},
loadingText: {
type: String,
default: '二维码生成中'
},
},
data() {
return {
result: '',
}
},
methods: {
_makeCode() {
let that = this
if (!this._empty(this.val)) {
qrcode = new QRCode({
context: that, // 上下文环境
canvasId: that.cid, // canvas-id
usingComponents: that.usingComponents, // 是否是自定义组件
showLoading: that.showLoading, // 是否显示loading
loadingText: that.loadingText, // loading文字
text: that.val, // 生成内容
size: that.cpSize, // 二维码大小
background: that.background, // 背景色
foreground: that.foreground, // 前景色
pdground: that.pdground, // 定位角点颜色
correctLevel: that.lv, // 容错级别
image: that.icon, // 二维码图标
imageSize: that.iconSize, // 二维码图标大小
cbResult: function(res) { // 生成二维码的回调
that._result(res)
},
});
} else {
uni.showToast({
title: '二维码内容不能为空',
icon: 'none',
duration: 2000
});
}
},
_clearCode() {
this._result('')
qrcode.clear()
},
_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: {
size: function(n, o) {
if (n != o && !this._empty(n)) {
this.cSize = n
if (!this._empty(this.val)) {
setTimeout(() => {
this._makeCode()
}, 100);
}
}
},
val: function(n, o) {
if (this.onval) {
if (n != o && !this._empty(n)) {
setTimeout(() => {
this._makeCode()
}, 0);
}
}
}
},
computed: {
cpSize() {
if (this.unit == "upx") {
// #ifndef APP-HARMONY
return uni.upx2px(this.size)
// #endif
// #ifdef APP-HARMONY
return this.size / 2
// #endif
} else {
return this.size
}
}
},
mounted: function() {
if (this.loadMake) {
if (!this._empty(this.val)) {
setTimeout(() => {
this._makeCode()
}, 0);
}
}
},
}
</script>
<style>
.tki-qrcode {
position: relative;
text-align: right;
}
.tki-qrcode-canvas {
position: fixed !important;
top: -99999upx;
left: -99999upx;
z-index: -99999;
}
</style>

View File

@@ -0,0 +1,72 @@
<template>
<u-radio-group class="jnpf-radio" :disabled='disabled' v-model="innerValue"
:wrap="direction == 'horizontal' ? false : true" @change="onChange">
<u-radio v-for="(item, index) in options" :key="index" :name="item[props.value]"
:class="{'jnpf-radio-disabled':disabled}">
{{ item[props.label] }}
</u-radio>
</u-radio-group>
</template>
<script>
export default {
inheritAttrs: false,
name: 'jnpfRadio',
props: {
modelValue: {
type: [String, Number, Boolean],
},
direction: {
type: String,
default: "horizontal"
},
options: {
type: Array,
default: () => []
},
props: {
type: Object,
default: () => ({
label: 'fullName',
value: 'id'
})
},
disabled: {
type: Boolean,
default: false
}
},
data() {
return {
innerValue: ''
}
},
watch: {
modelValue: {
handler(val) {
this.innerValue = val
},
immediate: true,
}
},
methods: {
onChange(value, e) {
const selectData = this.options.filter(o => value == o[this.props.value]) || []
this.$emit('update:modelValue', value)
this.$emit('change', value, selectData[0])
},
}
}
</script>
<style lang="scss" scoped>
:deep(.u-radio__icon-wrap--circle) {
border-color: #D9D9D9 !important;
}
.jnpf-radio-disabled {
:deep(.u-radio__icon-wrap--disabled) {
background-color: #E6E6E6 !important;
border-color: #D9D9D9 !important;
}
}
</style>

View File

@@ -0,0 +1,60 @@
<template>
<uni-rate class="jnpf-rate" v-model="innerValue" :size="20" :max="max" :allowHalf="allowHalf" :disabled="disabled"
@change="onChange" />
</template>
<script>
export default {
name: 'jnpf-rate',
inheritAttrs: false,
props: {
modelValue: {
type: [Number, String],
default: 0
},
allowHalf: {
type: Boolean,
default: false
},
max: {
type: Number,
default: 5
},
disabled: {
type: Boolean,
default: false
}
},
watch: {
modelValue: {
handler(val) {
this.innerValue = Number(val)
},
immediate: true
}
},
data() {
return {
innerValue: 0
}
},
methods: {
onChange(data) {
this.$emit('update:modelValue', data.value)
this.$emit('change', data.value)
},
}
}
</script>
<style lang="scss" scoped>
.jnpf-rate {
width: 100%;
display: flex;
justify-content: flex-end;
&.jnpf-rate-disabled {
:deep(.uni-icons) {
color: #E6E6E6 !important;
}
}
}
</style>

View File

@@ -0,0 +1,194 @@
<template>
<view class="jnpf-relation-form">
<selectBox v-model="innerValue" :disabled='disabled' :placeholder="placeholder" @openSelect="openSelect">
</selectBox>
<DisplayList :extraObj="extraObj" :extraOptions="extraOptions"
v-if="Object.keys(extraObj).length && innerValue">
</DisplayList>
</view>
</template>
<script>
import {
getRelationFormDetail
} from '@/api/common.js'
import DisplayList from '@/components/displayList'
import selectBox from '@/components/selectBox'
import {
useBaseStore
} from '@/store/modules/base'
const baseStore = useBaseStore()
export default {
name: 'jnpf-relation-form',
components: {
DisplayList,
selectBox
},
props: {
modelValue: {
default: ''
},
placeholder: {
type: String,
default: '请选择'
},
formType: {
type: String,
default: 'select'
},
disabled: {
type: Boolean,
default: false
},
columnOptions: {
type: Array,
default: []
},
extraOptions: {
type: Array,
default: () => []
},
relationField: {
type: String,
default: ''
},
propsValue: {
type: String,
default: ''
},
modelId: {
type: String,
default: ''
},
hasPage: {
type: Boolean,
default: false
},
pageSize: {
type: Number,
default: 10000
},
vModel: {
type: String,
default: ''
},
popupTitle: {
type: String,
default: ''
},
queryType: {
type: Number,
default: 1
}
},
data() {
return {
selectShow: false,
innerValue: '',
defaultValue: '',
current: null,
defaultOptions: [],
firstVal: '',
firstId: 0,
extraObj: {}
}
},
watch: {
modelValue(val) {
this.setDefault()
},
},
created() {
uni.$on('relationConfirm', (subVal, innerValue, list, selectRow) => {
this.confirm(subVal, innerValue, list, selectRow)
})
this.setDefault()
},
methods: {
setDefault() {
if (!this.modelId || !this.vModel) return
if (!this.modelValue) {
this.innerValue = ''
let relationData = baseStore.relationData
relationData[this.vModel] = {}
baseStore.updateRelationData(relationData)
return
}
let query = {
id: this.modelValue,
};
if (this.propsValue) query = {
...query,
propsValue: this.propsValue
};
getRelationFormDetail(this.modelId, query).then(res => {
if (!res.data || !res.data.data) return
let data = JSON.parse(res.data.data)
this.extraObj = data
this.innerValue = data[this.relationField] ? data[this.relationField] : this
.modelValue
let relationData = baseStore.relationData
relationData[this.vModel] = data
baseStore.updateRelationData(relationData)
})
},
openSelect() {
if (this.disabled) {
if (!this.modelValue) return
let config = {
modelId: this.modelId,
id: this.modelValue,
formTitle: '详情',
noShowBtn: 1,
noDataLog: 1
}
this.$nextTick(() => {
const url =
'/pages/apply/dynamicModel/detail?config=' +
this.jnpf.base64.encode(JSON.stringify(config))
uni.navigateTo({
url: url
})
})
return
}
let data = {
columnOptions: this.columnOptions,
relationField: this.relationField,
type: 'relation',
propsValue: this.propsValue,
modelId: this.modelId,
hasPage: this.hasPage,
pageSize: this.pageSize,
id: this.modelValue,
vModel: this.vModel,
popupTitle: this.popupTitle || '选择数据',
innerValue: this.innerValue,
queryType: this.queryType
}
uni.navigateTo({
url: '/pages/apply/popSelect/index?data=' + encodeURIComponent(JSON.stringify(
data))
})
},
confirm(subVal, innerValue, vModel, selectRow) {
if (vModel !== this.vModel) return; // 早期返回,如果条件不满足,则直接退出
this.firstVal = innerValue;
this.firstId = subVal;
// 确定 innerValue 的值
let innerValueStr = !this.propsValue ? innerValue + '' : selectRow[this.propsValue];
this.innerValue = selectRow[this.relationField] || "";
// 触发 update:modelValue 事件
this.$emit('update:modelValue', selectRow[this.propsValue]);
// 触发 change 事件
this.$emit('change', subVal, selectRow);
}
}
}
</script>
<style lang="scss" scoped>
.jnpf-relation-form {
width: 100%;
height: 100%;
}
</style>

View File

@@ -0,0 +1,76 @@
<template>
<view class="jnpf-relation-form-attr">
<u-input v-model="innerValue" input-align='right' disabled :placeholder="placeholder" />
</view>
</template>
<script>
import {
useBaseStore
} from '@/store/modules/base'
const baseStore = useBaseStore()
export default {
name: 'jnpf-relation-form-attr',
props: {
modelValue: {
type: [String, Number],
default: ''
},
showField: {
type: String,
default: ''
},
relationField: {
type: String,
default: ''
},
type: {
type: String,
default: 'relationFormAttr'
},
isStorage: {
type: Number,
default: 0
},
},
data() {
return {
innerValue: '',
placeholder: ''
}
},
computed: {
relationData() {
return baseStore.relationData
}
},
watch: {
relationData: {
handler(val) {
if (!this.showField || !this.relationField) return
let obj = val[this.relationField] || {}
this.innerValue = obj[this.showField] ? obj[this.showField] : ''
this.$emit('change', this.innerValue)
},
deep: true
},
innerValue(val) {
this.$emit('update:modelValue', val)
}
},
created() {
const placeholder = this.type === 'relationFormAttr' ? this.isStorage ? this.$t(
'component.jnpf.relationFormAttr.storage') : this.$t('component.jnpf.relationFormAttr.unStorage') :
this.isStorage ? this.$t('component.jnpf.popupAttr.storage') : this.$t(
'component.jnpf.popupAttr.unStorage')
this.placeholder = placeholder
}
}
</script>
<style lang="scss" scoped>
.jnpf-relation-form-attr {
width: 100%;
text-align: right;
}
</style>

View File

@@ -0,0 +1,160 @@
<template>
<u-popup class="jnpf-tree-select-popup" mode="right" v-model="showPopup" @close="close" :z-index="uZIndex"
width="100%">
<view class="jnpf-tree-select-body">
<view class="jnpf-tree-select-title">
<text class="icon-ym icon-ym-report-icon-preview-pagePre backIcon" @tap="close()"></text>
<view class="title">角色选择</view>
</view>
<view class="jnpf-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="jnpf-tree-selected">
<view class="jnpf-tree-selected-head">
<view>{{$t('component.jnpf.common.selected')}}({{selectedList.length||0}})</view>
<view v-if="multiple" class="clear-btn" @click="removeAll">
{{$t('component.jnpf.common.clearAll')}}
</view>
</view>
<view class="jnpf-tree-selected-box">
<scroll-view scroll-y="true" class="select-list">
<u-tag closeable @close="handleRemove(index)" v-for="(item,index) in selectedList" :key="index"
:text="item.fullName" class="u-selectTag" />
</scroll-view>
</view>
</view>
<view class="jnpf-tree-selected-line"></view>
<view class="jnpf-tree-selected-tabs">
<view class="tab-item tab-item-active">用户角色</view>
</view>
<view class="jnpf-tree-select-tree">
<scroll-view :scroll-y="true" style="height: 100%">
<view class="jnpf-selcet-list" v-if="options.length">
<view class="jnpf-selcet-cell" v-for="item in options" :key="item.id"
@click.stop="handleNodeClick(item)">
<view class="jnpf-selcet-cell-action">
<lyCheckbox :type="multiple ? 'checkbox' : 'radio'"
:checked="selectedIds.includes(item.id)" />
</view>
<view class="jnpf-selcet-cell-name">
{{item.fullName}}
</view>
</view>
</view>
<Empty class="h-full" v-else />
</scroll-view>
</view>
<!-- 底部按钮 -->
<view class="jnpf-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>
import lyCheckbox from '@/components/ly-tree/components/ly-checkbox.vue';
import Empty from '../Empty/index.vue'
export default {
components: {
lyCheckbox,
Empty
},
props: {
getOptions: {
type: Function,
},
selectedData: {
type: Array,
default: () => []
},
// 通过双向绑定控制组件的弹出与收起
modelValue: {
type: Boolean,
default: false
},
// 弹出的z-index值
zIndex: {
type: [String, Number],
default: 99999
},
multiple: {
type: Boolean,
default: false
}
},
data() {
return {
moving: false,
selectedList: [],
selectedIds: [],
keyword: '',
showPopup: false,
options: [],
cacheData: [],
};
},
watch: {
modelValue: {
handler(val) {
this.showPopup = val
if (val) setTimeout(() => this.init(), 10);
},
immediate: true
},
selectedList: {
handler(val) {
this.selectedIds = val.map((o) => o.id);
},
deep: true
},
},
computed: {
uZIndex() {
// 如果用户有传递z-index值优先使用
return this.zIndex ? this.zIndex : this.$u.zIndex.popup;
},
},
methods: {
init() {
this.keyword = ''
this.selectedList = JSON.parse(JSON.stringify(this.selectedData))
if (this.getOptions) {
this.getOptions().then(res => {
this.options = res || []
this.cacheData = res || []
})
} else {
this.options = []
this.cacheData = []
}
},
handleNodeClick(data) {
const index = this.selectedList.findIndex((o) => o.id === data.id);
if (index !== -1) return this.selectedList.splice(index, 1);
this.multiple ? this.selectedList.push(data) : (this.selectedList = [data]);
},
handleRemove(index) {
this.selectedList.splice(index, 1);
},
removeAll() {
this.selectedList = [];
},
handleConfirm() {
this.$emit('confirm', this.selectedList, this.selectedIds);
this.close();
},
close() {
this.$emit('close');
},
handleSearch(val) {
this.options = this.cacheData.filter((o) => o.fullName.includes(val));
},
}
};
</script>

View File

@@ -0,0 +1,135 @@
<template>
<view class="jnpf-role-select w-full">
<selectBox v-model="innerValue" :placeholder="placeholder" @openSelect="openSelect" :select-open="selectShow"
:disabled="disabled" />
<SelectPopup v-model="selectShow" :getOptions="getOptions" :multiple="multiple" :selectedData="selectedData"
@close="handleClose" @confirm="handleConfirm" />
</view>
</template>
<script>
import SelectPopup from './SelectPopup';
import selectBox from '@/components/selectBox'
import {
useBaseStore
} from '@/store/modules/base'
import {
getRoleCondition
} from '@/api/common'
const baseStore = useBaseStore()
export default {
name: 'jnpf-role-select',
components: {
SelectPopup,
selectBox
},
props: {
modelValue: {
default: ''
},
placeholder: {
type: String,
default: '请选择'
},
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: [],
}
},
watch: {
modelValue: {
handler() {
this.setDefault()
},
immediate: true
},
allList: {
handler() {
this.setDefault()
},
deep: true,
},
},
created() {
this.initData()
},
methods: {
async initData() {
this.allList = await baseStore.getRoleList()
},
setDefault() {
if (!this.modelValue || !this.modelValue.length) return this.setNullValue();
let 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]) {
selectedData.push(this.allList[j])
break inner
}
}
}
this.selectedData = selectedData
this.innerValue = this.selectedData.map(o => o.fullName).join();
},
getOptions() {
return new Promise((resolve, reject) => {
if (this.selectType === 'custom') {
const query = {
ids: this.ableIds
}
getRoleCondition(query).then(res => {
resolve(res.data || [])
}).catch(error => {
reject(error)
})
} else {
baseStore.getRoleList().then(res => {
resolve(res || [])
})
}
})
},
setNullValue() {
this.innerValue = '';
this.selectedData = [];
},
openSelect() {
if (this.disabled) return
this.selectShow = true
},
handleConfirm(selectedData, selectedIds) {
if (!this.multiple) {
this.$emit('update:modelValue', selectedIds[0])
this.$emit('change', selectedIds[0], selectedData[0])
} else {
this.$emit('update:modelValue', selectedIds)
this.$emit('change', selectedIds, selectedData)
}
},
handleClose() {
this.selectShow = false
}
}
}
</script>

View File

@@ -0,0 +1,149 @@
<template>
<view class="jnpf-select">
<selectBox v-model="innerValue" :disabled='disabled' :placeholder="placeholder" @openSelect="openSelect"
:select-open="selectShow" v-if="isFlow" >
</selectBox>
<MultSelect :list="list" :show="selectShow" :value-name="props.value" :label-name="props.label"
:defaultValue="defaultValue" @confirm="selectConfirm" @close="close" :filterable="filterable"
:multiple="multiple" />
</view>
</template>
<script>
import MultSelect from '@/components/MultSelect'
import selectBox from '@/components/selectBox'
export default {
name: 'jnpf-select',
components: {
MultSelect,
selectBox
},
props: {
modelValue: {
type: [String, Number, Array],
},
options: {
type: Array,
default: () => []
},
props: {
type: Object,
default: () => ({
label: 'fullName',
value: 'id'
})
},
placeholder: {
type: String,
default: '请选择'
},
multiple: {
type: Boolean,
default: false
},
disabled: {
type: Boolean,
default: false
},
filterable: {
type: Boolean,
default: false
},
isFlow: {
type: Boolean,
default: true
},
},
data() {
return {
innerValue: '',
defaultValue: [],
selectShow: false,
}
},
watch: {
modelValue: {
immediate: true,
handler(val) {
this.setDefault()
},
},
options: {
immediate: true,
handler(val) {
this.setDefault()
},
}
},
computed: {
list() {
return this.options
}
},
methods: {
openSelect() {
if (this.disabled) return
this.selectShow = true
},
selectConfirm(e) {
if (this.multiple) {
this.innerValue = e.label
this.defaultValue = e.value
this.$emit('update:modelValue', e.value || [])
this.$emit('change', e.value || [], e.list || [])
} else {
if (!e.length) return
const selectData = e[0]
this.innerValue = selectData[this.props.label]
this.defaultValue = [e[0][this.props.value]]
this.$emit('update:modelValue', selectData[this.props.value])
this.$emit('change', selectData[this.props.value], selectData)
}
},
setDefault() {
if (!this.options.length) return this.innerValue = ''
if (this.multiple) {
this.innerValue = ''
this.defaultValue = []
if (!this.modelValue || !this.modelValue.length) return
this.defaultValue = this.modelValue
for (let i = 0; i < this.options.length; i++) {
const item = this.options[i]
for (let j = 0; j < this.modelValue.length; j++) {
const it = this.modelValue[j]
if (item[this.props.value] == it) {
if (!this.innerValue) {
this.innerValue += item[this.props.label]
} else {
this.innerValue += ',' + item[this.props.label]
}
}
}
}
} else {
this.innerValue = ''
this.defaultValue = []
if (!this.modelValue && this.modelValue !== 0) return
for (let i = 0; i < this.options.length; i++) {
if (this.options[i][this.props.value] == this.modelValue) {
this.defaultValue = [this.modelValue]
this.innerValue = this.options[i][this.props.label]
return
}
}
}
},
close() {
this.selectShow = false
}
}
}
</script>
<style lang="scss">
.jnpf-select {
width: 100%;
.u-input__content__field-wrapper__field {
overflow: auto;
}
}
</style>

View File

@@ -0,0 +1,452 @@
<template>
<view class="signature-wrap">
<view v-if="!disabled" v-show="show" class="signature-contain">
<view class="signature-main" style="z-index: 3000;">
<view>
<!-- <uni-icons custom-prefix="custom-icon" type="arrow-up" size="30"></uni-icons> -->
<view class="signature-title">
<text v-for="(t,i) in titles" :key="i">{{t}}</text>
</view>
</view>
<canvas disable-scroll="true" class="signature" :class="cid" :canvas-id="cid" @touchstart="touchstart"
@touchmove="touchmove" @touchend="touchend">
<view class="tip" v-show="!hasDrew">
请在此区域手写签名
</view>
</canvas>
<view class="signature-btns">
<view class="btn btn-cancel cu-btn bg-main margin-tb-sm text-white" @tap="cancelSignature()">
<text></text><text></text>
</view>
<view class="btn btn-clear cu-btn bg-main margin-tb-sm text-white" @tap="clearSignature();">
<text></text><text></text>
</view>
<view class="btn btn-ok cu-btn bg-main margin-tb-sm text-white" @tap="onOK()">
<text></text><text></text>
</view>
</view>
</view>
</view>
</view>
</template>
<script>
let _keyStr = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
var _utf8_encode = function(string) {
string = string.replace(/\r\n/g, "\n");
var utftext = "";
for (var n = 0; n < string.length; n++) {
var c = string.charCodeAt(n);
if (c < 128) {
utftext += String.fromCharCode(c);
} else if ((c > 127) && (c < 2048)) {
utftext += String.fromCharCode((c >> 6) | 192);
utftext += String.fromCharCode((c & 63) | 128);
} else {
utftext += String.fromCharCode((c >> 12) | 224);
utftext += String.fromCharCode(((c >> 6) & 63) | 128);
utftext += String.fromCharCode((c & 63) | 128);
}
}
return utftext;
}
let base64encode = function(input) {
var output = "";
var chr1, chr2, chr3, enc1, enc2, enc3, enc4;
var i = 0;
input = _utf8_encode(input);
while (i < input.length) {
chr1 = input.charCodeAt(i++);
chr2 = input.charCodeAt(i++);
chr3 = input.charCodeAt(i++);
enc1 = chr1 >> 2;
enc2 = ((chr1 & 3) << 4) | (chr2 >> 4);
enc3 = ((chr2 & 15) << 2) | (chr3 >> 6);
enc4 = chr3 & 63;
if (isNaN(chr2)) {
enc3 = enc4 = 64;
} else if (isNaN(chr3)) {
enc4 = 64;
}
output = output +
_keyStr.charAt(enc1) + _keyStr.charAt(enc2) +
_keyStr.charAt(enc3) + _keyStr.charAt(enc4);
}
return output;
}
export default {
cxt: null,
data() {
return {
VERSION: '1.0.0',
cid: 'cvs' + this.jnpf.idGenerator(),
show: false,
ctrl: null,
listeners: [],
prevView: '',
draws: [],
lines: [],
line: null,
hasDrew: false,
};
},
props: {
value: {
default: '',
},
title: {
type: String,
default: '请签名',
},
disabled: {
type: Boolean,
default: false,
},
showBtn: {
type: Boolean,
default: false,
},
},
watch: {
value() {
this.prevView = this.value;
},
lines: {
deep: true,
handler(val) {
this.hasDrew = !!val.length
}
}
},
computed: {
titles() {
return this.title.split('')
},
absPrevView() {
var pv = this.prevView;
// if(pv){
// pv = this.$wrapUrl(pv)
// }
return pv;
}
},
mounted() {
this.prevView = this.value;
},
methods: {
onOK() {
let data = this.ctrl.getValue();
this.$emit('input', data);
this.prevView = data;
this.hideSignature();
let f = this.listeners.shift();
if (f) {
f(data);
}
},
touchSignature() {
let sig = this.prevView
if (!sig || !sig.length) {
this.showSignature()
}
},
showSignature() {
if (this.disabled) return;
if (!this.ctrl) {
this.initCtrl();
} else if (!this.show) {
this.clearSignature();
this.show = true;
}
},
async getSyncSignature() {
this.showSignature();
return await new Promise(async (resolve, reject) => {
this.listeners.push((res) => {
resolve(res);
});
});
},
cancelSignature() {
this.listeners.map((f) => {
f(null);
})
this.hideSignature();
},
hideSignature() {
this.ctrl && this.ctrl.clear();
this.show = false;
},
clearSignature() {
this.ctrl && this.ctrl.clear();
},
async initCtrl() {
this.show = true;
let cxt = uni.createCanvasContext(this.cid, this);
this.cxt = cxt;
// cxt.clearRect(0,0,c.width,c.height);
this.ctrl = {
width: 0,
height: 0,
clear: () => {
this.lines = [];
let info = uni.createSelectorQuery().in(this).select("." + this.cid);
info.boundingClientRect((data) => {
if (data) {
cxt.clearRect(0, 0, data.width, data.height);
if (data.width && data.height) {
this.ctrl.width = data.width;
this.ctrl.height = data.height;
}
}
}).exec();
this.redraw();
},
getValue: () => {
if (!this.lines.length) return '';
let svg = this._get_svg();
// new Buff
let b64 = base64encode(svg);
let data = 'data:image/svg+xml;base64,' + b64;
return data;
},
};
this.$nextTick(function() {
this.ctrl.clear();
})
},
_get_svg() {
let r = -90;
let paths = [];
let raww = this.ctrl.width;
let rawh = this.ctrl.height;
let width = Math.abs(r) != 90 ? raww : rawh;
let height = Math.abs(r) == 90 ? raww : rawh;
let cx = raww / 2;
let cy = rawh / 2;
let PI = Math.PI;
let R = (r || 0) % 360;
let cosv = Math.cos(R * PI / 180);
let sinv = Math.sin(R * PI / 180);
let dcx = (width - raww) / 2;
let dcy = (height - rawh) / 2;
let trans = function(p) {
if (!R) {
return p;
} else {
let nx = (p.x - cx) * cosv - (p.y - cy) * sinv + cx;
let ny = (p.x - cx) * sinv + (p.y - cy) * cosv + cy;
return {
x: nx + dcx,
y: ny + dcy
};
}
return p;
}
this.lines.map(l => {
if (l.points.length < 2) {
return;
}
let sp = trans(l.start)
let pts = [`M ${sp.x} ${Number(sp.y)}`];
l.points.map(p => {
let np = trans(p)
pts.push(`L ${np.x} ${Number(np.y)}`);
});
paths.push(
`<path stroke-linejoin="round" stroke-linecap="round" stroke-width="3" stroke="rgb(0,0,0)" fill="none" d="${pts.join(' ')}"/>`
);
})
let svg =
`<?xml version="1.0" encoding="UTF-8" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg xmlns="http://www.w3.org/2000/svg" version="1.1" width="${width}" height="${height}">${paths.join('\n')}</svg>`;
return svg;
},
_get_svg_raw() {
let paths = [];
this.lines.map(l => {
if (l.points.length < 2) {
return;
}
let pts = [`M ${l.start.x} ${Number(l.start.y)}`];
l.points.map(p => {
pts.push(`L ${p.x} ${Number(p.y)}`);
});
paths.push(
`<path stroke-linejoin="round" stroke-linecap="round" stroke-width="3" stroke="rgb(0,0,0)" fill="none" d="${pts.join(' ')}"/>`
);
})
let width = this.ctrl.width;
let height = this.ctrl.height;
let svg =
`<?xml version="1.0" encoding="UTF-8" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg xmlns="http://www.w3.org/2000/svg" version="1.1" width="${width}" height="${height}" transform="rotate(-90)">${paths.join('\n')}</svg>`;
return svg;
},
_get_point(e) {
return {
x: e.changedTouches[0].x.toFixed(1),
y: e.changedTouches[0].y.toFixed(1),
}
},
touchstart(e) {
let p = this._get_point(e);
this.line = {
start: p,
points: [p],
}
this.lines.push(this.line);
},
touchmove(e) {
let p = this._get_point(e);
this.line.points.push(p)
if (!this.tm) {
this.tm = setTimeout(() => {
this.redraw();
this.tm = 0;
}, 10)
}
},
touchend(e) {
let p = this._get_point(e);
this.line.points.push(p)
this.line.end = p
this.redraw()
},
redraw() {
let cxt = this.cxt;
cxt.setStrokeStyle("#000");
cxt.setLineWidth(3);
var last = null;
this.lines.map(l => {
cxt.beginPath();
if (l.points.length < 2) {
return;
}
cxt.moveTo(l.start.x, l.start.y);
l.points.map(p => {
cxt.lineTo(p.x, p.y)
})
cxt.stroke()
})
cxt.draw()
},
canvasIdErrorCallback: function(e) {}
}
}
</script>
<style lang="scss">
.signature-wrap {
height: 100%;
.img-wrap {
width: 100%;
display: flex;
align-items: flex-start;
text-align: left;
align-content: flex-start;
justify-content: flex-start;
color: #2A79F9;
flex-direction: column;
image {
width: 100%;
}
}
}
.signature-contain {
z-index: 9000;
position: fixed;
left: 0;
top: 0;
width: 100%;
.signature-main {
background: white;
flex-direction: row-reverse;
display: flex;
align-items: stretch;
height: 101%;
overflow: scroll;
}
.signature-title {
font-weight: bold;
font-size: 18px;
display: flex;
padding: 0 20rpx;
flex-direction: column;
justify-content: center;
height: 100vh;
color: $uni-text-color;
text {
transform: rotate(90deg);
}
}
.tip {
position: absolute;
top: 50%;
left: 50%;
white-space: nowrap;
transform: translate(-50%, -50%)rotate(90deg);
}
.signature {
background: #f7f7f7;
width: 90vw;
height: 95vh;
align-self: center;
// pointer-events:none;
}
.signature-btns {
display: flex;
padding: 2px;
// margin-right: 5px;
flex-direction: column;
.btn {
flex-grow: 1;
flex-shrink: 0;
padding: 20rpx;
font-size: 20px;
margin: 0;
text-align: center;
text-decoration: none;
height: 30vh;
display: flex;
align-content: center;
justify-content: center;
flex-direction: column;
text {
transform: rotate(90deg);
}
&+.btn {
border-top: 1px solid #eee;
}
&.btn-clear {
// background-color: #fc2a07;
color: $uni-color-warning;
}
&.btn-cancel {
// background-color: #eff4f4;
color: #606266;
}
&.btn-ok {
// background-color: $uni-color-success;
color: $uni-color-primary;
}
}
}
}
</style>

View File

@@ -0,0 +1,236 @@
<template>
<view class="jnpf-sign" :class="align=='right'?'flex-end':'flex-start'" v-if="signType === 'currency'">
<view class="jnpf-sign-box">
<template v-if="showBtn">
<image class="jnpf-sign-img" :src="innerValue" mode="scaleToFill" v-show="innerValue"
@tap.stop="handlePreviewImage(innerValue)" />
<view class="jnpf-sign-btn" :class="{'jnpf-sign-disabled':disabled}" v-if="!detailed && !isInvoke"
@click="addSign()">
<i class="icon-ym icon-ym-signature" />
<view class="title" v-if="!innerValue">{{ signTip }}</view>
</view>
<view class="jnpf-sign-btn" :class="{'jnpf-sign-disabled':disabled}" v-if="!detailed && isInvoke"
@click="showSignMode()">
<i class="icon-ym icon-ym-signature" />
<view class="title" v-if="!innerValue">{{ signTip }}</view>
</view>
</template>
</view>
</view>
<view class="u-flex signature-box" v-else>
<view class="jnpf-sign-btn" :class="{'jnpf-sign-disabled':disabled}" @click="showSignMode()">
<i class="icon-ym icon-ym-signature" />
<view class="title">添加签名</view>
</view>
<image class="jnpf-sign-img" :src="modelValue" mode="scaleToFill" v-show="modelValue "
@tap.stop="handlePreviewImage(modelValue )" />
</view>
<u-action-sheet :list="signOptions" v-model="signMode" @click="handleCommand"></u-action-sheet>
<Sign ref="sign" @input="setValue" />
</template>
<script>
import Sign from './Sign.vue'
export default {
name: 'jnpf-sign',
emits: ['change', 'update:modelValue'],
components: {
Sign
},
props: {
modelValue: {
type: [String, Number, Boolean],
},
fieldKey: {
type: String,
default: ''
},
signTip: {
type: String,
default: '添加签名'
},
disabled: {
type: Boolean,
default: false
},
detailed: {
type: Boolean,
default: false
},
align: {
type: String,
default: 'right'
},
showBtn: {
type: Boolean,
default: true
},
defaultCurrent: {
type: Boolean,
default: false
}, // 默认签名
isInvoke: {
type: Boolean,
default: false
}, // 调用签名
signType: {
type: String,
default: 'currency'
},
},
data() {
return {
innerValue: '',
signMode: false,
signList: [],
signOptions: [{
value: '1',
text: '手写签名'
}, {
value: '2',
text: '调用签名'
}],
}
},
created() {
uni.$on('setSignValue', (res) => {
let fieldKey = uni.getStorageSync('sign-fieldKey')
if (this.fieldKey == fieldKey) this.setValue(res)
})
},
onLoad(e) {
this.$nextTick(async () => {
await this.getSignData()
})
},
onUnload() {
uni.$off('setSignValue')
},
watch: {
modelValue: {
handler(val) {
this.innerValue = val || ''
},
deep: true,
immediate: true
},
},
methods: {
showSignMode() {
if (this.disabled) return
this.signMode = true
},
handleCommand(index) {
if (index !== 1) return this.addSign()
uni.navigateTo({
url: '/pages/apply/interPage/signInvokeList' + '?fieldKey=' + this.fieldKey + '&signVal=' +
encodeURIComponent(this.modelValue)
})
},
addSign() {
if (this.disabled) return
this.$nextTick(() => {
this.$refs.sign.showSignature();
})
},
setValue(val) {
if (!val) return
this.innerValue = val
this.$emit('update:modelValue', val)
this.$emit('change', val)
},
handlePreviewImage(url) {
// #ifndef MP
uni.previewImage({
urls: [url],
current: url,
success: () => {},
fail: () => {
uni.showToast({
title: '预览图片失败',
icon: 'none'
});
}
});
// #endif
}
}
}
</script>
<style lang="scss">
.signature-box {
width: 100%;
border-top: 1rpx solid #fbfbfc;
justify-content: space-between;
.jnpf-sign-btn {
color: #2188ff;
display: flex;
flex-shrink: 0;
height: 56rpx;
.icon-ym-signature {
font-size: 52rpx;
}
.title {
line-height: 56rpx;
font-size: 28rpx;
}
}
.jnpf-sign-img {
width: 160rpx;
height: 56rpx;
flex-shrink: 0;
background-color: #fff !important;
}
}
.jnpf-sign {
width: 100%;
display: flex;
align-items: center;
&.flex-end {
justify-content: flex-end;
}
&.flex-start {
justify-content: flex-start;
}
.jnpf-sign-box {
display: flex;
}
.jnpf-sign-img {
width: 160rpx;
height: 80rpx;
flex-shrink: 0;
}
.jnpf-sign-btn {
color: #2188ff;
width: 100%;
display: flex;
flex-shrink: 0;
height: 56rpx;
&.jnpf-sign-disabled {
color: #9B9B9B !important;
}
.icon-ym-signature {
font-size: 52rpx;
}
.title {
line-height: 56rpx;
font-size: 28rpx;
}
}
}
</style>

View File

@@ -0,0 +1,156 @@
<template>
<view class="jnpf-signature" :class="align=='right'?'flex-end':'flex-start'">
<view class="jnpf-signature-box">
<template v-if="showBtn">
<image class="jnpf-signature-img" :src="jnpf.getAuthImgUrl(innerValue)" mode="scaleToFill"
v-show="innerValue" @tap.stop="handlePreviewImage(innerValue)" />
<view class="jnpf-signature-btn" :class="{'jnpf-signature-disabled':disabled}" v-if="!detailed"
@click="open()">
<i class="icon-ym icon-ym-signature1" />
<view class="title" v-if="!innerValue">电子签章</view>
</view>
</template>
</view>
<MultSelect :show="show" :list="options" @confirm="confirm" @close="show = false" :default-value="defaultValue"
filterable />
</view>
</template>
<script>
import {
getListByIds
} from '@/api/signature.js'
import MultSelect from '@/components/MultSelect'
import jnpf from '@/utils/jnpf'
export default {
name: 'jnpf-sign',
components: {
MultSelect
},
props: {
modelValue: {
type: [String, Number, Boolean],
},
disabled: {
type: Boolean,
default: false
},
detailed: {
type: Boolean,
default: false
},
showBtn: {
type: Boolean,
default: true
},
align: {
type: String,
default: 'right'
},
ableIds: {
type: Array,
default: () => []
}
},
data() {
return {
innerValue: '',
show: false,
options: [],
defaultValue: []
}
},
watch: {
modelValue: {
handler(val) {
this.innerValue = val || ''
},
immediate: true,
}
},
methods: {
getListByIds() {
getListByIds({
'ids': this.ableIds
}).then(res => {
this.options = res.data.list || []
const index = this.options.findIndex(o => this.innerValue === o.icon)
if (index > -1) this.defaultValue = [this.options[index].id]
this.show = true
})
},
open() {
if (this.disabled) return
if (!this.ableIds.length) return this.show = true
if (this.ableIds.length) this.getListByIds()
},
confirm(val) {
if (!val.length) return
this.innerValue = val[0].icon || ''
this.$emit('update:modelValue', this.innerValue)
this.$emit('change', val[0])
},
handlePreviewImage(url) {
// #ifdef H5
uni.previewImage({
urls: [jnpf.getAuthImgUrl(url)],
current: url,
success: () => {},
fail: () => {
uni.showToast({
title: '预览图片失败',
icon: 'none'
});
}
});
// #endif
}
}
}
</script>
<style scoped lang="scss">
.jnpf-signature {
width: 100%;
display: flex;
align-items: center;
&.flex-end {
justify-content: flex-end;
}
&.flex-start {
justify-content: flex-start;
}
.jnpf-signature-box {
display: flex;
}
.jnpf-signature-img {
width: 160rpx;
height: 80rpx;
flex-shrink: 0;
}
.jnpf-signature-btn {
color: #2188ff;
width: 100%;
display: flex;
flex-shrink: 0;
&.jnpf-signature-disabled {
color: #9B9B9B !important;
}
.icon-ym-signature1 {
font-size: 52rpx;
}
.title {
font-size: 28rpx;
}
}
}
</style>

View File

@@ -0,0 +1,87 @@
<template>
<u-slider class="jnpf-slider" :class="{'jnpf-slider-disabled':disabled}" v-model="innerValue" :step="step"
:min="min" :max="max" :disabled="disabled" @end="end">
<view class="slider-badge-button" :class="{'disabled':disabled}">{{innerValue}}</view>
</u-slider>
</template>
<script>
export default {
name: 'jnpf-slider',
props: {
modelValue: {
type: [Number, String],
default: 0
},
min: {
type: Number,
default: 0
},
max: {
type: Number,
default: 100
},
step: {
type: Number,
default: 1
},
disabled: {
type: Boolean,
default: false
},
},
data() {
return {
innerValue: 0
}
},
watch: {
modelValue: {
handler(val) {
this.innerValue = val
},
immediate: true,
deep: true
},
innerValue: {
handler(val) {
this.$emit('update:modelValue', val)
this.$emit('change', val)
},
immediate: true,
deep: true
}
},
methods: {
end() {
this.$emit('update:modelValue', this.innerValue)
this.$emit('change', this.innerValue)
}
}
}
</script>
<style lang="scss" scoped>
.jnpf-slider {
width: 100%;
.slider-badge-button {
padding: 4rpx 6rpx;
background-color: $u-type-primary;
color: #fff;
border-radius: 10rpx;
font-size: 22rpx;
line-height: 1;
&.disabled {
background-color: #E6E6E6 !important;
color: #9B9B9B !important;
}
}
&.jnpf-slider-disabled {
:deep(.u-slider__gap) {
background-color: #E6E6E6 !important;
border-color: #D9D9D9 !important;
}
}
}
</style>

View File

@@ -0,0 +1,58 @@
<template>
<view class="steps-v">
<u-steps :list="list" :mode="mode" name="title" :current="modelValue" :name="name" @change="onStepChange">
</u-steps>
</view>
</template>
<script>
export default {
props: {
modelValue: {
default: 0
},
// 自定义标题key
name: {
type: String,
default: 'title'
},
mode: {
type: String,
default: 'dot'
},
current: {
default: 0
},
list: {
type: Array,
default: () => []
},
},
data() {
return {
stepCurrent: 0
}
},
methods: {
onStepChange(index) {
this.$emit('change', index)
},
}
}
</script>
<style lang="scss">
.steps-v {
background-color: #fff;
padding: 20rpx 0;
width: 100%;
overflow-x: scroll;
.u-steps .u-steps__item {
min-width: unset;
}
.u-steps .u-steps__item .u-steps__item__text--row {
width: 92px;
}
}
</style>

View File

@@ -0,0 +1,72 @@
<template>
<view class="jnpf-switch">
<u-switch v-model="innerValue" :active-value="activeValue" :inactive-value="inactiveValue" :disabled="disabled"
:class="{'jnpf-switch-disabled':disabled}" @change="onChange" :size="size"></u-switch>
</view>
</template>
<script>
export default {
name: 'jnpf-switch',
props: {
modelValue: {
type: [String, Number, Boolean],
},
activeValue: {
type: [String, Number, Boolean],
default: 1
},
inactiveValue: {
type: [String, Number, Boolean],
default: 0
},
size: {
default: 40
},
disabled: {
type: Boolean,
default: false
},
},
data() {
return {
innerValue: ''
}
},
watch: {
modelValue: {
handler(val) {
this.innerValue = !!Number(val)
},
immediate: true,
}
},
methods: {
onChange(val) {
this.$emit('update:modelValue', val)
this.$emit('change', val)
},
}
}
</script>
<style scoped lang="scss">
.jnpf-switch {
width: 100%;
display: flex;
justify-content: flex-end;
align-items: center;
:deep(.u-switch--disabled) {
background-color: #E6E6E6 !important;
border-color: #D9D9D9 !important;
}
.jnpf-switch-disabled {
:deep(.u-switch__node) {
background-color: #E6E6E6 !important;
border-color: #D9D9D9 !important;
}
}
}
</style>

View File

@@ -0,0 +1,31 @@
<template>
<view class="jnpf-text" :style="getTextstyle">{{content}}</view>
</template>
<script>
export default {
name: 'jnpf-text',
props: {
textStyle: {
type: Object,
default: () => ({})
},
content: {
default: ''
}
},
computed: {
getTextstyle() {
return {
...this.textStyle,
'line-height': this.textStyle['line-height'] * 2 + 'rpx',
'font-size': this.textStyle['font-size'] * 2 + 'rpx'
}
}
}
}
</script>
<style lang="scss" scoped>
.jnpf-text {
padding: 20rpx 32rpx;
}
</style>

View File

@@ -0,0 +1,89 @@
<template>
<view :class="['jnpf-textarea',showCount ? 'jnpf-textarea-count' : '']">
<u-input input-align='right' :border="false" type="textarea" v-model="innerValue" :placeholder="placeholder"
:disabled="disabled" @input="onInput" :clearable='disabled ? false : clearable'
:maxlength="maxlength||maxlength===0?maxlength:9999" :class="{'jnpf-textarea-disabled':disabled}" />
<view class="textarea-count" v-if="showCount">
<text>{{ innerValue?String(innerValue).length:0 }}</text><text v-if="maxlength">/{{ maxlength }}</text>
</view>
</view>
</template>
<script>
export default {
name: 'jnpf-textarea',
props: {
modelValue: {
type: String,
default: ''
},
placeholder: {
type: String,
default: '请输入'
},
maxlength: {
type: [Number, String],
default: null
},
disabled: {
type: Boolean,
default: false
},
clearable: {
type: Boolean,
default: false
},
showCount: {
type: Boolean,
default: false
},
},
data() {
return {
innerValue: ''
}
},
watch: {
modelValue: {
handler(val) {
this.innerValue = val
},
immediate: true,
}
},
methods: {
onInput(val) {
this.$emit('update:modelValue', val)
this.$emit('change', val)
},
}
}
</script>
<style lang="scss">
.jnpf-textarea {
position: relative;
width: 100%;
&.jnpf-textarea-count {
padding-bottom: 20rpx;
}
.textarea-count {
color: #909399;
font-size: 24rpx;
position: absolute;
bottom: 4rpx;
right: 0;
line-height: 24rpx;
}
.jnpf-textarea-disabled {
:deep(.uni-textarea-placeholder) {
color: #9B9B9B !important;
}
:deep(.u-input__textarea) {
color: #9B9B9B !important;
}
}
}
</style>

View File

@@ -0,0 +1,80 @@
<template>
<view class="jnpf-time-pickeer">
<JnpfDatePicker v-model="value" :scene="scene" :inputType="inputType" :placeholder="placeholder"
:disabled="disabled" :type="type" :startTime="startTime" :endTime="endTime" :format="format"
:selectType='selectType' @change="change" />
</view>
</template>
<script>
export default {
name: 'jnpf-time-pickeer',
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: 'time'
},
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 {
value: ""
}
},
watch: {
modelValue: {
handler(val) {
this.value = val
},
immediate: true
},
value(val) {
this.$emit('update:modelValue', val)
}
},
methods: {
change(value, type) {
this.$emit('change', value, type)
}
}
}
</script>
<style lang="scss" scoped>
.jnpf-time-pickeer {
width: 100%;
}
</style>

View File

@@ -0,0 +1,53 @@
<template>
<view class="jnpf-time-range">
<JnpfDateRange v-model="value" :placeholder="placeholder" :format='format' :disabled="disabled" :type="type" />
</view>
</template>
<script>
export default {
name: 'jnpf-time-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: 'time'
}
},
data() {
return {
value: ""
}
},
watch: {
modelValue: {
handler(val) {
this.value = val
},
immediate: true
},
value(val) {
this.$emit('update:modelValue', val)
}
}
}
</script>
<style lang="scss" scoped>
.jnpf-time-range {
width: 100%;
}
</style>

View File

@@ -0,0 +1,289 @@
<template>
<view class="u-select">
<u-popup :maskCloseAble="maskCloseAble" mode="bottom" :popup="false" v-model="showPopup" length="auto"
:safeAreaInsetBottom="safeAreaInsetBottom" @close="close" :z-index="uZIndex">
<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()">
{{cancelText}}
</view>
<view class="u-select__header__title">{{title}}</view>
<view class="u-select__header__confirm u-select__header__btn"
:style="{ color: moving ? cancelColor : confirmColor }" hover-class="u-hover-class"
:hover-stay-time="150" @touchmove.stop="" @tap.stop="handleConfirm()">
{{confirmText}}
</view>
</view>
<view class="search-box_sticky" v-if="filterable">
<view class="search-box">
<u-search :placeholder="$t('app.apply.pleaseKeyword')" height="72" :show-action="false"
bg-color="#f0f2f6" shape="square" v-model="filterText">
</u-search>
</view>
</view>
<view class="u-select__body u-select__body__treeSelect">
<view class="tree-box">
<scroll-view :scroll-y="true" style="height: 100%">
<ly-tree ref="tree" :node-key="realProps.value" :tree-data="options" :props="realProps"
:show-node-icon="true" :filter-node-method="filterNode" child-visible-for-filter-node
check-on-click-node :expand-on-click-node="false" default-expand-all
:show-radio="!multiple" :show-checkbox="multiple" />
</scroll-view>
</view>
</view>
</view>
</u-popup>
</view>
</template>
<script>
const defaultProps = {
label: 'fullName',
value: 'id',
icon: 'icon',
children: 'children'
}
import LyTree from '@/components/ly-tree/ly-tree.vue'
export default {
name: "tree-select",
components: {
LyTree
},
props: {
options: {
type: Array,
default () {
return [];
}
},
filterable: {
type: Boolean,
default: false
},
// 是否显示边框
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: 0
},
safeAreaInsetBottom: {
type: Boolean,
default: false
},
// 是否允许通过点击遮罩关闭Picker
maskCloseAble: {
type: Boolean,
default: true
},
defaultValue: {
type: Array,
default: () => []
},
props: {
type: Object,
default: () => ({
label: 'fullName',
value: 'id',
icon: 'icon',
children: 'children'
})
},
// 只能选择最后一层的数值
lastLevel: {
type: Boolean,
default: false
},
// 只能选择最后一层的数值时需要根据lastLevelKey来判断是否最后一层
lastLevelKey: {
type: String,
default: "hasChildren"
},
lastLevelValue: {
default: false
},
multiple: {
type: Boolean,
default: false
},
// 顶部标题
title: {
type: String,
default: ''
},
// 取消按钮的文字
cancelText: {
type: String,
default: '取消'
},
// 确认按钮的文字
confirmText: {
type: String,
default: '确认'
}
},
data() {
return {
filterText: '',
moving: false,
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);
}
},
computed: {
uZIndex() {
// 如果用户有传递z-index值优先使用
return this.zIndex ? this.zIndex : this.$u.zIndex.popup;
},
realProps() {
return {
...defaultProps,
...this.props
}
}
},
methods: {
// 标识滑动开始,只有微信小程序才有这样的事件
pickstart() {
// #ifdef MP-WEIXIN
this.moving = true;
// #endif
},
// 标识滑动结束
pickend() {
// #ifdef MP-WEIXIN
this.moving = false;
// #endif
},
filterNode(value, data) {
if (!value) return true;
return data[this.realProps.label].indexOf(value) !== -1;
},
init() {
this.filterText = ''
this.setSelectValue();
},
// 获取默认选中的值
setSelectValue() {
this.$nextTick(() => {
this.$refs.tree.setCheckedKeys(this.defaultValue)
})
},
close() {
this.$emit('close');
},
handleConfirm() {
// #ifdef MP-WEIXIN
if (this.moving) return;
// #endif
let selectValue = this.$refs.tree.getCheckedNodes()
if (this.lastLevel) {
selectValue = selectValue.filter(o => o[this.lastLevelKey] == this.lastLevelValue)
}
if (!selectValue.length) return
this.$emit('confirm', selectValue);
this.close();
}
}
};
</script>
<style scoped lang="scss">
.u-select {
&__action {
position: relative;
line-height: $u-form-item-height;
height: $u-form-item-height;
&__icon {
position: absolute;
right: 20rpx;
top: 50%;
transition: transform .4s;
transform: translateY(-50%);
z-index: 1;
&--reverse {
transform: rotate(-180deg) translateY(50%);
}
}
}
&__hader {
&__title {
color: $u-content-color;
}
}
&--border {
border-radius: 6rpx;
border-radius: 4px;
border: 1px solid $u-form-item-border-color;
}
&__header {
display: flex;
align-items: center;
justify-content: space-between;
height: 80rpx;
padding: 0 40rpx;
}
&__body {
width: 100%;
height: 500rpx;
overflow: hidden;
background-color: #fff;
.tree-box {
height: 100%;
}
&__picker-view {
height: 100%;
box-sizing: border-box;
&__item {
display: flex;
align-items: center;
justify-content: center;
font-size: 32rpx;
color: $u-main-color;
padding: 0 8rpx;
}
}
}
}
</style>

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