Files
hospital-rescue-app-v2/uni_modules/tmx-ui/components/x-picker-item/x-picker-item.uvue
T
2026-09-24 16:25:22 +08:00

409 lines
9.7 KiB
Plaintext

<script lang="ts">
import { PropType } from "vue"
import { getUid } from "../../core/util/xCoreUtil.uts"
import { checkIsCssUnit, rpx2px,getUnit } from "../../core/util/xCoreUtil.uts"
import { xConfig } from "../../config/xConfig.uts"
// import pickerItem from './picker-item.uvue'
import { X_PICKER_X_ITEM } from "../../interface.uts"
/**
* @name 选择容器子节点 xPickerViewItem
* @description xPickerView内部子组件,不可引用
* @page /pages/index/picker-view
* @category 表单组件
* @constant 平台兼容
* | Harmony | H5 | andriod | IOS | 小程序 | UTS | UNIAPP-X SDK | version |
| --- | --- | --- | --- | --- | --- | --- | --- |
| ☑ | ☑ | ☑️ | ☑️ | ☑️ | ☑️ | 4.76+ | 1.1.18 |
*/
export default {
// components: {
// 'picker-item': pickerItem
// },
data() {
return {
boxHeight: 0,
id: ('xPickerItem-' + getUid()) as string,
nowCurrentIndex: [0],
tid: 0,
tid2:0,
tid3:3,
}
},
emits: ['changeDeep', 'countChange'],
props: {
cellHeight: {
type: String,
default: '60'
},
duration: {
type: Number,
default: 350
},
list: {
type: Array as PropType<X_PICKER_X_ITEM[]>,
default: () : X_PICKER_X_ITEM[] => [] as X_PICKER_X_ITEM[]
},
wrapWight: {
type: Number,
default: 0
},
parentIndex: {
type: Number,
default: 0
},
selectedIndex: {
type: Array as PropType<number[]>,
default: () : number[] => [] as number[]
},
cellUnits: {
type: Array as PropType<string[]>,
default: () : string[] => [] as string[]
},
unitsFontSize:{
type:String,
default:'12'
},
fontSize: {
type: String,
default: "15"
}
},
mounted() {
let t = this;
this.pushDeepCount(this.parentIndex)
t.setNowCurrentIndex(false)
},
beforeUnmount() {
clearTimeout(this.tid)
clearTimeout(this.tid2)
clearTimeout(this.tid3)
},
computed: {
_fontSize() : string {
let fontSize = checkIsCssUnit(this.fontSize, xConfig.unit)
if(xConfig.fontScale==1) return fontSize;
let sizeNumber = parseInt(fontSize)
if(isNaN(sizeNumber)){
sizeNumber = 16
}
return (sizeNumber*xConfig.fontScale).toString() + getUnit(this.fontSize)
},
_parentIndex() : number {
return this.parentIndex
},
_cellHeight() : string {
return checkIsCssUnit(this.cellHeight, xConfig.unit)
},
_boxHeight() : number {
let p = parseInt(this.cellHeight);
if (this.cellHeight.lastIndexOf('rpx') > -1) {
p = rpx2px(p);
}
return p
},
_totalHeight() : number {
return (Math.max(1, this._list.length) + 4) * this._boxHeight
},
_wrapWight() : number {
return this.wrapWight
},
_selectedIndex() : number[] {
return this.selectedIndex
},
_unitsName() : string {
if (this.cellUnits.length == 0) return ""
if (this.cellUnits.length < this._parentIndex) return ""
return this.cellUnits[this._parentIndex]! as string
},
_cellUnits() : string[] {
return this.cellUnits as string[]
},
_list(): X_PICKER_X_ITEM[] {
return this.list
},
_nowChildren(): X_PICKER_X_ITEM[] {
if(this._list.length==0) return [] as X_PICKER_X_ITEM[]
let index = Math.max(0,Math.min(this.nowCurrentIndex[0],this._list.length-1))
let item = this._list[index];
return item.children
},
_isDark():boolean{
return xConfig.dark=='dark'
},
_maskStyle():string{
if(this._isDark){
return 'background-image:linear-gradient(180deg,rgba(0, 0, 0, 0),rgba(0, 0, 0, 0)),linear-gradient(0deg, rgba(0, 0, 0, 0),rgba(0, 0, 0, 0))'
}
return 'background-image:linear-gradient(180deg,rgba(255,255,255,0),rgba(255,255,255,0)),linear-gradient(0deg, rgba(255,255,255,0),rgba(255,255,255,0))'
}
},
watch: {
list(){
let t = this;
t.setNowCurrentIndex(true)
},
selectedIndex(newvaluse : number[]) {
let t = this;
t.setNowCurrentIndex(false)
}
},
methods: {
setNowCurrentIndex(isTmChange:boolean){
let t = this;
clearTimeout(this.tid3)
// #ifdef MP-WEIXIN
this.tid3 = setTimeout(function() {
t.nowCurrentIndex = [t.getIndexByid()] as number[]
if(isTmChange){
t.mchange(t.nowCurrentIndex)
}
}, 15);
// #endif
// #ifndef MP-WEIXIN
t.nowCurrentIndex = [t.getIndexByid()] as number[]
if(isTmChange){
t.mchange(t.nowCurrentIndex)
}
// #endif
},
getIndexByid():number{
let index = 0
if(this._selectedIndex.length==0) return index;
if(this.parentIndex>this._selectedIndex.length) return index
index = this._selectedIndex[this.parentIndex]
index = Math.max(0,Math.min(index,this._list.length-1))
return index;
},
getIdByindex():string|null{
let id = null;
if(this._list.length==0) return id
if(this.nowCurrentIndex.length==0) return id;
let index = Math.max(0,Math.min(this.nowCurrentIndex[0],this._list.length-1))
return this._list[index].id
},
mchange(indexs : number[]) {
let index = indexs[0];
let parentIndex = this.parentIndex;
let ids = this._selectedIndex.slice(0)
if(parentIndex<=ids.length-1){
ids.splice(parentIndex,1,index)
}else{
for(let i=0;i<this.parentIndex;i++){
ids.push(0)
}
ids.push(index)
}
this.$emit("changeDeep", ids)
},
change(s : number[]) {
this.$emit("changeDeep", s)
},
pushDeepCount(n:number){
this.$emit("countChange", n)
},
onChange(event : UniPickerViewChangeEvent) {
if (event.detail.value.length == 0 || this._list.length==0) return;
let indexs = event.detail.value!;
if (indexs.join('') == this.nowCurrentIndex.join('')) return;
let index = indexs[0]
index = Math.max(0,Math.min(index,this._list.length-1))
let item = this._list[index]
if (item.disabled) {
// 寻找最近的未禁用项
let left = index - 1
let right = index + 1
let found = -1
while (left >= 0 || right < this._list.length) {
if (left >= 0 && !this._list[left].disabled) { found = left; break }
if (right < this._list.length && !this._list[right].disabled) { found = right; break }
left -= 1
right += 1
}
if (found >= 0) {
index = found
indexs = [index]
} else {
// 全部禁用,回退到0
index = 0
indexs = [0]
}
}
this.nowCurrentIndex = indexs;
this.mchange(indexs)
}
},
}
</script>
<template>
<view>
<view class="xPickerViewUnit" v-if="_unitsName!=''">
<x-text :font-size="unitsFontSize" class="xPickerViewUnitText">{{_unitsName}}</x-text>
</view>
<view class="xPickerView">
<view style="padding: 0 2.5px;">
<picker-view :value="nowCurrentIndex" @change="onChange"
:style="{height:'250px',width:(_wrapWight-5)+'px'}"
:mask-style="`${_maskStyle}`"
:mask-bottom-style="_maskStyle"
:mask-top-style="_maskStyle"
:indicator-class="_isDark?'indicatorClassDark':'indicatorClassLight'"
:indicator-style="`height:50px;backgroundColor:${_isDark?'rgba(255,255,255,0.05)':'rgba(0,0,0,0.05)'};border-radius:10px`">
<picker-view-column>
<view :style="{height:'50px'}" v-for="(item,index) in _list" :key="index"
class="xPickerViewWrapCoumn">
<text class="xPickerViewWrapCoumnText" :style="{
fontSize:_fontSize,
lineHeight: 1.1,
fontWeight:nowCurrentIndex[0]==index?'bold':'inherit',
opacity:item.disabled?0.4:(nowCurrentIndex[0]==index?1:0.6),
color: _isDark?'rgba(255,255,255,0.8)':'#000000'}">
{{item.title}}
</text>
</view>
</picker-view-column>
</picker-view>
</view>
<x-picker-item @countChange="pushDeepCount" :font-size="fontSize" :cellUnits="_cellUnits" @changeDeep="change" :selectedIndex="_selectedIndex"
:wrapWight="_wrapWight" :parentIndex="_parentIndex+1" v-if="_nowChildren.length>0" :list="_nowChildren"
:cell-height="_cellHeight">
</x-picker-item>
</view>
</view>
</template>
<style>
/* #ifdef WEB */
.uni-picker-view-indicator:after,
.uni-picker-view-indicator:before {
border: none;
}
/* #endif */
/* #ifdef MP-WEIXIN */
.indicatorClassDark:after,
.indicatorClassDark:before,
.indicatorClassLight:after,
.indicatorClassLight:before {
content:'';
height: 0px;
width: 100%;
border-color: transparent;
}
.indicatorClassDark{
background-color: rgba(255,255,255,0.05);
}
.indicatorClassLight{
background-color: rgba(0,0,0,0.05);
}
/* #endif */
.xPickerViewUnit {
display: flex;
flex-direction: row;
justify-content: center;
padding: 8px;
}
.xPickerViewUnitText {
font-size: 12px;
color: #888;
font-weight: bold;
}
.xPickerViewWrapCoumnText {
margin:0 6px;
width: 100%;
text-align: center;
/* lines: 2; */
/* #ifdef WEB */
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
text-overflow: ellipsis;
overflow: hidden;
word-break: break-all;
/* #endif */
}
.xPickerView {
display: flex;
flex-direction: row;
}
.xPickerViewWrap {
position: relative;
}
.xPickerContent {
position: absolute;
left: 0;
top: 0;
width: 100%;
z-index: 5;
}
.xPickerMasker {
display: flex;
flex-direction: row;
align-items: center;
justify-content: center;
pointer-events: none;
height: 100%;
width: 100%;
top: 0px;
left: 0px;
position: absolute;
}
.xPickErBar {
background-color: #f5f5f5;
border-radius: 10px;
margin: 0 3px;
flex: 1;
}
.xPickerContent {
transition-duration: 350ms;
transition-property: left, right, top, bottom;
transition-timing-function: cubic-bezier(0, 0.55, 0.45, 1);
}
.xPickerViewWrapCoumn {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
/* background-color: #f5f5f5; */
}
</style>