优化组件使用

This commit is contained in:
bb_pan 2025-07-11 16:51:18 +08:00
parent b31cb9aa72
commit 18dbf7481d
5 changed files with 330 additions and 27 deletions

View File

@ -132,7 +132,7 @@
<script setup>
import { onLoad, onShow, onBackPress } from '@dcloudio/uni-app'
import { ref, reactive } from 'vue'
import eselect from '@/components/tree-select/eselect.vue'
import eselect from '@/pages/materialsStation/toolsLease/components/eselect.vue'
import {
getTeamListApi,
getProjectList,

View File

@ -541,6 +541,8 @@ const ocrClick = () => {
box-shadow: 0 4rpx 16rpx rgba(0, 0, 0, 0.06);
margin-bottom: 24rpx;
.item-btn {
padding-left: 3px;
padding-right: 3px;
@media (min-width: 768px) {
width: 100px;
font-size: 15px;

View File

@ -0,0 +1,282 @@
<template>
<view class="ep-picker-box">
<!-- 蒙版区域 开始 -->
<view class="ep-mask-box" v-show="show" @click="show = false"></view>
<!-- 蒙版区域 开始 -->
<!-- 输入框区域 开始 -->
<view class="ep-input-box" @click="openOptions">
<!-- <view style="display: flex;align-items: center;min-height: 36px;font-size: 28rpx;">{{showLabel}}</view> -->
<uni-easyinput
v-model="showLabel"
maxlength="20"
:placeholder="placeholder"
style="width: 100%; font-size: 28rpx"
@input="inputChange"
@clear="handleClear"
:disabled="disabled"
/>
<!-- <image src="@/static/img/select.png" mode="" style="width: 36rpx;height: 36rpx;"></image> -->
</view>
<!-- 输入框区域 结束 -->
<!-- 弹出的下拉区域 开始 -->
<view v-show="show" class="ep-picker-content-wrap">
<scroll-view class="ep-picker-content" :scroll-y="true">
<!-- 展示下拉项列表 开始 -->
<leoTree :data="selectData" @node-click="nodeClick" :defaultProps="defaultProps"></leoTree>
<!-- 展示下拉项列表 结束 -->
<!-- 下拉列表为空 开始 -->
<view v-if="selectData.length == 0" class="option-no-data">无数据...</view>
<!-- 下拉列表为空 结束 -->
</scroll-view>
<text class="triangle"></text>
</view>
<!-- 弹出的下拉区域 结束 -->
</view>
</template>
<script>
import leoTree from '@/components/tree-select/tree/tree.vue'
export default {
name: 'eselect',
components: {
leoTree,
},
data() {
return {
show: false,
left: 0,
showLabel: '',
placeholder: '请选择',
selectData: [],
}
},
props: {
value: {
type: [String, Number],
default: '',
},
options: {
type: Array,
default: function () {
return []
},
},
value_key: {
type: String,
default: 'value',
},
label_key: {
type: String,
default: 'label',
},
defaultProps: {
type: Object,
default: () => {
return {
id: 'id',
children: 'children',
label: 'name',
}
},
},
detailValue: {
type: [String, Number],
default: '',
},
disabled: {
type: Boolean,
default: false,
},
},
mounted() {
setTimeout(() => {
// console.log('🚀 ~ created ~ this.detailValue:', this.detailValue)
if (this.detailValue) {
this.showLabel = this.detailValue
} else {
this.showLabel = ''
}
}, 200)
},
methods: {
//
openOptions() {
if (this.disabled) return
if (this.showLabel == '') {
this.selectData = this.options
} else {
this.selectData = this.mapTree(this.showLabel, this.options)
}
this.show = true
},
nodeClick(e) {
if (!e.children) {
this.show = false
// this.showLabel = e.name
this.$emit('change', e)
}
},
clearInput() {
this.showLabel = ''
this.selectData = this.options
},
handleClear() {
this.$emit('clear')
},
//
inputChange(e) {
// console.log(e)
if (e == '') {
this.selectData = this.options
} else {
this.selectData = this.mapTree(e, this.options)
}
// console.log(this.selectData)
},
mapTree(value, arr) {
let newarr = []
arr.forEach((element) => {
if (element.name.indexOf(value) > -1) {
//
newarr.push(element)
} else {
if (element.children && element.children.length > 0) {
let redata = this.mapTree(value, element.children)
if (redata && redata.length > 0) {
let obj = {
...element,
children: redata,
expanded: true, //
}
newarr.push(obj)
}
}
}
})
return newarr
},
},
}
</script>
<style scoped>
/* 引入字体图标 */
/* @import './iconfont.css'; */
.ep-picker-box {
/* width:100%; */
/* box-sizing: border-box; */
position: relative;
display: flex;
align-items: center;
font-size: 20rpx;
color: #0f274b;
width: 130rpx;
height: 48rpx;
border-radius: 12rpx 12rpx 12rpx 12rpx;
/* border: 2rpx solid #3888FF; */
background: #fff;
}
.ep-mask-box {
position: fixed;
z-index: 99999;
top: 0;
right: 0;
left: 0;
bottom: 0;
background: none;
}
.ep-input-box {
border-radius: 4px;
position: relative;
cursor: pointer;
width: 100%;
height: 100%;
display: flex;
justify-content: space-between;
align-items: center;
overflow: auto;
text-overflow: ellipsis;
}
/* 展开收起箭头样式 */
.ep-input-box .iconfont {
position: absolute;
top: 50%;
right: 5px;
font-size: 20px;
transform: translateY(-50%);
color: #b8b8b8;
}
/* 下拉容器样式 外层 */
.ep-picker-content-wrap {
max-height: 48vh;
width: 100%;
position: absolute;
top: 88rpx;
left: 0;
z-index: 999999;
padding-top: 6px;
}
/* 下拉容器样式 内层 */
.ep-picker-content-wrap .ep-picker-content {
background-color: #fff;
color: #999;
padding: 3px 0;
box-shadow: 0 0 20rpx 5rpx rgb(0 0 0 / 30%);
border-radius: 5px;
max-height: 46vh;
}
/* 下拉项通用样式 */
.ep-picker-content-wrap .ep-picker-content .option-item {
padding: 20rpx 12rpx 14rpx;
font-size: 20rpx;
cursor: pointer;
border-bottom: 1rpx solid #dfdddd;
word-break: break-all;
}
.ep-picker-content-wrap .ep-picker-content .option-item:last-child {
border-bottom: none;
}
/* 无下拉项数据时样式 */
.ep-picker-content-wrap .ep-picker-content .option-no-data {
padding: 8px 18px;
cursor: text;
color: #999;
text-align: center;
}
/* 鼠标移入下拉项样式 */
.ep-picker-content-wrap .ep-picker-content .option-item:hover {
background-color: #f5f7fa;
}
/* 已选中的下拉项样式 */
.ep-picker-content-wrap .ep-picker-content .option-item.active {
/* color: #007AFF; */
}
/* 下拉容器指示箭头样式 */
.ep-picker-content-wrap .triangle {
width: 0;
height: 0;
border-top: 6px solid rgba(0, 0, 0, 0);
border-right: 6px solid rgba(0, 0, 0, 0);
border-bottom: 6px solid #fff;
border-left: 6px solid rgba(0, 0, 0, 0);
position: absolute;
top: -6px;
left: 50%;
transform: translateX(-50%);
box-sizing: content-box;
}
</style>

View File

@ -90,10 +90,10 @@
<uni-th width="50" align="center">序号</uni-th>
<uni-th width="160" align="center">类型名称</uni-th>
<uni-th width="180" align="center">规格型号</uni-th>
<uni-th width="100" align="center">{{ opts.isOut ? '出库数' : '领用数' }}</uni-th>
<uni-th width="80" align="center">在库数</uni-th>
<uni-th width="80" align="center">在用数</uni-th>
<uni-th width="80" align="center" v-if="opts.isOut">预领数</uni-th>
<uni-th width="100" align="center">{{ opts.isOut ? '出库数' : '领用数' }}</uni-th>
<uni-th width="100" align="center">操作</uni-th>
</uni-tr>
<uni-tr v-for="(item, index) in tableData" :key="index">
@ -102,15 +102,13 @@
<uni-td align="center">
<view class="name">{{ item.typeName }}</view>
</uni-td>
<uni-td align="center">{{ item.storageNum }}</uni-td>
<uni-td align="center">{{ item.useNum }}</uni-td>
<uni-td align="center" v-if="opts.isOut">{{ item.preNum }}</uni-td>
<uni-td align="center"
><uni-easyinput
v-if="item.manageType == 1 || !opts.isOut"
v-model="item.preNum"
placeholder="请输入数量"
type="number"
:clearable="false"
@change="checkPerNum(item)"
></uni-easyinput>
<!-- 编码 -->
@ -118,6 +116,9 @@
!item.maCodeList || item.maCodeList.length == 0 ? '选择编码' : item.maCodeList.length
}}</span>
</uni-td>
<uni-td align="center">{{ item.storageNum }}</uni-td>
<uni-td align="center">{{ item.useNum }}</uni-td>
<uni-td align="center" v-if="opts.isOut">{{ item.preNum }}</uni-td>
<uni-td align="center">
<view
style="
@ -176,7 +177,7 @@
<script setup>
import { onLoad, onShow, onBackPress } from '@dcloudio/uni-app'
import { ref, reactive } from 'vue'
import eselect from '@/components/tree-select/eselect.vue'
import eselect from '@/pages/materialsStation/toolsLease/components/eselect.vue'
import {
getBmTeamList,
getProjectList,

View File

@ -2,8 +2,17 @@
<view class="uni-stat__select">
<span v-if="label" class="uni-label-text hide-on-phone">{{ label + '' }}</span>
<view class="uni-stat-box" :class="{ 'uni-stat__actived': current }">
<view class="uni-select" :class="{ 'uni-select--disabled': disabled }">
<view class="uni-select__input-box" @click="toggleSelector">
<view
class="uni-select"
:class="{ 'uni-select--disabled': disabled }"
:style="{ border: showInput ? 'none' : '1px solid #DCDFE6' }"
>
<!-- 下拉框显示区域 -->
<view
class="uni-select__input-box"
@click="toggleSelector"
v-if="!showInput || !filterable"
>
<view v-if="current" class="uni-select__input-text">{{ textShow }}</view>
<view v-else class="uni-select__input-text uni-select__input-placeholder">{{
typePlaceholder
@ -15,22 +24,25 @@
<uni-icons :type="showSelector ? 'top' : 'bottom'" size="14" color="#999" />
</view>
</view>
<!-- 输入框显示区域 -->
<view class="uni-select__input-box" v-else-if="filterable && showInput">
<uni-easyinput
v-model="searchValue"
:placeholder="typePlaceholder"
clearable
@input="onSearchInput"
@blur="onInputBlur"
:focus="showInput"
/>
</view>
<view class="uni-select--mask" v-if="showSelector" @click="toggleSelector" />
<view class="uni-select__selector" :style="getOffsetByPlacement" v-if="showSelector">
<view
:class="placement == 'bottom' ? 'uni-popper__arrow_bottom' : 'uni-popper__arrow_top'"
></view>
<!-- 🔍 搜索输入框 filterable 控制 -->
<view v-if="filterable" class="uni-select__search-box">
<uni-easyinput
v-model="searchValue"
placeholder="请输入关键词"
clearable
@input="onSearchInput"
/>
</view>
<scroll-view scroll-y="true" class="uni-select__selector-scroll">
<view class="uni-select__selector-empty" v-if="filteredData.length === 0">
<text>{{ emptyTips }}</text>
@ -129,6 +141,7 @@ export default {
data() {
return {
showSelector: false,
showInput: false,
current: '',
searchValue: '',
mixinDatacomResData: [],
@ -165,7 +178,7 @@ export default {
},
filteredData() {
const keyword = this.searchValue.trim().toLowerCase()
if (!this.filterable || !keyword) return this.mixinDatacomResData
if (!keyword) return this.mixinDatacomResData
return this.mixinDatacomResData.filter((item) =>
this.formatItemName(item).toLowerCase().includes(keyword),
)
@ -232,6 +245,7 @@ export default {
change(item) {
if (!item.disable) {
this.showSelector = false
this.showInput = false
this.searchValue = ''
this.current = this.formatItemName(item)
this.emit(item.value)
@ -245,12 +259,22 @@ export default {
},
toggleSelector() {
if (this.disabled) return
this.showSelector = !this.showSelector
if (!this.showSelector && this.filterable) this.searchValue = ''
this.showInput = true
this.showSelector = true
this.searchValue = ''
},
onSearchInput(val) {
this.searchValue = val
},
onInputBlur() {
// blur
setTimeout(() => {
if (this.showSelector) {
this.showInput = false
this.showSelector = false
}
}, 200)
},
formatItemName(item) {
if (this.format) {
let str = this.format
@ -282,12 +306,6 @@ export default {
</script>
<style lang="scss">
.uni-select__search-box {
padding: 5px 10px;
border-bottom: 1px solid #eee;
background-color: #f9f9f9;
}
.uni-stat__select {
display: flex;
align-items: center;