|
|
@@ -0,0 +1,486 @@
|
|
|
+<template>
|
|
|
+ <view class="check-project-container">
|
|
|
+ <view class="search-bar">
|
|
|
+ <view class="dropdown-wrapper">
|
|
|
+ <view class="dropdown-selector" @click="showDropdown = !showDropdown">
|
|
|
+ <text class="dropdown-text">{{ boilerCheckTypeLabelName }} bo</text>
|
|
|
+ <!-- <text class="dropdown-arrow">▼</text> -->
|
|
|
+ </view>
|
|
|
+ <!-- 下拉先注释掉,检验性质貌似不需要再修改了 -->
|
|
|
+ <!-- <view v-if="showDropdown" class="dropdown-menu">
|
|
|
+ <view
|
|
|
+ v-for="option in inspectionNatureOptions"
|
|
|
+ :key="option.value"
|
|
|
+ class="dropdown-item"
|
|
|
+ :class="{ active: inspectionNature === option.value }"
|
|
|
+ @click="selectInspectionNature(option)"
|
|
|
+ >
|
|
|
+ <text>{{ option.label }}</text>
|
|
|
+ </view>
|
|
|
+ </view> -->
|
|
|
+ </view>
|
|
|
+
|
|
|
+ <input
|
|
|
+ v-model="searchKeyword"
|
|
|
+ class="search-input"
|
|
|
+ placeholder="搜索项目名称"
|
|
|
+ @confirm="handleSearch"
|
|
|
+ />
|
|
|
+ </view>
|
|
|
+
|
|
|
+ <scroll-view class="project-list" :scroll-y="true">
|
|
|
+ <view v-if="dataSource.length === 0" class="empty-state">
|
|
|
+ <text class="empty-text">暂无数据</text>
|
|
|
+ </view>
|
|
|
+ <wd-collapse v-else v-model="expandedNames">
|
|
|
+ <wd-collapse-item
|
|
|
+ v-for="group in groupedData"
|
|
|
+ :key="group.type"
|
|
|
+ :title="group.title"
|
|
|
+ :name="group.type"
|
|
|
+ >
|
|
|
+ <view class="project-grid">
|
|
|
+ <view
|
|
|
+ v-for="(item, index) in group.items"
|
|
|
+ :key="item.templateId"
|
|
|
+ class="project-item"
|
|
|
+ :class="{
|
|
|
+ first: index === 0 || index === 1,
|
|
|
+ last: index === group.items.length - 1 || index === group.items.length - 2,
|
|
|
+ selected: isSelected(item),
|
|
|
+ }"
|
|
|
+ @click="handleSelect(item)"
|
|
|
+ >
|
|
|
+ <text class="project-name">{{ item.name }}</text>
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+ </wd-collapse-item>
|
|
|
+ </wd-collapse>
|
|
|
+ </scroll-view>
|
|
|
+
|
|
|
+ <view class="bottom-actions">
|
|
|
+ <button class="action-btn cancel-btn" @click="handleCancel">取消</button>
|
|
|
+ <button class="action-btn confirm-btn" @click="handleConfirm">确认</button>
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+</template>
|
|
|
+
|
|
|
+<script lang="ts" setup>
|
|
|
+import { ref, computed, onMounted, watch } from 'vue'
|
|
|
+import { getInspectProjectItemPage, addInspectProject } from '@/api/boiler/boilerTaskOrder'
|
|
|
+
|
|
|
+interface ReportTemplate {
|
|
|
+ orderId: string
|
|
|
+ name: string
|
|
|
+ isAutoAmount: string
|
|
|
+ templateId: string
|
|
|
+ connectId: string
|
|
|
+ formulaTemplateUrl: string
|
|
|
+ fee: number
|
|
|
+ use: boolean
|
|
|
+ reportType: number
|
|
|
+ recordTemplateUrl: string
|
|
|
+ reportTemplateUrl: string
|
|
|
+ isMainProject: string
|
|
|
+ feeCalcType: string
|
|
|
+ taskOrderItemId: string
|
|
|
+}
|
|
|
+
|
|
|
+interface Props {
|
|
|
+ propjectList: ReportTemplate[][]
|
|
|
+ selectTemplates: Record<string, any[]>
|
|
|
+ useOnline?: string
|
|
|
+ equipData: any
|
|
|
+}
|
|
|
+
|
|
|
+const props = defineProps<Props>()
|
|
|
+
|
|
|
+const emit = defineEmits<{
|
|
|
+ setIds: [item: any, type: string]
|
|
|
+ cleanIds: [type: string]
|
|
|
+ change: [selectedItems: any[]]
|
|
|
+ confirm: [selectedItems: any[]]
|
|
|
+ cancel: []
|
|
|
+}>()
|
|
|
+
|
|
|
+const searchKeyword = ref('')
|
|
|
+const dataSource = ref<ReportTemplate[]>([])
|
|
|
+const showDropdown = ref(false)
|
|
|
+const hadTemplateId = ref('')
|
|
|
+const expandedNames = ref<string[]>(['100'])
|
|
|
+const localSelectedTemplates = ref<ReportTemplate[]>([])
|
|
|
+
|
|
|
+const boilerCheckTypeMap = {
|
|
|
+ 100: '内部检验',
|
|
|
+ 200: '外部检验',
|
|
|
+ 300: '耐压检验',
|
|
|
+}
|
|
|
+
|
|
|
+interface GroupItem {
|
|
|
+ type: string
|
|
|
+ title: string
|
|
|
+ items: ReportTemplate[]
|
|
|
+}
|
|
|
+
|
|
|
+const groupedData = computed(() => {
|
|
|
+ const result: GroupItem[] = []
|
|
|
+
|
|
|
+ result.push({
|
|
|
+ type: '100',
|
|
|
+ title: boilerCheckTypeLabelName.value + ' 法定收费项目',
|
|
|
+ items: [...dataSource.value],
|
|
|
+ })
|
|
|
+
|
|
|
+ result.push({
|
|
|
+ type: '200',
|
|
|
+ title: boilerCheckTypeLabelName.value + ' 服务收费项目',
|
|
|
+ items: [...dataSource.value],
|
|
|
+ })
|
|
|
+
|
|
|
+ console.log(result, dataSource.value)
|
|
|
+
|
|
|
+ return result
|
|
|
+})
|
|
|
+
|
|
|
+const boilerCheckTypeLabelName = computed(() => {
|
|
|
+ const checkTypeNum = props.equipData?.taskOrder?.checkType
|
|
|
+ return boilerCheckTypeMap[checkTypeNum]
|
|
|
+})
|
|
|
+
|
|
|
+const isSelected = (item: ReportTemplate): boolean => {
|
|
|
+ return localSelectedTemplates.value.some((template) => template.templateId === item.templateId)
|
|
|
+}
|
|
|
+
|
|
|
+const selectedItems = computed(() => {
|
|
|
+ return localSelectedTemplates.value
|
|
|
+})
|
|
|
+
|
|
|
+const handleSearch = () => {
|
|
|
+ loadTemplates()
|
|
|
+}
|
|
|
+
|
|
|
+const loadTemplates = async () => {
|
|
|
+ if (props.useOnline === '1') {
|
|
|
+ const resp = await getInspectProjectItemPage({
|
|
|
+ orderId: props.equipData?.taskOrder?.id,
|
|
|
+ equipmentCategory: '200',
|
|
|
+ inspectionNature: [props.equipData?.taskOrder?.checkType],
|
|
|
+ equipType: props.equipData?.taskOrderItem?.boilerType,
|
|
|
+ itemIds: [props.equipData?.taskOrderItem?.id],
|
|
|
+ })
|
|
|
+
|
|
|
+ const templateList = resp?.data?.filter((item: any) =>
|
|
|
+ ['100', '200', '300'].includes(String(item.reportType)),
|
|
|
+ )
|
|
|
+
|
|
|
+ checkExistingTemplates(templateList || [])
|
|
|
+ dataSource.value = templateList || []
|
|
|
+ } else {
|
|
|
+ uni.showToast({ title: '离线模式暂不支持添加项目', icon: 'none' })
|
|
|
+ dataSource.value = []
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+const checkExistingTemplates = (templates: ReportTemplate[]) => {
|
|
|
+ for (const list of props.propjectList) {
|
|
|
+ for (const item of list) {
|
|
|
+ if (item.reportType == 100) {
|
|
|
+ for (const template of templates) {
|
|
|
+ if (template.templateId == item.templateId) {
|
|
|
+ hadTemplateId.value = item.templateId
|
|
|
+ break
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+const handleSelect = (item: ReportTemplate) => {
|
|
|
+ if (hadTemplateId.value === item.templateId && item.reportType === 100) {
|
|
|
+ uni.showToast({ title: '该主报告已存在', icon: 'none' })
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ const index = localSelectedTemplates.value.findIndex(
|
|
|
+ (template) => template.templateId === item.templateId,
|
|
|
+ )
|
|
|
+
|
|
|
+ debugger
|
|
|
+ if (index > -1) {
|
|
|
+ localSelectedTemplates.value.splice(index, 1)
|
|
|
+ } else {
|
|
|
+ localSelectedTemplates.value.push(item)
|
|
|
+ }
|
|
|
+
|
|
|
+ emit('setIds', item, 'CheckProject')
|
|
|
+ emit('change', selectedItems.value)
|
|
|
+}
|
|
|
+
|
|
|
+onMounted(() => {
|
|
|
+ const initSelected = props.selectTemplates.CheckProject || []
|
|
|
+ localSelectedTemplates.value = [...initSelected]
|
|
|
+ loadTemplates()
|
|
|
+})
|
|
|
+
|
|
|
+watch(
|
|
|
+ () => props.selectTemplates.CheckProject,
|
|
|
+ (newVal) => {
|
|
|
+ if (newVal) {
|
|
|
+ localSelectedTemplates.value = [...newVal]
|
|
|
+ }
|
|
|
+ },
|
|
|
+ { deep: true },
|
|
|
+)
|
|
|
+
|
|
|
+const handleConfirm = async () => {
|
|
|
+ const selected = localSelectedTemplates.value
|
|
|
+ if (selected.length === 0) {
|
|
|
+ uni.showToast({ title: '请至少选择一个检验项目', icon: 'none' })
|
|
|
+ return
|
|
|
+ }
|
|
|
+ const itemList = selected.map((item) => ({
|
|
|
+ connectId: item.connectId,
|
|
|
+ fee: item.fee,
|
|
|
+ orderItemId: props.equipData?.taskOrderItem?.id,
|
|
|
+ templateId: item.templateId,
|
|
|
+ type: props.equipData?.taskOrderItem?.boilerType,
|
|
|
+ }))
|
|
|
+
|
|
|
+ await addInspectProject({
|
|
|
+ itemList,
|
|
|
+ type: 200,
|
|
|
+ })
|
|
|
+
|
|
|
+ console.log('确认选中的检验项目:', itemList)
|
|
|
+ emit('confirm', itemList)
|
|
|
+}
|
|
|
+
|
|
|
+const handleCancel = () => {
|
|
|
+ localSelectedTemplates.value = []
|
|
|
+ emit('cancel')
|
|
|
+}
|
|
|
+</script>
|
|
|
+
|
|
|
+<style lang="scss" scoped>
|
|
|
+.check-project-container {
|
|
|
+ display: flex;
|
|
|
+ flex-direction: column;
|
|
|
+ height: 100%;
|
|
|
+ overflow: hidden;
|
|
|
+}
|
|
|
+
|
|
|
+.search-bar {
|
|
|
+ display: flex;
|
|
|
+ flex-shrink: 0;
|
|
|
+ gap: 10px;
|
|
|
+ align-items: center;
|
|
|
+ padding: 10px 0;
|
|
|
+}
|
|
|
+
|
|
|
+.dropdown-wrapper {
|
|
|
+ position: relative;
|
|
|
+}
|
|
|
+
|
|
|
+.dropdown-selector {
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ min-width: 100px;
|
|
|
+ padding: 8px 12px;
|
|
|
+ background-color: #f5f5f5;
|
|
|
+ border-radius: 4px;
|
|
|
+}
|
|
|
+
|
|
|
+.dropdown-text {
|
|
|
+ margin-right: 8px;
|
|
|
+ font-size: 14px;
|
|
|
+ color: #333;
|
|
|
+}
|
|
|
+
|
|
|
+.dropdown-arrow {
|
|
|
+ font-size: 10px;
|
|
|
+ color: #666;
|
|
|
+}
|
|
|
+
|
|
|
+.dropdown-menu {
|
|
|
+ position: absolute;
|
|
|
+ top: 100%;
|
|
|
+ left: 0;
|
|
|
+ z-index: 100;
|
|
|
+ min-width: 100px;
|
|
|
+ background-color: #fff;
|
|
|
+ border: 1px solid #e0e0e0;
|
|
|
+ border-radius: 4px;
|
|
|
+ box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
|
|
|
+}
|
|
|
+
|
|
|
+.dropdown-item {
|
|
|
+ padding: 10px 12px;
|
|
|
+ font-size: 14px;
|
|
|
+ color: #333;
|
|
|
+ border-bottom: 1px solid #f0f0f0;
|
|
|
+}
|
|
|
+
|
|
|
+.dropdown-item:last-child {
|
|
|
+ border-bottom: none;
|
|
|
+}
|
|
|
+
|
|
|
+.dropdown-item.active {
|
|
|
+ color: #2f8eff;
|
|
|
+ background-color: #e6f7ff;
|
|
|
+}
|
|
|
+
|
|
|
+.search-input {
|
|
|
+ flex: 1;
|
|
|
+ padding: 0 12px;
|
|
|
+ font-size: 14px;
|
|
|
+ background-color: #f5f5f5;
|
|
|
+ border-radius: 4px;
|
|
|
+}
|
|
|
+
|
|
|
+.project-list {
|
|
|
+ flex: 1;
|
|
|
+ height: 0;
|
|
|
+}
|
|
|
+
|
|
|
+.project-group {
|
|
|
+ margin-bottom: 10px;
|
|
|
+}
|
|
|
+
|
|
|
+.project-group-header {
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: space-between;
|
|
|
+ padding: 12px;
|
|
|
+ background-color: #f5f5f5;
|
|
|
+}
|
|
|
+
|
|
|
+.project-group-title {
|
|
|
+ font-size: 14px;
|
|
|
+ font-weight: 600;
|
|
|
+ color: #333;
|
|
|
+}
|
|
|
+
|
|
|
+.project-group-count {
|
|
|
+ font-size: 12px;
|
|
|
+ color: #999;
|
|
|
+}
|
|
|
+
|
|
|
+.project-grid {
|
|
|
+ display: flex;
|
|
|
+ flex-wrap: wrap;
|
|
|
+ gap: 10px;
|
|
|
+}
|
|
|
+
|
|
|
+.project-item {
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ min-width: calc(50% - 5px);
|
|
|
+ max-width: calc(50% - 5px);
|
|
|
+ padding: 10px 15px;
|
|
|
+ background-color: #fff;
|
|
|
+ border: 1px solid #d9d9d9;
|
|
|
+ border-radius: 4px;
|
|
|
+}
|
|
|
+
|
|
|
+.project-item.first {
|
|
|
+ border-top-left-radius: 4px;
|
|
|
+}
|
|
|
+
|
|
|
+.project-item.first:last-child,
|
|
|
+.project-item.first:nth-last-child(2) {
|
|
|
+ border-top-right-radius: 4px;
|
|
|
+}
|
|
|
+
|
|
|
+.project-item.last {
|
|
|
+ border-bottom-left-radius: 4px;
|
|
|
+}
|
|
|
+
|
|
|
+.project-item.last:nth-child(odd) {
|
|
|
+ border-bottom-right-radius: 4px;
|
|
|
+}
|
|
|
+
|
|
|
+.project-item.selected {
|
|
|
+ background-color: #e6f7ff;
|
|
|
+ border-color: #2f8eff;
|
|
|
+}
|
|
|
+
|
|
|
+.project-name {
|
|
|
+ flex: 1;
|
|
|
+ overflow: hidden;
|
|
|
+ font-size: 14px;
|
|
|
+ color: #333;
|
|
|
+ text-overflow: ellipsis;
|
|
|
+ white-space: nowrap;
|
|
|
+}
|
|
|
+
|
|
|
+.empty-state {
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: center;
|
|
|
+ padding: 40px 0;
|
|
|
+}
|
|
|
+
|
|
|
+.empty-text {
|
|
|
+ font-size: 14px;
|
|
|
+ color: #999;
|
|
|
+}
|
|
|
+
|
|
|
+:deep(.wd-collapse-item) {
|
|
|
+ margin-bottom: 10px;
|
|
|
+ overflow: hidden;
|
|
|
+ background-color: #fff;
|
|
|
+ border-radius: 8px;
|
|
|
+}
|
|
|
+
|
|
|
+:deep(.wd-collapse-item__title) {
|
|
|
+ padding: 12px 15px;
|
|
|
+ font-size: 15px;
|
|
|
+ font-weight: 500;
|
|
|
+ color: #333;
|
|
|
+}
|
|
|
+
|
|
|
+:deep(.wd-collapse-item__title-wrapper) {
|
|
|
+ background-color: #fff;
|
|
|
+}
|
|
|
+
|
|
|
+:deep(.wd-collapse-item__content) {
|
|
|
+ padding: 10px;
|
|
|
+}
|
|
|
+
|
|
|
+:deep(.wd-collapse-item__arrow) {
|
|
|
+ color: #999;
|
|
|
+}
|
|
|
+
|
|
|
+.bottom-actions {
|
|
|
+ display: flex;
|
|
|
+ flex-direction: row;
|
|
|
+ flex-shrink: 0;
|
|
|
+ gap: 10px;
|
|
|
+ padding: 10px 15px;
|
|
|
+ background-color: #fff;
|
|
|
+ border-top: 1px solid #eee;
|
|
|
+
|
|
|
+ .action-btn {
|
|
|
+ display: flex;
|
|
|
+ flex: 1;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: center;
|
|
|
+ height: 40px;
|
|
|
+ font-size: 15px;
|
|
|
+ border: none;
|
|
|
+ border-radius: 5px;
|
|
|
+ }
|
|
|
+
|
|
|
+ .cancel-btn {
|
|
|
+ color: #666;
|
|
|
+ background-color: #f5f5f5;
|
|
|
+ border: 1px solid #ddd;
|
|
|
+ }
|
|
|
+
|
|
|
+ .confirm-btn {
|
|
|
+ color: #fff;
|
|
|
+ background-color: rgb(47, 142, 255);
|
|
|
+ }
|
|
|
+}
|
|
|
+</style>
|