合并 #2

Merged
shenhong merged 4 commits from fea into dev 2025-06-12 17:27:00 +08:00
6 changed files with 235 additions and 37 deletions
Showing only changes of commit a461a5e488 - Show all commits

View File

@ -16,5 +16,5 @@ VITE_APP_UPLOAD_API = '/uploadApis'
# VITE_APP_BASE_URL = 'http://47.109.205.240:8080' # VITE_APP_BASE_URL = 'http://47.109.205.240:8080'
# VITE_APP_UPLOAD_URL = 'http://47.109.205.240:9300' # VITE_APP_UPLOAD_URL = 'http://47.109.205.240:9300'
# 内网接口地址 # 内网接口地址
VITE_APP_BASE_URL = 'http://192.168.18.74:8080' VITE_APP_BASE_URL = 'http://192.168.18.99:8080'
VITE_APP_UPLOAD_URL = 'http://192.168.18.74:8080' VITE_APP_UPLOAD_URL = 'http://192.168.18.99:8080'

View File

@ -13,5 +13,5 @@ VITE_APP_UPLOAD_API = '/uploadApis'
# VITE_APP_UPLOAD_URL = 'http://47.109.205.240:9300' # VITE_APP_UPLOAD_URL = 'http://47.109.205.240:9300'
# 内网接口地址 # 内网接口地址
VITE_APP_BASE_URL = 'http://192.168.18.74:8080' VITE_APP_BASE_URL = 'http://192.168.18.99:8080'
VITE_APP_UPLOAD_URL = 'http://192.168.18.74:8080' VITE_APP_UPLOAD_URL = 'http://192.168.18.99:8080'

View File

