applications/task-work-order/src/views/orderView/orderManage/clueEvents/ViewDiaLog.vue
@@ -1,8 +1,8 @@ <template> <el-dialog class="gd-dialog" :close-on-click-modal="false" v-model="visible" title="查看" @closed="visible = false" width="1000px" destroy-on-close> <div class="" v-loading="loading"> <div class="gd-table-content-bg"> <el-table :data="list"> <el-dialog class="gd-dialog" v-model="visible" title="查看" @closed="visible = false" width="1000px" destroy-on-close> <div class="gd-table-container" v-loading="loading" style="height: 600px"> <div class="gd-table-content gd-table-content-bg"> <el-table class="gd-table" :data="list"> <el-table-column label="线索缩略图" width="120"> <template v-slot="{ row }"> <el-image @@ -32,9 +32,10 @@ <el-table-column prop="distributeUserName" show-overflow-tooltip label="分发人员" /> <el-table-column label="操作" class-name="operation-btns" width="140"> <template v-slot="{ row }"> <el-link @click="openDistributeDialog(row)" :disabled="row.distributeStatus === 1"> <el-link v-if="row.distributeStatus === 0" @click="openDistributeDialog(row)" :disabled="row.distributeStatus === 1"> 转为事件并分发 </el-link> <div class="disabled-text" v-else>转为事件并分发</div> </template> </el-table-column> </el-table> @@ -119,4 +120,9 @@ defineExpose({ open }) </script> <style lang="scss" scoped></style> <style lang="scss" scoped> .disabled-text { color: #C0C4CC; cursor: not-allowed; } </style> applications/task-work-order/src/views/orderView/orderManage/clueEvents/index.vue
@@ -1,7 +1,8 @@ <!-- 线索事件管理 --> <template> <basic-container> <el-form ref="queryParamsRef" :model="searchParams" class="gd-search-form"> <el-form-item label="任务名称" prop="patrolTaskName"> <el-form-item label="模糊搜索" prop="patrolTaskName"> <el-input class="gd-input" v-model="searchParams.patrolTaskName" @@ -11,7 +12,7 @@ /> </el-form-item> <el-form-item label="任务类型" prop="patrolTaskType"> <el-form-item label="巡查任务类型" prop="patrolTaskType"> <el-select class="gd-select" popper-class="gd-select-popper" @@ -29,7 +30,7 @@ </el-select> </el-form-item> <el-form-item label="任务状态" prop="taskStatus"> <!-- <el-form-item label="任务状态" prop="taskStatus"> <el-select class="gd-select" popper-class="gd-select-popper" @@ -45,7 +46,7 @@ :value="item.dictKey" /> </el-select> </el-form-item> </el-form-item> --> <el-form-item label="执行时间" prop="executeTime"> <el-date-picker @@ -86,10 +87,12 @@ <el-table-column prop="executeTime" show-overflow-tooltip label="任务执行时间" /> <el-table-column prop="workOrderName" show-overflow-tooltip label="关联工单" /> <el-table-column prop="createTime" show-overflow-tooltip label="巡查任务创建时间" /> <el-table-column prop="resultCount" show-overflow-tooltip label="线索数量" /> <el-table-column prop="issueEventCount" show-overflow-tooltip label="转为问题" /> <el-table-column prop="taskDesc" show-overflow-tooltip label="巡查任务描述" /> <el-table-column label="操作" class-name="operation-btns"> <template v-slot="{ row }"> <el-link @click="viewDiaLogView(row)">查看</el-link> <el-link @click="viewDiaLogView(row)">查看线索</el-link> </template> </el-table-column> </el-table> applications/task-work-order/src/views/orderView/orderManage/inspectionReport/index.vue
@@ -1,9 +1,348 @@ <!-- 巡查报告管理 --> <template> <basic-container> 基础管理 <el-form ref="queryParamsRef" :model="searchParams" class="gd-search-form"> <el-form-item label="模糊搜索" prop="nickName"> <el-input class="gd-input" v-model="searchParams.nickName" placeholder="请输入" clearable @clear="handleSearch" /> </el-form-item> <el-form-item label="文档类型" prop="resultType"> <el-select class="gd-select" popper-class="gd-select-popper" v-model="searchParams.resultType" placeholder="请选择" clearable @change="handleSearch" > <el-option v-for="item in dictObj.patrolTaskType" :key="item.dictKey" :label="item.dictValue" :value="item.dictKey" /> </el-select> </el-form-item> <el-form-item class="gd-search-actions"> <el-button :icon="RefreshRight" @click="resetForm"></el-button> <el-button class="search-btn" :icon="Search" @click="handleSearch"></el-button> </el-form-item> </el-form> <div class="gd-table-toolbar"> <el-button :icon="Download" color="#4C34FF" type="primary" @click="handleDownload">文档下载</el-button> <el-button :icon="Upload" color="#4C34FF" type="primary" @click="handleUpload">文档上传</el-button> </div> <div class="gd-table-container" v-loading="loading"> <div class="gd-table-content gd-table-content-bg"> <el-table class="gd-table" :data="list" @selection-change="handleSelectionChange"> <el-table-column type="selection" width="46" /> <el-table-column type="index" width="64" label="序号" /> <el-table-column prop="nickName" show-overflow-tooltip label="文档名称" /> <el-table-column prop="attachSize" show-overflow-tooltip label="文档大小" /> <el-table-column prop="deptName" show-overflow-tooltip label="文档归属" /> <!-- <el-table-column prop="resultType" show-overflow-tooltip label="文档类型" /> --> <el-table-column prop="resultType" show-overflow-tooltip label="文档类型"> <template v-slot="{ row }"> {{ getDictLabel(row.resultType, dictObj.patrolTaskType) }} </template> </el-table-column> <el-table-column label="操作" class-name="operation-btns"> <template v-slot="{ row }"> <el-link @click="seeOnlineWord(item)">查看</el-link> <el-link @click="openForm(row)">在线编辑</el-link> <el-link @click="handleDelete(row)">删除</el-link> </template> </el-table-column> </el-table> </div> <div class="gd-pagination-parent"> <el-pagination popper-class="gd-select-popper" v-model:current-page="searchParams.current" v-model:page-size="searchParams.size" layout="total, prev, pager, next, sizes" :total="total" @change="getList" /> </div> </div> <el-dialog class="gd-dialog" append-to-body v-model="isShowEditView" :title="titleTxt" :width="pxToRem(800)" :close-on-click-modal="false" :destroy-on-close="true" @close="handleClose"> <el-form class="gd-dialog-form" ref="ruleFormRef" :model="editParams" :rules="rules" label-width="140px"> <el-form-item label="文档名称" prop="nickName"> <el-input v-model="editParams.nickName" /> </el-form-item> <el-form-item label="文档类型" prop="resultType" v-if="titleTxt === '上传巡查报告'"> <el-select class="gd-select" popper-class="gd-select-popper" v-model="editParams.resultType" placeholder="请选择" clearable > <el-option v-for="item in dictObj.patrolTaskType" :key="item.dictKey" :label="item.dictValue" :value="item.dictKey" /> </el-select> </el-form-item> <el-form-item label="上传文件" prop="link" v-if="titleTxt === '上传巡查报告'"> {{ uploadName }} <el-upload class="avatar-uploader" action="" :show-file-list="false" :before-upload="onUploadFileBefore" > <el-button size="small" type="primary">点击上传</el-button> </el-upload> </el-form-item> </el-form> <!-- </div> --> <template #footer> <el-button color="#F2F3F5" @click="isShowEditView = false">取消</el-button> <el-button class="save-btn" color="#4C34FF" :loading="submitting" :disabled="submitting" @click="submit(ruleFormRef)"> 保存 </el-button> </template> </el-dialog> <PreviewFiles v-model="previewVisible" :src="searchUrl" type="docx"/> <el-image v-if="previewVisibleImg" :src="searchUrl" fit="contain" style="height: 100%;width: 100%" /> </basic-container> </template> <script setup> import { Search, RefreshRight, Download, Upload, Delete } from '@element-plus/icons-vue' import { fjPageApi, fjSubmitApi, fjRemoveApi, fjDetailApi, fjUploadApi } from './inspectionRequestApi' import { useStore } from 'vuex' import { ref, computed, inject, onMounted } from 'vue' import { ElMessage, ElMessageBox } from 'element-plus' import { getDictLabel } from '@ztzf/utils' import PreviewFiles from '@/components/PreviewFiles/PreviewFiles.vue' import { getDictionaryByCode } from '@/api/system/dictbiz' const store = useStore() const userInfo = computed(() => store.getters.userInfo); // 初始化查询参数 const initSearchParams = () => ({ nickName: '', resultType: '', current: 1, // 当前页 size: 10, // 每页大小 }) // 查看文档 const previewVisible = ref(false) const previewVisibleImg = ref(false) const searchUrl = ref('') // 上传名称 const uploadName = ref('') const dictObj = ref({ patrolTaskType: [], // 巡查任务类型 }) const searchParams = ref(initSearchParams()) // 查询参数 const total = ref(0) // 总条数 const loading = ref(true) // 列表加载中 const list = ref([]) // 列表数据 const selectedIds = ref([]) // 勾选的ID列表 const selectedFiles = ref([]) // 勾选的文件列表 const queryParamsRef = ref(null) // 查询表单实例 const isShowEditView = ref(false) const titleTxt = ref('上传巡查报告') const editParams = ref({ id:'', nickName: '', resultType: '', link: '', }) const ruleFormRef = ref() const submitting = ref(false) const rules = ref({ nickName: [{ required: true, message: '请输入文档名称', trigger: ['blur'] }], resultType: [{ required: true, message: '请选择文档类型', trigger: ['change'] }], link: [{ required: true, message: '请上传文件', trigger: ['change'] }], }) // 获取字典 function getDictList() { getDictionaryByCode('patrolTaskType').then(res => { dictObj.value = res.data.data }) } // 获取列表 async function getList() { loading.value = true try { const res = await fjPageApi({ ...searchParams.value }) console.log(res?.data?.data?.records,'888') list.value = res?.data?.data?.records ?? [] console.log(list.value,'999') total.value = res?.data?.data?.total ?? 0 } finally { loading.value = false } } // 重置查询 function resetForm() { queryParamsRef.value?.resetFields() searchParams.value.current = 1 getList() } // 查询 function handleSearch() { searchParams.value.current = 1 getList() } // 新增/编辑/查看 弹框 function openForm(row) { isShowEditView.value = true titleTxt.value = '编辑' editParams.value.id = row.id editParams.value.nickName = row.nickName editParams.value.resultType = row.resultType editParams.value.link = row.link } // 在线查看文档 function seeOnlineWord(item) { if (!item.link) { ElMessage.error('文档链接不存在') return } else if (!item.link.includes('docx') && !item.link.includes('pdf') && !item.link.includes('png') && !item.link.includes('jpg')) { ElMessage.error('可进行下载观看!') return } else if (item.link.includes('png') || item.link.includes('jpg')) { previewVisibleImg.value = true searchUrl.value = item.link return } else if (item.link.includes('docx') || item.link.includes('pdf')) { previewVisible.value = true searchUrl.value = item.link return } } // 删除 async function handleDelete(row) { const tips = row ? '该条' : '选中的项' await ElMessageBox.confirm(`确认删除${tips}吗?`, '提示', { type: 'warning', customClass: 'gd-confirm-custom', confirmButtonClass: 'gd-confirm-button', cancelButtonClass: 'gd-confirm-cancel-button', }) const ids = row ? row.id : selectedIds.value.join(',') await fjRemoveApi({ ids }) ElMessage.success('删除成功') selectedIds.value = [] getList() } // 勾选值设置 function handleSelectionChange(rows) { selectedFiles.value = rows selectedIds.value = rows.map((item) => item.id) } // 文档下载 async function handleDownload() { // 如果是勾选一个可以直接下载,超过一个打包下载 // 依次下载每个文件(添加延迟以避免浏览器限制) selectedFiles.value.forEach((file, index) => { setTimeout(() => { if (file.link) { const a = document.createElement('a') a.href = file.link a.download = file.originalName || `attachment_${index + 1}` document.body.appendChild(a) a.click() document.body.removeChild(a) } }, index * 300) // 300ms delay between downloads }) } // 文档上传 async function handleUpload() { isShowEditView.value = true titleTxt.value = '上传巡查报告' } // 上传文件前处理 function onUploadFileBefore(file) { // 执行文件上传 let data = new FormData(); data.append('file', file); fjUploadApi(data).then(res => { if (res.data.code === 200) { ElMessage.success('上传成功') // 保存文件URL到表单 uploadName.value = res.data.data.originalName editParams.value.link = res.data.data.link } else { ElMessage.error(res.msg || '上传失败') } }) return false // 阻止组件的默认上传行为 } // 保存上传文件数据 async function submit(formValidate) { if (!formValidate) return await formValidate.validate(async (valid, fields) => { if (valid) { submitting.value = true try { await fjSubmitApi({ ...editParams.value }) ElMessage.success('保存成功') isShowEditView.value = false getList() } finally { submitting.value = false } } }) } function handleClose() { // 清除表单内容 uploadName.value = '' editParams.value = { id: '', nickName: '', resultType: '', uploadFile: '', } } onMounted(() => { getDictList() getList() }) </script> <style scoped lang="scss"> </style> applications/task-work-order/src/views/orderView/orderManage/operatingIncome/index.vue
@@ -1,9 +1,329 @@ <!-- 运营收益 --> <template> <basic-container> 基础管理 <div class="gd-table-toolbar"> <el-button :icon="Plus" color="#4C34FF" type="primary" @click="handleAdd">新增</el-button> <el-button :icon="Delete" color="#4C34FF" :disabled="!selectedIds.length" @click="handleDelete()">删除</el-button> </div> <div class="gd-table-container" v-loading="loading"> <div class="gd-table-content gd-table-content-bg"> <el-table class="gd-table" :data="tableList" @selection-change="handleSelectionChange"> <el-table-column type="selection" width="46" /> <el-table-column label="序号" type="index" width="60"></el-table-column> <el-table-column prop="operatingIncome" label="营业收入" align="center"></el-table-column> <el-table-column prop="totalCost" label="综合总成本费用" align="center"></el-table-column> <el-table-column prop="netProfit" label="净利润" align="center"></el-table-column> <el-table-column prop="financialIrr" label="财务内部收益率" align="center"></el-table-column> <el-table-column prop="marketSpace" label="市场空间" align="center" show-overflow-tooltip></el-table-column> <el-table-column prop="createTime" label="创建时间" align="center"></el-table-column> <el-table-column prop="nickName" label="创建人" align="center"></el-table-column> <el-table-column label="操作" width="180" align="center"> <template #default="scope"> <!-- <el-button icon="el-icon-view" type="text" @click="handleDetail(scope.row)">查看</el-button> --> <el-button type="text" @click="handleEdit(scope.row)">编辑</el-button> <el-button type="text" @click="handleDelete(scope.row)">删除</el-button> </template> </el-table-column> </el-table> </div> <div class="gd-pagination-parent"> <el-pagination popper-class="gd-select-popper" v-model:current-page="params.current" v-model:page-size="params.size" layout="total, prev, pager, next, sizes" :total="total" @change="getList" /> </div> </div> <el-dialog class="gd-dialog" append-to-body v-model="isShowEditView" :title="titleTxt" :width="pxToRem(800)" :close-on-click-modal="false" :destroy-on-close="true" @close="handleClose"> <el-form class="gd-dialog-form" ref="ruleFormRef" :model="editParams" :rules="rules" label-width="140px"> <el-form-item label="营业收入" prop="operatingIncome"> <el-input v-model="editParams.operatingIncome" /> </el-form-item> <el-form-item label="综合总成本费用" prop="totalCost"> <el-input v-model="editParams.totalCost" /> </el-form-item> <el-form-item label="净利润" prop="netProfit"> <el-input v-model="editParams.netProfit" /> </el-form-item> <el-form-item label="财务内部收益率" prop="financialIrr"> <el-input v-model="editParams.financialIrr" /> </el-form-item> <el-form-item label="市场空间" prop="marketSpace"> <el-input v-model="editParams.marketSpace" /> </el-form-item> </el-form> <!-- </div> --> <template #footer> <el-button color="#F2F3F5" @click="isShowEditView = false">取消</el-button> <el-button class="save-btn" color="#4C34FF" :loading="submitting" :disabled="submitting" @click="submit(ruleFormRef)"> 保存 </el-button> </template> </el-dialog> </basic-container> </template> <script setup> import { ElMessage, ElMessageBox, ElLoading } from 'element-plus'; import { operatingIncomePage, operatingIncomeUpdate, operatingIncomeAdd, operatingIncomeBatchDelete } from './operatingIncomeApi'; let titleTxt = ref('新增') const total = ref(0) const params = ref({ current: 1, size: 10, }); const submitting = ref(false) const loading = ref(true) // 列表加载中 const selectedIds = ref([]) // 勾选的ID列表 let tableList = ref([]) let isShowEditView = ref(false) const ruleFormRef = ref() let editParams = ref({ id: '', operatingIncome: '', totalCost: '', netProfit: '', financialIrr: '', marketSpace: '', }) const rules = reactive({ operatingIncome: [ { required: true, message: '请输入营业收入', trigger: 'blur' }, { validator: (rule, value, callback) => { if (!/^\d+(\.\d+)?$/.test(value)) { callback(new Error('请输入有效的数字(整数或小数)')); } else { callback(); } }, trigger: 'blur' } ], totalCost: [ { required: true, message: '请输入综合总成本费用', trigger: 'blur' }, { validator: (rule, value, callback) => { if (!/^\d+(\.\d+)?$/.test(value)) { callback(new Error('请输入有效的数字(整数或小数)')); } else { callback(); } }, trigger: 'blur' } ], netProfit: [ { required: true, message: '请输入净利润', trigger: 'blur' }, { validator: (rule, value, callback) => { if (!/^\d+(\.\d+)?$/.test(value)) { callback(new Error('请输入有效的数字(整数或小数)')); } else { callback(); } }, trigger: 'blur' } ], financialIrr: [ { required: true, message: '请输入财务内部收益率', trigger: 'blur' }, { validator: (rule, value, callback) => { if (!/^\d+(\.\d+)?$/.test(value)) { callback(new Error('请输入有效的数字(整数或小数)')); } else { callback(); } }, trigger: 'blur' } ], marketSpace: [ { required: true, message: '请输入市场空间', trigger: 'blur' }, ], }) // 勾选值设置 function handleSelectionChange(rows) { selectedIds.value = rows.map(item => item.id) } function getList() { loading.value = true operatingIncomePage(params.value).then(res => { tableList.value = res.data.data.records || [] total.value = res.data.data.total || 0 }).finally(() => { loading.value = false }) } function handleEdit(row) { titleTxt.value = '编辑' isShowEditView.value = true editParams.value = { ...row } } // 删除 async function handleDelete(row) { const tips = row ? '该条' : '选中的项' await ElMessageBox.confirm(`确认删除${tips}吗?`, '提示', { type: 'warning', customClass: 'gd-confirm-custom', confirmButtonClass: 'gd-confirm-button', cancelButtonClass: 'gd-confirm-cancel-button', }) const ids = row ? row.id : selectedIds.value await operatingIncomeBatchDelete(ids) ElMessage.success('删除成功') selectedIds.value = [] getList() } function handleAdd() { titleTxt.value = '新增' isShowEditView.value = true } async function submit(formValidate) { if (!formValidate) return await formValidate.validate((valid, fields) => { if (valid) { submitting.value = true try { if (titleTxt.value === '新增') { operatingIncomeAdd(editParams.value).then(res => { isShowEditView.value = false ElMessage.success('新增成功') getList() }) } else { operatingIncomeUpdate(editParams.value).then(res => { isShowEditView.value = false ElMessage.success('操作成功') getList() }) } } finally { submitting.value = false } } }) } function handleClose() { // 清除表单内容 editParams.value = { id: '', operating_income: '', total_cost: '', net_profit: '', financial_irr: '', market_space: '', } } onMounted(() => { getList() }) </script> <style scoped lang="scss"> <style lang="scss" scoped> .operatingIncome { height: 0; flex: 1; margin: 0 10px 10px 10px; background-color: #ffffff; padding: 10px 20px; border-radius: 5px; display: flex; flex-direction: column; .search-box { margin-top: 20px; height: 40px; } :deep(.el-input) { .el-input__wrapper { width: 200px; } } // 表格 .mange-table { height: 0; flex: 1; margin-top: 18px; overflow: auto; } :deep(.el-pagination) { display: flex; justify-content: right; } :deep(.el-pagination button) { background: center center no-repeat none !important; color: #8eb8ea !important; } :deep(.ztzf-select){ .el-select__selection { width: 200px; } } } .content { padding: 20px; .view-table { width: 100%; border-collapse: collapse; border: 1px solid #EBEEF5; tr { &:not(:last-child) { border-bottom: 1px solid #EBEEF5; } td { padding: 12px 10px; &.label { width: 140px; text-align: right; // color: #909399; // background-color: #F5F7FA; border-right: 1px solid #EBEEF5; } &.value { width: 180px; // color: #303133; } } } } } .content-edit { .el-form { .el-form-item { width: 320px; :deep(.el-form-item__label) { width: 140px; } } // .el-form-item:last-child { // width: 640px; // } .btns { display: flex; justify-content: center } } } </style> uniapps/work-wx/src/subPackages/regulationsDetail/details.vue
@@ -1,6 +1,6 @@ <template> <view class="regulationsDetail"> <scroll-view <scroll-view class="scroll-container" scroll-y :enable-back-to-top="true" @@ -18,6 +18,7 @@ </view> </view> </scroll-view> <u-pdf-reader v-if="pdfUrl" :src="pdfUrl"></u-pdf-reader> </view> </template> <script setup> @@ -39,10 +40,14 @@ td: 'border: 1px solid #ddd; padding: 8rpx;' }; const pdfUrl = ref('') function downloadFile(item) { console.log(item,'999') // aLinkDownloadUtil(item.fileUrl, item.fileName) downloadAndPreview(item.fileUrl, item.fileName) // downloadAndPreview(item.fileUrl, item.fileName) pdfUrl.value = item.fileUrl // downloadAndSavePDF(item.fileUrl, item.fileName) } // 下载并打开文件(支持PDF、图片、Word等) const downloadAndPreview = async (fileUrl, fileName) => { @@ -50,18 +55,18 @@ title: '下载中...', mask: true }) try { // 1. 下载文件到临时目录 const downloadRes = await uni.downloadFile({ url: fileUrl, timeout: 60000 }) if (downloadRes.statusCode !== 200) { throw new Error(`下载失败: ${downloadRes.statusCode}`) } // 2. 打开文件(小程序会调用系统能力) uni.openDocument({ filePath: downloadRes.tempFilePath, @@ -80,7 +85,7 @@ handleOpenFail(downloadRes.tempFilePath, fileName) } }) } catch (error) { console.error('下载失败:', error) uni.showToast({ @@ -90,6 +95,84 @@ } finally { uni.hideLoading() } } // 下载并保存PDF到手机(iOS需要特殊处理) const downloadAndSavePDF = (pdfUrl, fileName = 'document.pdf') => { uni.showLoading({ title: '下载中...', mask: true }) // 检查权限(主要针对iOS) const checkAndDownload = () => { uni.downloadFile({ url: pdfUrl, success: (downloadRes) => { uni.hideLoading() if (downloadRes.statusCode === 200) { const tempFilePath = downloadRes.tempFilePath // 保存到本地 uni.saveFile({ tempFilePath: tempFilePath, success: (saveRes) => { const savedFilePath = saveRes.savedFilePath uni.showModal({ title: '下载成功', content: `文件已保存到: ${savedFilePath}`, showCancel: false, success: () => { // 可以引导用户去文件管理查看 } }) }, fail: (saveErr) => { console.error('保存失败:', saveErr) uni.showToast({ title: '保存失败111', icon: 'error' }) } }) } }, fail: (err) => { uni.hideLoading() uni.showToast({ title: '下载失败1111', icon: 'error' }) } }) } // 检查文件访问权限 uni.authorize({ scope: 'scope.writePhotosAlbum', success: () => { checkAndDownload() }, fail: () => { uni.showModal({ title: '权限提示', content: '需要文件存储权限才能下载文件', success: (modalRes) => { if (modalRes.confirm) { uni.openSetting({ success: (settingRes) => { if (settingRes.authSetting['scope.writePhotosAlbum']) { checkAndDownload() } } }) } } }) } }) } // 获取文件类型 @@ -142,7 +225,7 @@ .safe-area { /* 处理导航栏高度 */ padding-top: var(--status-bar-height); /* iOS 安全区域 */ padding-top: constant(safe-area-inset-top); padding-top: env(safe-area-inset-top); @@ -153,12 +236,12 @@ overflow: hidden; /* 关键:滚动内容在安全区域内 */ height: calc(100vh - var(--status-bar-height) - 44px); /* 计算高度考虑导航栏 */ @supports (top: constant(safe-area-inset-top)) { height: calc(100vh - constant(safe-area-inset-top) - 44px); } @supports (top: env(safe-area-inset-top)) { height: calc(100vh - env(safe-area-inset-top) - 44px); } @@ -166,7 +249,7 @@ .content { padding: 0 24rpx 40rpx; .title { font-family: Source Han Sans CN, Source Han Sans CN; font-weight: 500;