点口管理
This commit is contained in:
@@ -3,8 +3,6 @@ import {
|
||||
post
|
||||
} from '@/utils/request.js'
|
||||
|
||||
// BaseInfo/getProjectWorkArea?projectId=0792b983-4de2-44d5-adba-361b7fc99a97&
|
||||
|
||||
/**
|
||||
* 请求单位工程
|
||||
*/
|
||||
|
||||
@@ -6,4 +6,9 @@ import {
|
||||
/**
|
||||
* 获取焊接首页数据
|
||||
*/
|
||||
export const reqHJIndexData = (projectId)=>get(`HJGLIndex/GetJGLIndexItem?projectId=${projectId}`)
|
||||
export const reqHJIndexData = (projectId)=>get(`HJGLIndex/GetJGLIndexItem?projectId=${projectId}`)
|
||||
|
||||
/**
|
||||
* 获取点口管理列表
|
||||
*/
|
||||
export const reqGetNotEndPointBatch = (unitWorkId,projectId)=>get(`NDETrust/getNotEndPointBatch?unitWorkId=${unitWorkId}&projectId=${projectId}`)
|
||||
+125
-1
@@ -44,4 +44,128 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
.nbd-select {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
height: 100%;
|
||||
background: #ffffff;
|
||||
border-radius: 24rpx 24rpx 0 0;
|
||||
overflow: hidden;
|
||||
|
||||
&-header {
|
||||
padding: 24rpx 30rpx;
|
||||
border-bottom: 1rpx solid #e8e8e8;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
background: #fafbfc;
|
||||
|
||||
.u-size-mini{
|
||||
padding: 0 30rpx !important;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.nbd-select-title-wrap {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
.nbd-select-title {
|
||||
font-size: 30rpx;
|
||||
font-weight: 600;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.nbd-select-tip {
|
||||
font-size: 24rpx;
|
||||
color: #999;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&-filter {
|
||||
padding: 20rpx 32rpx;
|
||||
border-bottom: 1rpx solid #e8e8e8;
|
||||
background: #fafbfc;
|
||||
|
||||
.search-box {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
background: #ffffff;
|
||||
border-radius: 36rpx;
|
||||
padding: 0 24rpx;
|
||||
height: 64rpx;
|
||||
|
||||
.search-input {
|
||||
flex: 1;
|
||||
font-size: 28rpx;
|
||||
color: #333;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.search-clear {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 4rpx;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&-inner {
|
||||
flex: 1;
|
||||
overflow-y: auto;
|
||||
background: #ffffff;
|
||||
&-wrap {
|
||||
padding: 12rpx 0 30rpx;
|
||||
}
|
||||
}
|
||||
|
||||
&-empty {
|
||||
padding: 80rpx 0;
|
||||
}
|
||||
|
||||
&-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: 24rpx 30rpx;
|
||||
border-bottom: 1rpx solid #f5f6f8;
|
||||
transition: all 0.2s;
|
||||
background: #ffffff;
|
||||
|
||||
&:nth-of-type(2n) {
|
||||
background: #fafbfc;
|
||||
}
|
||||
|
||||
&:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
&.active {
|
||||
background: rgba(41, 121, 255, 0.08);
|
||||
border-left: 4rpx solid $u-type-primary;
|
||||
padding-left: 26rpx;
|
||||
|
||||
.nbd-select-item-text {
|
||||
color: $u-type-primary;
|
||||
font-weight: 500;
|
||||
}
|
||||
}
|
||||
|
||||
.nbd-select-item-text {
|
||||
flex: 1;
|
||||
font-size: 28rpx;
|
||||
color: #333;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.nbd-select-checkbox {
|
||||
margin-left: 16rpx;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -195,6 +195,14 @@
|
||||
grid-template-columns: repeat(4, 1fr);
|
||||
gap: 24rpx 16rpx;
|
||||
overflow-x: hidden;
|
||||
|
||||
.empty-tip {
|
||||
grid-column: 1 / -1;
|
||||
text-align: center;
|
||||
padding: 40rpx 0;
|
||||
font-size: 26rpx;
|
||||
color: #999;
|
||||
}
|
||||
}
|
||||
|
||||
.grid-item {
|
||||
@@ -351,4 +359,143 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 列表页通用样式
|
||||
.page-list {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
height: 100vh;
|
||||
background: #f5f6f8;
|
||||
|
||||
// 头部过滤区域
|
||||
.filter-header {
|
||||
background: #ffffff;
|
||||
padding: 20rpx 24rpx;
|
||||
border-bottom: 1rpx solid #f0f0f0;
|
||||
|
||||
.filter-row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 16rpx;
|
||||
}
|
||||
|
||||
// 选择按钮
|
||||
.project-select-btn {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: 12rpx 24rpx;
|
||||
background: #f5f6f8;
|
||||
border-radius: 12rpx;
|
||||
max-height: 70rpx;
|
||||
|
||||
.select-text {
|
||||
font-size: 28rpx;
|
||||
color: #333;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
flex: 1;
|
||||
margin-right: 12rpx;
|
||||
}
|
||||
}
|
||||
|
||||
.refresh-btn {
|
||||
padding: 8rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
||||
.rotating {
|
||||
animation: rotate 1s linear infinite;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes rotate {
|
||||
from { transform: rotate(0deg); }
|
||||
to { transform: rotate(360deg); }
|
||||
}
|
||||
|
||||
// 列表区域
|
||||
.list-scroll {
|
||||
flex: 1;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
// 加载中
|
||||
.loading-box {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
height: 100%;
|
||||
padding: 80rpx 0;
|
||||
|
||||
.loading-text {
|
||||
margin-top: 20rpx;
|
||||
font-size: 26rpx;
|
||||
color: #999;
|
||||
}
|
||||
}
|
||||
|
||||
.list-wrap {
|
||||
padding: 24rpx;
|
||||
}
|
||||
|
||||
// 列表项:序号 + 标题 + 箭头
|
||||
.list-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 24rpx 28rpx;
|
||||
background-color: #ffffff;
|
||||
margin-bottom: 20rpx;
|
||||
border-radius: 12rpx;
|
||||
&:active {
|
||||
background: #f8f9fa;
|
||||
}
|
||||
|
||||
.item-index {
|
||||
width: 44rpx;
|
||||
height: 44rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
background: #f0f3ff;
|
||||
color: $u-type-primary;
|
||||
font-size: 24rpx;
|
||||
font-weight: 600;
|
||||
border-radius: 50%;
|
||||
margin-right: 20rpx;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.item-title {
|
||||
flex: 1;
|
||||
font-size: 30rpx;
|
||||
font-weight: 500;
|
||||
color: #333;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
}
|
||||
|
||||
.loading-more {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
padding: 32rpx 0;
|
||||
color: #999;
|
||||
font-size: 24rpx;
|
||||
}
|
||||
|
||||
.no-more {
|
||||
text-align: center;
|
||||
padding: 32rpx 0;
|
||||
color: #ccc;
|
||||
font-size: 24rpx;
|
||||
}
|
||||
}
|
||||
@@ -1,163 +0,0 @@
|
||||
<template>
|
||||
<u-popup v-model="visible" mode="bottom" height="80%">
|
||||
<view class="project-select">
|
||||
<view class="project-select-btns">
|
||||
<u-button size="mini" type="info" @click="handleCancel">取消</u-button>
|
||||
<text></text>
|
||||
<u-button size="mini" type="primary" @click="handleConfirm">确定</u-button>
|
||||
</view>
|
||||
<view class="project-select-filter">
|
||||
<u-search placeholder="请输入项目名称" height="60" v-model="searchKey" :show-action="false"
|
||||
@change="handleSearchKey"></u-search>
|
||||
</view>
|
||||
<scroll-view scroll-y="true" class="project-select-inner">
|
||||
<view class="project-select-inner-wrap">
|
||||
<view class="li" v-for="(item,idx) in filteredList" :key="idx"
|
||||
:class="selectObj && selectObj[props.valueKey] == item[props.valueKey] ? 'active' : ''"
|
||||
@click="handerChangList(item)"
|
||||
>
|
||||
{{ item[props.labelKey] }}
|
||||
</view>
|
||||
<view v-if="filteredList.length === 0" class="empty-tip">暂无匹配项目</view>
|
||||
</view>
|
||||
</scroll-view>
|
||||
</view>
|
||||
</u-popup>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import {
|
||||
ref,
|
||||
watch,
|
||||
computed
|
||||
} from 'vue';
|
||||
|
||||
const props = defineProps({
|
||||
modelValue: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
searchKey: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
list: {
|
||||
type: Array,
|
||||
default: () => []
|
||||
},
|
||||
labelKey: {
|
||||
type: String,
|
||||
default: 'label'
|
||||
},
|
||||
valueKey: {
|
||||
type: String,
|
||||
default: 'value'
|
||||
},
|
||||
selectId: {
|
||||
type: String,
|
||||
default: ''
|
||||
}
|
||||
})
|
||||
|
||||
const emit = defineEmits(['update:modelValue', 'cancel', 'confirm', 'searchChange'])
|
||||
|
||||
const visible = ref(false)
|
||||
const searchKey = ref("")
|
||||
|
||||
const selectObj = ref(null)
|
||||
|
||||
// 过滤后的列表
|
||||
const filteredList = computed(() => {
|
||||
if (!props.searchKey) return props.list
|
||||
return props.list.filter(item =>
|
||||
item[props.labelKey]?.includes(props.searchKey)
|
||||
)
|
||||
})
|
||||
|
||||
watch(() => props.modelValue, (val) => {
|
||||
visible.value = val
|
||||
if(val){
|
||||
const selectedItem = props.list.find(item => item[props.valueKey] === props.selectId)
|
||||
if (selectedItem) {
|
||||
selectObj.value = selectedItem
|
||||
} else {
|
||||
selectObj.value = null
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
watch(visible, (val) => {
|
||||
emit('update:modelValue', val)
|
||||
})
|
||||
const handerChangList = (item)=>{
|
||||
selectObj.value = item
|
||||
}
|
||||
// 点击取消
|
||||
const handleCancel = () => {
|
||||
emit('update:modelValue', false)
|
||||
}
|
||||
// 点击确认
|
||||
const handleConfirm = () => {
|
||||
emit("confirm", selectObj.value)
|
||||
}
|
||||
// 搜索
|
||||
const handleSearchKey = (val) => {
|
||||
emit('searchChange', val)
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.project-select {
|
||||
height: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
background: #fff;
|
||||
border-radius: 24rpx 24rpx 0 0;
|
||||
|
||||
.project-select-btns {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 24rpx 32rpx;
|
||||
border-bottom: 1rpx solid #f0f0f0;
|
||||
}
|
||||
|
||||
.project-select-filter {
|
||||
padding: 16rpx 32rpx;
|
||||
border-bottom: 1rpx solid #f0f0f0;
|
||||
}
|
||||
|
||||
.project-select-inner {
|
||||
flex: 1;
|
||||
overflow-y: auto;
|
||||
|
||||
.project-select-inner-wrap {
|
||||
padding: 0 32rpx 32rpx;
|
||||
|
||||
.li {
|
||||
padding: 28rpx 0;
|
||||
border-bottom: 1rpx solid #f5f6f8;
|
||||
font-size: 28rpx;
|
||||
color: #333;
|
||||
transition: all 0.2s;
|
||||
|
||||
&:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
&.active {
|
||||
color: $u-type-primary;
|
||||
font-weight: 500;
|
||||
}
|
||||
}
|
||||
|
||||
.empty-tip {
|
||||
text-align: center;
|
||||
padding: 80rpx 0;
|
||||
color: #999;
|
||||
font-size: 26rpx;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
+179
-283
@@ -1,22 +1,24 @@
|
||||
<template>
|
||||
<u-popup v-model="localVisible" mode="bottom" :height="height">
|
||||
<view class="nbd-select">
|
||||
<!-- 标题栏 -->
|
||||
<view class="nbd-select-header" v-if="title">
|
||||
<text class="nbd-select-title">{{ title }}</text>
|
||||
<text class="nbd-select-tip" v-if="tip">{{ tip }}</text>
|
||||
<!-- 顶部按钮 -->
|
||||
<view class="nbd-select-header">
|
||||
<u-button size="mini" @click="handleCancel">
|
||||
{{ cancelText }}
|
||||
</u-button>
|
||||
<view v-if="title || tip" class="nbd-select-title-wrap">
|
||||
<text class="nbd-select-title">{{ title }}</text>
|
||||
<text class="nbd-select-tip" v-if="tip">{{ tip }}</text>
|
||||
</view>
|
||||
<u-button size="mini" type="primary" @click="handleConfirm">
|
||||
{{ confirmText }}
|
||||
</u-button>
|
||||
</view>
|
||||
|
||||
<!-- 搜索栏 -->
|
||||
<view class="nbd-select-filter" v-if="showSearch">
|
||||
<u-search
|
||||
:placeholder="searchPlaceholder"
|
||||
:height="72"
|
||||
v-model="searchKey"
|
||||
:show-action="false"
|
||||
@change="handleSearch"
|
||||
@clear="handleSearch"
|
||||
></u-search>
|
||||
<u-search :placeholder="searchPlaceholder" :height="60" v-model="searchKey" :show-action="false"
|
||||
@change="handleSearch" @clear="handleSearch"></u-search>
|
||||
</view>
|
||||
|
||||
<!-- 列表内容 -->
|
||||
@@ -28,298 +30,192 @@
|
||||
</view>
|
||||
|
||||
<!-- 列表项 -->
|
||||
<view
|
||||
v-for="(item, idx) in filteredList"
|
||||
:key="idx"
|
||||
class="nbd-select-item"
|
||||
:class="{ active: isSelected(item) }"
|
||||
@click="handleItemClick(item)"
|
||||
>
|
||||
<view v-for="(item, idx) in filteredList" :key="idx" class="nbd-select-item"
|
||||
:class="{ active: isSelected(item) }" @click="handleItemClick(item)">
|
||||
<text class="nbd-select-item-text">{{ item[labelKey] }}</text>
|
||||
<view v-if="multiple" class="nbd-select-checkbox">
|
||||
<u-icon
|
||||
:name="isSelected(item) ? 'checkbox-mark' : 'square'"
|
||||
:size="36"
|
||||
:color="isSelected(item) ? $u.type.primary : '#dcdee0'"
|
||||
></u-icon>
|
||||
<u-icon :name="isSelected(item) ? 'checkbox-mark' : 'square'" :size="36"
|
||||
:color="isSelected(item) ? $u.type.primary : '#dcdee0'"></u-icon>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</scroll-view>
|
||||
|
||||
<!-- 底部按钮 -->
|
||||
<view class="nbd-select-footer">
|
||||
<u-button class="nbd-select-btn-cancel" @click="handleCancel">
|
||||
{{ cancelText }}
|
||||
</u-button>
|
||||
<u-button class="nbd-select-btn-confirm" type="primary" @click="handleConfirm">
|
||||
{{ confirmText }}
|
||||
</u-button>
|
||||
</view>
|
||||
</view>
|
||||
</u-popup>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, computed, watch } from 'vue'
|
||||
import {
|
||||
ref,
|
||||
computed,
|
||||
watch
|
||||
} from 'vue'
|
||||
|
||||
const props = defineProps({
|
||||
// 弹窗显示状态
|
||||
modelValue: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
// 弹窗高度
|
||||
height: {
|
||||
type: String,
|
||||
default: '70%'
|
||||
},
|
||||
// 标题
|
||||
title: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
// 标题提示
|
||||
tip: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
// 数据列表
|
||||
list: {
|
||||
type: Array,
|
||||
default: () => []
|
||||
},
|
||||
// 选中项(支持数组,多选时使用)
|
||||
model: {
|
||||
type: [Object, Array, String, Number],
|
||||
default: null
|
||||
},
|
||||
// 是否多选
|
||||
multiple: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
// 显示搜索框
|
||||
showSearch: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
// 搜索占位符
|
||||
searchPlaceholder: {
|
||||
type: String,
|
||||
default: '请输入关键词搜索'
|
||||
},
|
||||
// 字段名配置
|
||||
labelKey: {
|
||||
type: String,
|
||||
default: 'label'
|
||||
},
|
||||
valueKey: {
|
||||
type: String,
|
||||
default: 'value'
|
||||
},
|
||||
// 自定义搜索字段(默认搜索 labelKey)
|
||||
searchKeyField: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
// 按钮文字
|
||||
cancelText: {
|
||||
type: String,
|
||||
default: '取消'
|
||||
},
|
||||
confirmText: {
|
||||
type: String,
|
||||
default: '确定'
|
||||
}
|
||||
})
|
||||
|
||||
const emit = defineEmits([
|
||||
'update:modelValue',
|
||||
'update:model',
|
||||
'cancel',
|
||||
'confirm',
|
||||
'searchChange',
|
||||
'change'
|
||||
])
|
||||
|
||||
const localVisible = ref(false)
|
||||
const searchKey = ref('')
|
||||
|
||||
// 当前选中的项(多选时为数组)
|
||||
const selectedItems = ref(props.multiple ? (props.model || []) : (props.model || null))
|
||||
|
||||
// 监听外部 model 变化
|
||||
watch(() => props.model, (newVal) => {
|
||||
selectedItems.value = props.multiple ? (newVal || []) : newVal
|
||||
}, { deep: true })
|
||||
|
||||
// 弹窗状态同步
|
||||
watch(() => props.modelValue, (val) => {
|
||||
localVisible.value = val
|
||||
if (val) {
|
||||
// 打开时重置搜索
|
||||
searchKey.value = ''
|
||||
}
|
||||
})
|
||||
|
||||
watch(localVisible, (val) => {
|
||||
emit('update:modelValue', val)
|
||||
})
|
||||
|
||||
// 过滤后的列表
|
||||
const filteredList = computed(() => {
|
||||
if (!searchKey.value) return props.list
|
||||
|
||||
const keyword = searchKey.value.toLowerCase()
|
||||
const searchField = props.searchKeyField || props.labelKey
|
||||
|
||||
return props.list.filter(item => {
|
||||
const value = item[searchField]
|
||||
if (value === null || value === undefined) return false
|
||||
return String(value).toLowerCase().includes(keyword)
|
||||
const props = defineProps({
|
||||
// 弹窗显示状态
|
||||
modelValue: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
// 弹窗高度
|
||||
height: {
|
||||
type: String,
|
||||
default: '70%'
|
||||
},
|
||||
// 标题
|
||||
title: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
// 标题提示
|
||||
tip: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
// 数据列表
|
||||
list: {
|
||||
type: Array,
|
||||
default: () => []
|
||||
},
|
||||
// 选中项(支持数组,多选时使用)
|
||||
model: {
|
||||
type: [Object, Array, String, Number],
|
||||
default: null
|
||||
},
|
||||
// 是否多选
|
||||
multiple: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
// 显示搜索框
|
||||
showSearch: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
// 搜索占位符
|
||||
searchPlaceholder: {
|
||||
type: String,
|
||||
default: '请输入关键词搜索'
|
||||
},
|
||||
// 字段名配置
|
||||
labelKey: {
|
||||
type: String,
|
||||
default: 'label'
|
||||
},
|
||||
valueKey: {
|
||||
type: String,
|
||||
default: 'value'
|
||||
},
|
||||
// 自定义搜索字段(默认搜索 labelKey)
|
||||
searchKeyField: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
// 按钮文字
|
||||
cancelText: {
|
||||
type: String,
|
||||
default: '取消'
|
||||
},
|
||||
confirmText: {
|
||||
type: String,
|
||||
default: '确定'
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
// 判断是否选中
|
||||
const isSelected = (item) => {
|
||||
if (props.multiple) {
|
||||
return selectedItems.value.some(
|
||||
selected => selected[props.valueKey] === item[props.valueKey]
|
||||
)
|
||||
}
|
||||
if (selectedItems.value && typeof selectedItems.value === 'object') {
|
||||
return selectedItems.value[props.valueKey] === item[props.valueKey]
|
||||
}
|
||||
return selectedItems.value === item[props.valueKey]
|
||||
}
|
||||
const emit = defineEmits([
|
||||
'update:modelValue',
|
||||
'update:model',
|
||||
'cancel',
|
||||
'confirm',
|
||||
'searchChange',
|
||||
'change'
|
||||
])
|
||||
|
||||
// 点击列表项
|
||||
const handleItemClick = (item) => {
|
||||
if (props.multiple) {
|
||||
const index = selectedItems.value.findIndex(
|
||||
selected => selected[props.valueKey] === item[props.valueKey]
|
||||
)
|
||||
if (index > -1) {
|
||||
selectedItems.value.splice(index, 1)
|
||||
const localVisible = ref(false)
|
||||
const searchKey = ref('')
|
||||
|
||||
// 当前选中的项(多选时为数组)
|
||||
const selectedItems = ref(props.multiple ? (props.model || []) : (props.model || null))
|
||||
|
||||
// 监听外部 model 变化
|
||||
watch(() => props.model, (newVal) => {
|
||||
selectedItems.value = props.multiple ? (newVal || []) : newVal
|
||||
}, {
|
||||
deep: true
|
||||
})
|
||||
|
||||
// 弹窗状态同步
|
||||
watch(() => props.modelValue, (val) => {
|
||||
localVisible.value = val
|
||||
if (val) {
|
||||
// 打开时重置搜索
|
||||
searchKey.value = ''
|
||||
}
|
||||
})
|
||||
|
||||
watch(localVisible, (val) => {
|
||||
emit('update:modelValue', val)
|
||||
})
|
||||
|
||||
// 过滤后的列表
|
||||
const filteredList = computed(() => {
|
||||
if (!searchKey.value) return props.list
|
||||
|
||||
const keyword = searchKey.value.toLowerCase()
|
||||
const searchField = props.searchKeyField || props.labelKey
|
||||
|
||||
return props.list.filter(item => {
|
||||
const value = item[searchField]
|
||||
if (value === null || value === undefined) return false
|
||||
return String(value).toLowerCase().includes(keyword)
|
||||
})
|
||||
})
|
||||
|
||||
// 判断是否选中
|
||||
const isSelected = (item) => {
|
||||
if (props.multiple) {
|
||||
return selectedItems.value.some(
|
||||
selected => selected[props.valueKey] === item[props.valueKey]
|
||||
)
|
||||
}
|
||||
if (selectedItems.value && typeof selectedItems.value === 'object') {
|
||||
return selectedItems.value[props.valueKey] === item[props.valueKey]
|
||||
}
|
||||
return selectedItems.value === item[props.valueKey]
|
||||
}
|
||||
|
||||
// 点击列表项
|
||||
const handleItemClick = (item) => {
|
||||
if (props.multiple) {
|
||||
const index = selectedItems.value.findIndex(
|
||||
selected => selected[props.valueKey] === item[props.valueKey]
|
||||
)
|
||||
if (index > -1) {
|
||||
selectedItems.value.splice(index, 1)
|
||||
} else {
|
||||
selectedItems.value.push(item)
|
||||
}
|
||||
} else {
|
||||
selectedItems.value.push(item)
|
||||
}
|
||||
} else {
|
||||
selectedItems.value = item
|
||||
}
|
||||
emit('change', selectedItems.value)
|
||||
}
|
||||
|
||||
// 搜索
|
||||
const handleSearch = (val) => {
|
||||
emit('searchChange', val)
|
||||
}
|
||||
|
||||
// 取消
|
||||
const handleCancel = () => {
|
||||
emit('cancel')
|
||||
localVisible.value = false
|
||||
}
|
||||
|
||||
// 确认
|
||||
const handleConfirm = () => {
|
||||
emit('confirm', selectedItems.value)
|
||||
emit('update:model', selectedItems.value)
|
||||
localVisible.value = false
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.nbd-select {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
height: 100%;
|
||||
background: #ffffff;
|
||||
border-radius: 24rpx 24rpx 0 0;
|
||||
overflow: hidden;
|
||||
|
||||
&-header {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
padding: 24rpx 32rpx 20rpx;
|
||||
border-bottom: 1rpx solid #f0f0f0;
|
||||
|
||||
.nbd-select-title {
|
||||
font-size: 32rpx;
|
||||
font-weight: 600;
|
||||
color: #333;
|
||||
margin-bottom: 8rpx;
|
||||
}
|
||||
|
||||
.nbd-select-tip {
|
||||
font-size: 24rpx;
|
||||
color: #999;
|
||||
selectedItems.value = item
|
||||
}
|
||||
emit('change', selectedItems.value)
|
||||
}
|
||||
|
||||
&-filter {
|
||||
padding: 16rpx 32rpx;
|
||||
border-bottom: 1rpx solid #f0f0f0;
|
||||
// 搜索
|
||||
const handleSearch = (val) => {
|
||||
emit('searchChange', val)
|
||||
}
|
||||
|
||||
&-inner {
|
||||
flex: 1;
|
||||
overflow-y: auto;
|
||||
padding: 0 32rpx;
|
||||
|
||||
&-wrap {
|
||||
padding: 16rpx 0;
|
||||
}
|
||||
// 取消
|
||||
const handleCancel = () => {
|
||||
emit('cancel')
|
||||
localVisible.value = false
|
||||
}
|
||||
|
||||
&-empty {
|
||||
padding: 80rpx 0;
|
||||
// 确认
|
||||
const handleConfirm = () => {
|
||||
emit('confirm', selectedItems.value)
|
||||
emit('update:model', selectedItems.value)
|
||||
localVisible.value = false
|
||||
}
|
||||
|
||||
&-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: 28rpx 0;
|
||||
border-bottom: 1rpx solid #f5f6f8;
|
||||
transition: background 0.2s;
|
||||
|
||||
&:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
&.active .nbd-select-item-text {
|
||||
color: $u-type-primary;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.nbd-select-item-text {
|
||||
flex: 1;
|
||||
font-size: 28rpx;
|
||||
color: #333;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.nbd-select-checkbox {
|
||||
margin-left: 16rpx;
|
||||
}
|
||||
}
|
||||
|
||||
&-footer {
|
||||
display: flex;
|
||||
gap: 24rpx;
|
||||
padding: 20rpx 32rpx 40rpx;
|
||||
|
||||
.nbd-select-btn-cancel,
|
||||
.nbd-select-btn-confirm {
|
||||
flex: 1;
|
||||
height: 80rpx;
|
||||
font-size: 28rpx;
|
||||
border-radius: 40rpx;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
</script>
|
||||
+23
-14
@@ -22,37 +22,37 @@
|
||||
<view class="hj-row">
|
||||
<view class="hj-cell">
|
||||
<text class="hj-label">工厂焊接一次合格率</text>
|
||||
<text class="hj-value">{{hjIndexData?.GCFirstPassRate}}</text>
|
||||
<text class="hj-value">{{ hjIndexData?.GCFirstPassRate|| '--'}}</text>
|
||||
</view>
|
||||
<view class="hj-cell">
|
||||
<text class="hj-label">现场焊接一次合格率</text>
|
||||
<text class="hj-value">{{hjIndexData?.XCFirstPassRate}}</text>
|
||||
<text class="hj-value">{{ hjIndexData?.XCFirstPassRate || '--' }}</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="hj-row">
|
||||
<view class="hj-cell">
|
||||
<text class="hj-label">工厂预制进度</text>
|
||||
<text class="hj-value hj-sub">{{hjIndexData?.GCProgress}}</text>
|
||||
<text class="hj-value hj-sub">{{ hjIndexData?.GCProgress|| '--' }}</text>
|
||||
</view>
|
||||
<view class="hj-cell">
|
||||
<text class="hj-label">现场焊接进度</text>
|
||||
<text class="hj-value hj-sub">{{hjIndexData?.XCProgress}}</text>
|
||||
<text class="hj-value hj-sub">{{ hjIndexData?.XCProgress || '--'}}</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="hj-row">
|
||||
<view class="hj-cell">
|
||||
<text class="hj-label">工厂焊工功效</text>
|
||||
<text class="hj-value">{{hjIndexData?.GCWelderEfficacy}}</text>
|
||||
<text class="hj-value">{{ hjIndexData?.GCWelderEfficacy || '--'}}</text>
|
||||
</view>
|
||||
<view class="hj-cell">
|
||||
<text class="hj-label">现场焊接功效</text>
|
||||
<text class="hj-value">{{hjIndexData?.XCWelderEfficacy}}</text>
|
||||
<text class="hj-value">{{ hjIndexData?.XCWelderEfficacy || '--'}}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="hj-footer">
|
||||
<text class="hj-footer-label">项目管道实时预制率 (包含工厂和现场的预制口)</text>
|
||||
<text class="hj-footer-value">{{hjIndexData?.PipePrefabricationRate}}</text>
|
||||
<text class="hj-footer-value">{{ hjIndexData?.PipePrefabricationRate || '--'}}</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
@@ -73,13 +73,14 @@
|
||||
</view>
|
||||
<text class="item-label">{{ item.name }}</text>
|
||||
</view>
|
||||
<view v-if="quickApps.length === 0" class="empty-tip">请选择应用</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
|
||||
|
||||
<!-- 业务查询 -->
|
||||
<view class="section-card home-query" v-if="queryApps&&queryApps.length>0">
|
||||
<view class="section-card home-query" v-if="queryApps && queryApps.length > 0">
|
||||
<view class="section-title">
|
||||
<view class="title-left">
|
||||
<text class="title-line"></text>
|
||||
@@ -89,7 +90,7 @@
|
||||
<view class="section-grid">
|
||||
<view class="grid-item" v-for="(item, idx) in queryApps" :key="idx" @click="handleSkip(item)">
|
||||
<view class="icon-box">
|
||||
<u-icon :name="item.icon" :custom-prefix='item.prefix' :size="56" :color="item.color" />
|
||||
<u-icon :name="item.icon" :custom-prefix='item.prefix' :size="56" :color="pastelColors[idx % 6]" />
|
||||
</view>
|
||||
<text class="item-label">{{ item.name }}</text>
|
||||
</view>
|
||||
@@ -121,9 +122,9 @@
|
||||
</view>
|
||||
</view>
|
||||
</u-popup>
|
||||
<nbd-select-project v-model="showProject" :select-id="currentProject?.ProjectId" :list="projectList"
|
||||
label-key="ProjectName" value-key="ProjectId" :search-key="projectNameKeyword"
|
||||
@search-change="handleSearchChange" @confirm="handleConfirmProject" />
|
||||
<nbd-select v-model="showProject" title="请选择项目" :list="projectList" label-key="ProjectName" :show-search="true"
|
||||
value-key="ProjectId" :default-value="currentProject?.ProjectId" @search-change="handleSearchChange"
|
||||
@confirm="handleConfirmProject" />
|
||||
</view>
|
||||
</template>
|
||||
|
||||
@@ -178,7 +179,15 @@
|
||||
|
||||
const currentProjectName = computed(() => currentProject.value?.ProjectName || '')
|
||||
|
||||
const handleSkip= (item) => {
|
||||
const handleSkip = (item) => {
|
||||
if(!currentProject.value.ProjectId){
|
||||
handleShowProjectSelect()
|
||||
uni.showToast({
|
||||
title: '请选择一个项目',
|
||||
icon: 'none'
|
||||
})
|
||||
return
|
||||
}
|
||||
uni.navigateTo({
|
||||
url: item.path
|
||||
})
|
||||
@@ -201,7 +210,7 @@
|
||||
showEditQuick.value = false
|
||||
uni.showToast({
|
||||
title: '已更新快捷应用',
|
||||
icon: 'success'
|
||||
icon: 'none'
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
+84
-334
@@ -1,14 +1,13 @@
|
||||
<template>
|
||||
<view class="page">
|
||||
<view class="page-list">
|
||||
<!-- 头部过滤区域 -->
|
||||
<view class="filter-header">
|
||||
<view class="filter-row">
|
||||
<!-- 下拉过滤 1 -->
|
||||
<u-dropdown v-model="filter1Value" :options="filter1Options" @change="handleFilter1Change"></u-dropdown>
|
||||
|
||||
<!-- 下拉过滤 2 -->
|
||||
<u-dropdown v-model="filter2Value" :options="filter2Options" @change="handleFilter2Change"></u-dropdown>
|
||||
|
||||
<!-- 单位工程下拉选择 -->
|
||||
<view class="project-select-btn">
|
||||
<u-input style="color: #333;" v-model="unitWorkName" :clearable="false" type="select"
|
||||
placeholder="请选择单位工程" @click="handleShowUnitWorkSelect" />
|
||||
</view>
|
||||
<!-- 刷新按钮 -->
|
||||
<view class="refresh-btn" @click="handleRefresh">
|
||||
<u-icon name="reload" :size="36" :class="{ rotating: loading }"></u-icon>
|
||||
@@ -17,355 +16,106 @@
|
||||
</view>
|
||||
|
||||
<!-- 列表内容 -->
|
||||
<scroll-view
|
||||
class="list-scroll"
|
||||
scroll-y
|
||||
:scroll-into-view="scrollIntoView"
|
||||
@scrolltolower="loadMore"
|
||||
refresher-enabled
|
||||
:refresher-triggered="refreshing"
|
||||
@refresh="handleRefresh"
|
||||
>
|
||||
<!-- 列表项 -->
|
||||
<view class="list-wrap">
|
||||
<view
|
||||
v-for="(item, index) in listData"
|
||||
:key="item.id || index"
|
||||
class="list-item"
|
||||
@click="handleItemClick(item)"
|
||||
>
|
||||
<view class="item-header">
|
||||
<text class="item-title">{{ item.name || '未命名' }}</text>
|
||||
<text class="item-status" :class="item.status">{{ item.statusText || '' }}</text>
|
||||
</view>
|
||||
<view class="item-content">
|
||||
<text class="item-desc">{{ item.description || '' }}</text>
|
||||
</view>
|
||||
<view class="item-footer">
|
||||
<text class="item-time">{{ item.createTime || '' }}</text>
|
||||
<text class="item-author">{{ item.creator || '' }}</text>
|
||||
</view>
|
||||
<view class="list-scroll">
|
||||
<!-- 加载中 -->
|
||||
<view v-if="loading" class="loading-box">
|
||||
<u-loading mode="circle" size="40"></u-loading>
|
||||
<text class="loading-text">加载中...</text>
|
||||
</view>
|
||||
<!-- 数据列表 -->
|
||||
<view v-else class="list-wrap">
|
||||
<view v-for="(item, index) in listData" :key="item.id || index" class="list-item"
|
||||
@click="handleItemClick(item)">
|
||||
<text class="item-index">{{ index + 1 }}</text>
|
||||
<text class="item-title">{{ item.PointBatchCode || '--' }}</text>
|
||||
<u-icon name="arrow-right" :size="28" color="#ccc"></u-icon>
|
||||
</view>
|
||||
|
||||
<!-- 空状态 -->
|
||||
<u-empty
|
||||
v-if="!loading && listData.length === 0"
|
||||
mode="list"
|
||||
text="暂无数据"
|
||||
></u-empty>
|
||||
|
||||
<!-- 加载提示 -->
|
||||
<view v-if="loading && listData.length > 0" class="loading-more">
|
||||
<u-loading mode="circle" size="32"></u-loading>
|
||||
<text>加载中...</text>
|
||||
</view>
|
||||
|
||||
<!-- 没有更多 -->
|
||||
<view v-if="!loading && !hasMore && listData.length > 0" class="no-more">
|
||||
<text>— 没有更多了 —</text>
|
||||
</view>
|
||||
<u-empty v-if="listData.length === 0" mode="list" text="暂无数据"></u-empty>
|
||||
</view>
|
||||
</scroll-view>
|
||||
</view>
|
||||
|
||||
<!-- 单位工程选择弹窗 -->
|
||||
<nbd-select v-model="showUnitWorkSelect" :show-search="true" title="请选择单位工程" :list="unitWorkList"
|
||||
label-key="BaseInfoName" value-key="BaseInfoId" @confirm="handleUnitWorkConfirm" />
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, reactive, onMounted } from 'vue'
|
||||
import {
|
||||
ref,
|
||||
onMounted,
|
||||
computed
|
||||
} from 'vue'
|
||||
import {
|
||||
reqProjectWorkArea
|
||||
} from '@/api/base.js'
|
||||
import {
|
||||
reqGetNotEndPointBatch
|
||||
} from '@/api/hj.js'
|
||||
import {
|
||||
useUserStore
|
||||
} from '@/store'
|
||||
import {
|
||||
storeToRefs
|
||||
} from 'pinia'
|
||||
|
||||
// ===== 过滤条件 =====
|
||||
const filter1Value = ref('')
|
||||
const filter2Value = ref('')
|
||||
const userStore = useUserStore()
|
||||
const {
|
||||
currentProject
|
||||
} = storeToRefs(userStore)
|
||||
|
||||
// 过滤选项 1
|
||||
const filter1Options = ref([
|
||||
{ label: '全部类型', value: '' },
|
||||
{ label: '类型 A', value: 'type_a' },
|
||||
{ label: '类型 B', value: 'type_b' },
|
||||
{ label: '类型 C', value: 'type_c' }
|
||||
])
|
||||
// ===== 单位工程选择 =====
|
||||
const showUnitWorkSelect = ref(false)
|
||||
const selectedUnitWork = ref(null)
|
||||
const unitWorkName = computed(() => selectedUnitWork.value?.BaseInfoName || '')
|
||||
const unitWorkList = ref([])
|
||||
|
||||
// 过滤选项 2
|
||||
const filter2Options = ref([
|
||||
{ label: '全部状态', value: '' },
|
||||
{ label: '进行中', value: 'pending' },
|
||||
{ label: '已完成', value: 'completed' },
|
||||
{ label: '已取消', value: 'cancelled' }
|
||||
])
|
||||
|
||||
// ===== 列表数据 =====
|
||||
const listData = ref([])
|
||||
const loading = ref(false)
|
||||
const refreshing = ref(false)
|
||||
const hasMore = ref(true)
|
||||
const currentPage = ref(1)
|
||||
const pageSize = 20
|
||||
const scrollIntoView = ref('')
|
||||
|
||||
// ===== 筛选条件变更 =====
|
||||
const filterParams = reactive({
|
||||
filter1: '',
|
||||
filter2: ''
|
||||
})
|
||||
|
||||
// 过滤 1 变化
|
||||
const handleFilter1Change = (value) => {
|
||||
filterParams.filter1 = value
|
||||
resetAndLoad()
|
||||
}
|
||||
|
||||
// 过滤 2 变化
|
||||
const handleFilter2Change = (value) => {
|
||||
filterParams.filter2 = value
|
||||
resetAndLoad()
|
||||
}
|
||||
|
||||
// ===== 数据加载 =====
|
||||
|
||||
// 加载数据
|
||||
const fetchData = async (isRefresh = false) => {
|
||||
if (loading.value || (!isRefresh && !hasMore.value)) return
|
||||
|
||||
loading.value = true
|
||||
if (isRefresh) {
|
||||
refreshing.value = true
|
||||
}
|
||||
|
||||
try {
|
||||
// TODO: 替换为实际 API 调用
|
||||
// const res = await api.getList({
|
||||
// page: currentPage.value,
|
||||
// pageSize,
|
||||
// ...filterParams
|
||||
// })
|
||||
|
||||
// 模拟数据
|
||||
const mockData = await mockApiFetch({
|
||||
page: currentPage.value,
|
||||
pageSize,
|
||||
...filterParams
|
||||
const handleShowUnitWorkSelect = () => {
|
||||
reqProjectWorkArea(currentProject.value.ProjectId).then(res => {
|
||||
unitWorkList.value = res.data || []
|
||||
showUnitWorkSelect.value = true
|
||||
})
|
||||
|
||||
if (isRefresh) {
|
||||
listData.value = mockData.list
|
||||
} else {
|
||||
listData.value = [...listData.value, ...mockData.list]
|
||||
}
|
||||
|
||||
hasMore.value = mockData.hasMore
|
||||
currentPage.value++
|
||||
} catch (error) {
|
||||
console.error('加载数据失败:', error)
|
||||
uni.showToast({
|
||||
title: '加载失败,请重试',
|
||||
icon: 'none'
|
||||
})
|
||||
} finally {
|
||||
loading.value = false
|
||||
refreshing.value = false
|
||||
}
|
||||
}
|
||||
|
||||
// 重置并重新加载
|
||||
const resetAndLoad = () => {
|
||||
currentPage.value = 1
|
||||
hasMore.value = true
|
||||
listData.value = []
|
||||
fetchData(true)
|
||||
}
|
||||
|
||||
// 下拉刷新
|
||||
const handleRefresh = () => {
|
||||
resetAndLoad()
|
||||
}
|
||||
|
||||
// 上拉加载更多
|
||||
const loadMore = () => {
|
||||
if (!loading.value && hasMore.value) {
|
||||
fetchData(false)
|
||||
}
|
||||
}
|
||||
|
||||
// 列表项点击
|
||||
const handleItemClick = (item) => {
|
||||
console.log('点击列表项:', item)
|
||||
// TODO: 跳转详情
|
||||
// uni.navigateTo({ url: `/pages/xxx/detail?id=${item.id}` })
|
||||
}
|
||||
|
||||
// ===== 模拟 API(实际使用时删除)=====
|
||||
const mockApiFetch = async (params) => {
|
||||
return new Promise((resolve) => {
|
||||
setTimeout(() => {
|
||||
const start = (params.page - 1) * params.pageSize
|
||||
const end = start + params.pageSize
|
||||
const hasMore = end < 100 // 模拟总共 100 条数据
|
||||
|
||||
const list = Array.from({ length: hasMore ? params.pageSize : (100 - start) }, (_, i) => ({
|
||||
id: start + i + 1,
|
||||
name: `项目 ${start + i + 1}`,
|
||||
description: '这是一个测试项目的描述信息,可能包含更多内容',
|
||||
status: ['pending', 'completed', 'cancelled'][Math.floor(Math.random() * 3)],
|
||||
statusText: ['进行中', '已完成', '已取消'][Math.floor(Math.random() * 3)],
|
||||
createTime: '2024-01-01 12:00:00',
|
||||
creator: `用户${Math.floor(Math.random() * 10) + 1}`
|
||||
}))
|
||||
|
||||
resolve({
|
||||
list,
|
||||
hasMore
|
||||
})
|
||||
}, 500)
|
||||
})
|
||||
}
|
||||
|
||||
// ===== 生命周期 =====
|
||||
onMounted(() => {
|
||||
fetchData(true)
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.page {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
height: 100vh;
|
||||
background: #f5f6f8;
|
||||
}
|
||||
|
||||
// 头部过滤区域
|
||||
.filter-header {
|
||||
background: #ffffff;
|
||||
padding: 20rpx 24rpx;
|
||||
border-bottom: 1rpx solid #f0f0f0;
|
||||
|
||||
.filter-row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 16rpx;
|
||||
}
|
||||
|
||||
.refresh-btn {
|
||||
margin-left: auto;
|
||||
padding: 8rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
||||
.rotating {
|
||||
animation: rotate 1s linear infinite;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes rotate {
|
||||
from {
|
||||
transform: rotate(0deg);
|
||||
}
|
||||
to {
|
||||
transform: rotate(360deg);
|
||||
}
|
||||
}
|
||||
|
||||
// 列表滚动区域
|
||||
.list-scroll {
|
||||
flex: 1;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.list-wrap {
|
||||
padding: 24rpx;
|
||||
}
|
||||
|
||||
// 列表项
|
||||
.list-item {
|
||||
background: #ffffff;
|
||||
border-radius: 16rpx;
|
||||
padding: 28rpx;
|
||||
margin-bottom: 20rpx;
|
||||
box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.05);
|
||||
|
||||
&:last-child {
|
||||
margin-bottom: 0;
|
||||
const handleUnitWorkConfirm = (item) => {
|
||||
selectedUnitWork.value = item
|
||||
showUnitWorkSelect.value = false
|
||||
handleRefresh()
|
||||
}
|
||||
|
||||
.item-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: 16rpx;
|
||||
// ===== 列表数据 =====
|
||||
const listData = ref([])
|
||||
const loading = ref(false)
|
||||
|
||||
.item-title {
|
||||
font-size: 30rpx;
|
||||
font-weight: 600;
|
||||
color: #333;
|
||||
}
|
||||
// 加载数据
|
||||
const fetchData = async () => {
|
||||
if (loading.value) return
|
||||
loading.value = true
|
||||
|
||||
.item-status {
|
||||
font-size: 22rpx;
|
||||
padding: 6rpx 16rpx;
|
||||
border-radius: 20rpx;
|
||||
background: #f0f0f0;
|
||||
color: #666;
|
||||
|
||||
&.pending {
|
||||
background: rgba(255, 167, 38, 0.1);
|
||||
color: #ffa726;
|
||||
}
|
||||
|
||||
&.completed {
|
||||
background: rgba(76, 175, 80, 0.1);
|
||||
color: #4caf50;
|
||||
}
|
||||
|
||||
&.cancelled {
|
||||
background: rgba(244, 67, 54, 0.1);
|
||||
color: #f44336;
|
||||
}
|
||||
try {
|
||||
const res = await reqGetNotEndPointBatch(
|
||||
selectedUnitWork.value?.BaseInfoId || '',
|
||||
currentProject.value?.ProjectId
|
||||
)
|
||||
listData.value = res.data || []
|
||||
} catch (error) {
|
||||
console.error('加载数据失败:', error)
|
||||
uni.showToast({ title: '加载失败,请重试', icon: 'none' })
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
.item-content {
|
||||
margin-bottom: 16rpx;
|
||||
|
||||
.item-desc {
|
||||
font-size: 26rpx;
|
||||
color: #666;
|
||||
line-height: 1.6;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
display: -webkit-box;
|
||||
-webkit-line-clamp: 2;
|
||||
-webkit-box-orient: vertical;
|
||||
}
|
||||
const handleRefresh = () => {
|
||||
listData.value = []
|
||||
fetchData()
|
||||
}
|
||||
|
||||
.item-footer {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
|
||||
.item-time,
|
||||
.item-author {
|
||||
font-size: 22rpx;
|
||||
color: #999;
|
||||
}
|
||||
const handleItemClick = (item) => {
|
||||
console.log('点击列表项:', item)
|
||||
// TODO: 跳转详情
|
||||
}
|
||||
}
|
||||
|
||||
// 加载中
|
||||
.loading-more {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
padding: 32rpx 0;
|
||||
color: #999;
|
||||
font-size: 24rpx;
|
||||
}
|
||||
|
||||
// 没有更多
|
||||
.no-more {
|
||||
text-align: center;
|
||||
padding: 32rpx 0;
|
||||
color: #ccc;
|
||||
font-size: 24rpx;
|
||||
}
|
||||
</style>
|
||||
</script>
|
||||
@@ -96,7 +96,7 @@ export const useMenuStore = defineStore('menu', () => {
|
||||
enabled: true,
|
||||
strategies: [{
|
||||
key: 'menu',
|
||||
paths: [],
|
||||
paths: ['appsList'],
|
||||
}]
|
||||
},
|
||||
})
|
||||
|
||||
@@ -42,11 +42,6 @@ export const useUserStore = defineStore('user', () => {
|
||||
const logout = () => {
|
||||
token.value = ""
|
||||
userInfo.value = null
|
||||
// loginForm.value = {
|
||||
// account: '',
|
||||
// password: '',
|
||||
// Telephone: '',
|
||||
// }
|
||||
currentProject.value = null
|
||||
}
|
||||
|
||||
|
||||
+5
-5
@@ -16,34 +16,34 @@ export const defaultApps = [{
|
||||
menuId: '3ACE25CE-C5CE-4CEC-AD27-0D5CF1DF2F01',
|
||||
path: "/pipe/diankou/list",
|
||||
prefix: 'nbd-icon',
|
||||
selected: true
|
||||
selected: false
|
||||
},
|
||||
{
|
||||
name: '试压管理',
|
||||
icon: 'shiyabao',
|
||||
menuId: '55976B16-2C33-406E-B514-2FE42D031071',
|
||||
prefix: 'nbd-icon',
|
||||
selected: true
|
||||
selected: false
|
||||
},
|
||||
{
|
||||
name: '包装管理',
|
||||
icon: 'baozhuangguanli',
|
||||
menuId: "25DED954-10C9-47CC-99F2-C44FDE9E0A81",
|
||||
prefix: 'nbd-icon',
|
||||
selected: true
|
||||
selected: false
|
||||
},
|
||||
{
|
||||
name: '发货管理',
|
||||
icon: 'a-facheguanli',
|
||||
menuId: "EEC0D060-C15E-4D25-B015-C2B91F735DAC",
|
||||
prefix: 'nbd-icon',
|
||||
selected: true
|
||||
selected: false
|
||||
},
|
||||
{
|
||||
name: '预制组件管理',
|
||||
icon: 'yuzhijian',
|
||||
menuId: "8255554C-0A92-4C7B-BF19-779AF0220A8C",
|
||||
prefix: 'nbd-icon',
|
||||
selected: true
|
||||
selected: false
|
||||
}
|
||||
]
|
||||
+1
-1
@@ -1,7 +1,7 @@
|
||||
import { useUserStore } from '@/store'
|
||||
|
||||
// TODO: 替换为实际的 API 地址
|
||||
export const baseUrl = ' https://lygcgs.com.cn:8078/shjapi/api/'
|
||||
export const baseUrl = 'https://sggl.sedin.com.cn/sgglapi/api/'
|
||||
|
||||
// ===== 防止重复请求 =====
|
||||
const pendingRequests = new Map()
|
||||
|
||||
Reference in New Issue
Block a user