@ -66,6 +66,13 @@ export function createInspectionResult(data) {
data, data,
}); });
} }
// 巡查结果-批量新增POST
export function createInspectionResultBatch(data) {
return request('/land-resource/inspection/result/saveBatch', {
method: 'POST',
data,
});
}
// 巡查结果-删除DELETE // 巡查结果-删除DELETE
export function deleteInspectionResult(id) { export function deleteInspectionResult(id) {
return request(`/land-resource/inspection/result/${id}`, { return request(`/land-resource/inspection/result/${id}`, {

View File

@ -0,0 +1,113 @@
<template>
<div class="file-uploader">
<el-upload
class="file-uploader__upload"
:http-request="customUploadRequest"
:on-success="handleUploadSuccess"
:on-remove="handleRemove"
:file-list="fileList"
list-type="picture-card"
:limit="limit"
:show-file-list="true"
:auto-upload="true"
:disabled="readonly"
:accept="accept"
>
<el-icon v-if="fileList.length < limit"><Plus /></el-icon>
</el-upload>
<el-image-viewer v-if="previewShow" :url-list="previewList" :initial-index="previewIndex" @close="previewShow = false" />
</div>
</template>
<script setup>
import { ref, computed } from 'vue';
import { Plus } from '@element-plus/icons-vue';
import { CommonUpload } from '@/apis/index';
const props = defineProps({
modelValue: {
type: Array,
default: () => [],
},
ossUrl: {
type: String,
default: 'http://gov-cloud.oss-cn-chengdu.aliyuncs.com/',
},
limit: {
type: Number,
default: 5,
},
accept: {
type: String,
default: 'image/*',
},
readonly: {
type: Boolean,
default: false,
},
});
const emit = defineEmits(['update:modelValue']);
// el-upload file-list
const fileList = computed(() => {
return props.modelValue.map((path, idx) => ({
name: `image_${idx}`,
url: props.ossUrl + path,
uid: `${idx}`,
}));
});
//
const previewShow = ref(false);
const previewList = computed(() => fileList.value.map((item) => item.url));
const previewIndex = ref(0);
//
const customUploadRequest = async ({ file, onSuccess, onError }) => {
const formData = new FormData();
formData.append('file', file);
try {
const res = await CommonUpload(formData);
// { code:200, data: { url: 'relative/path.jpg' } }
onSuccess(res, file);
} catch (err) {
onError(err);
}
};
// modelValue
function handleUploadSuccess(res) {
const relative = res.data?.url;
if (relative) {
const newArr = [...props.modelValue, relative];
emit('update:modelValue', newArr);
}
}
//
function handleRemove(file) {
const fullUrl = file.url;
const relative = fullUrl.replace(props.ossUrl, '');
const newArr = props.modelValue.filter((path) => path !== relative);
emit('update:modelValue', newArr);
}
//
function handlePreview(file) {
const idx = fileList.value.findIndex((item) => item.uid === file.uid);
if (idx !== -1) {
previewIndex.value = idx;
previewShow.value = true;
}
}
</script>
<style scoped>
.file-uploader {
display: flex;
flex-wrap: wrap;
}
.file-uploader__upload {
margin-right: 16px;
}
</style>

View File

@ -2,7 +2,7 @@ import Layout from '@/layouts/index.vue';
// import annualplanRouters from './annualplan'; // import annualplanRouters from './annualplan';
import statisticsRoutes from './statisticAnalysis'; import statisticsRoutes from './statisticAnalysis';
import landsRoutes from './lands'; import landsRoutes from './lands';
import dictRoutes from './dict'; // import dictRoutes from './dict';
export default [ export default [
{ {
@ -48,7 +48,7 @@ export default [
// ...annualplanRouters, // ...annualplanRouters,
...landsRoutes, ...landsRoutes,
// ...statisticsRoutes, // ...statisticsRoutes,
...dictRoutes, // ...dictRoutes,
], ],
}, },
]; ];

View File

@ -15,7 +15,7 @@
<el-button type="success" icon="download" @click="handleExport">导出</el-button> <el-button type="success" icon="download" @click="handleExport">导出</el-button>
</template> </template>
<template #menu="scope"> <template #menu="scope">
<custom-table-operate :actions="crudOptions.actions" :data="scope" /> <custom-table-operate :actions="getActions(scope.row)" :data="scope" />
</template> </template>
</avue-crud> </avue-crud>
@ -71,7 +71,7 @@
<div v-for="(form, index) in illegalForms" :key="index" class="form-container"> <div v-for="(form, index) in illegalForms" :key="index" class="form-container">
<div class="form-header"> <div class="form-header">
<span>记录 #{{ index + 1 }}</span> <span>记录 #{{ index + 1 }}</span>
<el-button v-if="illegalForms.length > 1" type="danger" icon="el-icon-delete" circle size="mini" @click="handleRemoveForm(index)" /> <el-button v-if="!isReadonlyRegist" type="danger" icon="el-icon-delete" circle size="mini" @click="handleRemoveForm(index)" />
</div> </div>
<el-form :model="form" :disabled="isReadonlyRegist" label-width="100px" class="form-item"> <el-form :model="form" :disabled="isReadonlyRegist" label-width="100px" class="form-item">
@ -90,29 +90,27 @@
</el-form-item> </el-form-item>
<el-form-item label="是否违法" prop="illegalFlag"> <el-form-item label="是否违法" prop="illegalFlag">
<el-radio-group v-model="form.illegalFlag"> <el-radio-group v-model="form.illegalFlag">
<el-radio :label="1"></el-radio> <el-radio value="1"></el-radio>
<el-radio :label="0"></el-radio> <el-radio value="0"></el-radio>
</el-radio-group> </el-radio-group>
</el-form-item> </el-form-item>
<!-- 违法时间 --> <!-- 违法时间 -->
<el-form-item label="违法时间" prop="illegalDate"> <el-form-item v-if="form.illegalFlag === '1'" label="违法时间" prop="illegalDate">
<el-date-picker v-model="form.illegalDate" type="datetime" placeholder="选择违法时间" /> <el-date-picker
v-model="form.illegalDate"
type="datetime"
placeholder="选择违法时间"
format="YYYY年MM月DD日"
value-format="YYYY-MM-DD"
:disabled="isReadonlyRegist || form.illegalFlag === 0"
/>
</el-form-item> </el-form-item>
<!-- 违法图片 --> <!-- 违法图片 -->
<el-form-item label="违法图片" prop="illegalImages"> <el-form-item v-if="form.illegalFlag === '1'" label="违法图片" prop="illegalImages">
<el-upload <file-uploader v-model="form.illegalImages" :limit="1" :readonly="isReadonlyRegist || form.illegalFlag === 0" />
action="/upload"
list-type="picture-card"
:on-success="(res, file) => handleUploadSuccess(res, file, index)"
:on-error="handleUploadError"
:on-preview="handlePreview"
:on-remove="(file, fileList) => handleRemove(file, fileList, index)"
>
<i class="el-icon-plus"></i>
</el-upload>
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col :span="12"> <el-col v-if="form.illegalFlag === '1'" :span="12">
<el-form-item label="违法类型" prop="illegalType"> <el-form-item label="违法类型" prop="illegalType">
<url-select <url-select
v-model="form.illegalTypeCode" v-model="form.illegalTypeCode"
@ -121,10 +119,17 @@
label-key="dictLabel" label-key="dictLabel"
value-key="dictValue" value-key="dictValue"
:response-parser="(res) => res.data" :response-parser="(res) => res.data"
:disabled="isReadonlyRegist || form.illegalFlag === 0"
/> />
</el-form-item> </el-form-item>
<el-form-item label="违法行为描述" prop="desc"> <el-form-item v-if="form.illegalFlag === '1'" label="违法行为描述" prop="desc">
<el-input v-model="form.desc" :autosize="{ minRows: 2, maxRows: 6 }" type="textarea" placeholder="请输入违法行为描述" /> <el-input
v-model="form.desc"
:autosize="{ minRows: 2, maxRows: 6 }"
type="textarea"
placeholder="请输入违法行为描述"
:disabled="isReadonlyRegist || form.illegalFlag === 0"
/>
</el-form-item> </el-form-item>
</el-col> </el-col>
</el-row> </el-row>
@ -150,6 +155,7 @@ import { ref, reactive, watch, onMounted, computed, nextTick } from 'vue';
import { CRUD_OPTIONS } from '@/config'; import { CRUD_OPTIONS } from '@/config';
import { ElMessage } from 'element-plus'; import { ElMessage } from 'element-plus';
import { useActionPermissions } from '@/hooks/useActionPermissions'; import { useActionPermissions } from '@/hooks/useActionPermissions';
import { useUserStore } from '@/store/modules/user';
import { import {
createLandInspection, createLandInspection,
deleteLandInspection, deleteLandInspection,
@ -159,6 +165,7 @@ import {
fetchLandInspectionList, fetchLandInspectionList,
exportLandInspection, exportLandInspection,
createInspectionResult, createInspectionResult,
createInspectionResultBatch,
deleteInspectionResult, deleteInspectionResult,
getInspectionResultDetail, getInspectionResultDetail,
} from '@/apis/landResourceManagement/landInspection/index'; } from '@/apis/landResourceManagement/landInspection/index';
@ -167,6 +174,9 @@ const dialogTitle = ref('新增');
const visible = ref(false); const visible = ref(false);
const isReadonlyInfo = ref(false); const isReadonlyInfo = ref(false);
const isReadonlyRegist = ref(false); const isReadonlyRegist = ref(false);
const UserStore = useUserStore();
const user = UserStore.getUserInfo();
console.log('admin 属性:', user.admin);
const pageData = ref({ const pageData = ref({
currentPage: 1, currentPage: 1,
@ -205,7 +215,7 @@ const illegalForm = ref({
illegalTypeCode: '', // illegalTypeCode: '', //
illegalTypeName: '', // illegalTypeName: '', //
desc: '', // desc: '', //
img: '111', // img: '', //
status: '', // status: '', //
}); });
const illegalForms = ref([{ ...illegalForm.value }]); const illegalForms = ref([{ ...illegalForm.value }]);
@ -224,7 +234,7 @@ const crudOptions = reactive({
{ label: '巡查对象', prop: 'inspectionTarget' }, { label: '巡查对象', prop: 'inspectionTarget' },
{ label: '注意事项', prop: 'notes' }, { label: '注意事项', prop: 'notes' },
{ label: '是否违法', prop: 'isIllegal' }, { label: '是否违法', prop: 'isIllegal' },
{ label: '状态', prop: 'inspectionStatus' }, { label: '状态', prop: 'inspectionStatusName' },
], ],
actions: [ actions: [
{ {
@ -322,9 +332,17 @@ const handleView = async (id) => {
const response = await getLandInspectionDetail(id); const response = await getLandInspectionDetail(id);
taskForm.value = response.data; taskForm.value = response.data;
const arr = response.data.inspectionResults; const arr = response.data.inspectionResults;
if (arr && Array.isArray(arr)) { illegalForms.value = arr ? arr : [];
illegalForms.value = arr; illegalForms.value.forEach((item) => {
} // img
if (item.img) {
//
item.illegalImages = [item.img];
} else {
//
item.illegalImages = [];
}
});
isReadonlyInfo.value = true; isReadonlyInfo.value = true;
if (taskForm.value.inspectionUsers && Array.isArray(taskForm.value.inspectionUsers)) { if (taskForm.value.inspectionUsers && Array.isArray(taskForm.value.inspectionUsers)) {
taskForm.value.taskUserIds = taskForm.value.inspectionUsers.map((user) => user.userId); taskForm.value.taskUserIds = taskForm.value.inspectionUsers.map((user) => user.userId);
@ -394,8 +412,12 @@ const handleViewResult = async (row) => {
}; };
// //
const handleRemoveForm = (index) => { const handleRemoveForm = async (index) => {
illegalForms.value.splice(index, 1); if (illegalForms.value[index].id) {
await deleteInspectionResult(illegalForms.value[index].id);
} else {
illegalForms.value.splice(index, 1);
}
}; };
const handleSubmit = async () => { const handleSubmit = async () => {
@ -420,8 +442,30 @@ const handleSubmit = async () => {
visible.value = false; visible.value = false;
await getData(); await getData();
} else if (dialogTitle.value === '结果登记') { } else if (dialogTitle.value === '结果登记') {
response = await createInspectionResult(illegalForm.value); // 1. id img
const payload = illegalForms.value
.filter((item) => !item.id)
.map((item) => {
//
const firstImage = Array.isArray(item.illegalImages) && item.illegalImages.length ? item.illegalImages[0] : '';
return {
...item,
img: firstImage,
};
});
// 2.
if (payload.length === 0) {
ElMessage.warning('没有需要登记的新违法记录');
return;
}
// 3.
response = await createInspectionResultBatch(payload);
ElMessage.success(response?.msg || '结果登记成功'); ElMessage.success(response?.msg || '结果登记成功');
// 4.
await getData(); await getData();
} }
// //
@ -467,7 +511,13 @@ function handleSizeChange(val) {
// //
// --------------------------------------------------------------------- // ---------------------------------------------------------------------
// user.admintrueoperatorinspector
const role = ref('operator'); const role = ref('operator');
if (user.admin) {
role.value = 'operator';
} else {
role.value = 'inspector';
}
// //
const allActions = [ const allActions = [
{ name: '查看', icon: 'view', key: 'view', event: ({ row }) => handleView(row.id) }, { name: '查看', icon: 'view', key: 'view', event: ({ row }) => handleView(row.id) },
@ -482,7 +532,7 @@ const allActions = [
// -> // ->
const permissionMap = { const permissionMap = {
admin: ['operator', 'inspector'], // operator inspector admin: ['operator', 'inspector'], // operator inspector
operator: ['view', 'edit', 'delete', 'publish', 'back', 'rePublish', 'result', 'viewResult'], operator: ['view', 'edit', 'delete', 'publish', 'back', 'rePublish', 'viewResult'],
inspector: ['result', 'viewResult'], inspector: ['result', 'viewResult'],
}; };
// -> // ->
@ -492,8 +542,36 @@ const statusMap = {
'01': ['viewResult'], '01': ['viewResult'],
'02': ['view', 'edit', 'delete', 'rePublish'], '02': ['view', 'edit', 'delete', 'rePublish'],
}; };
// 使 Hook function getActions(row) {
// const { actions } = useActionPermissions(role, status, allActions, permissionMap, statusMap); // 1. action.key
let raw = permissionMap[role.value] || [];
// 2. raw permissionMap key
const expanded = raw.reduce((acc, key) => {
if (permissionMap[key]) {
// key action.key
acc.push(...permissionMap[key]);
} else {
// key action.key
acc.push(key);
}
return acc;
}, []);
//
const roleAllowed = Array.from(new Set(expanded));
// 3. action.key
// row.inspectionStatus row.status
const statusKey = row.inspectionStatus ?? row.status;
const statusAllowed = statusMap[statusKey] || [];
// 4. key
const finalKeys = roleAllowed.filter((key) => statusAllowed.includes(key));
// 5. finalKeys allActions
return allActions.filter((a) => finalKeys.includes(a.key));
}
</script> </script>
<style scoped lang="scss"> <style scoped lang="scss">