合并 #2
@ -16,5 +16,5 @@ VITE_APP_UPLOAD_API = '/uploadApis'
|
||||
# VITE_APP_BASE_URL = 'http://47.109.205.240:8080'
|
||||
# VITE_APP_UPLOAD_URL = 'http://47.109.205.240:9300'
|
||||
# 内网接口地址
|
||||
VITE_APP_BASE_URL = 'http://192.168.18.74:8080'
|
||||
VITE_APP_UPLOAD_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.99:8080'
|
||||
|
@ -13,5 +13,5 @@ VITE_APP_UPLOAD_API = '/uploadApis'
|
||||
# VITE_APP_UPLOAD_URL = 'http://47.109.205.240:9300'
|
||||
|
||||
# 内网接口地址
|
||||
VITE_APP_BASE_URL = 'http://192.168.18.74:8080'
|
||||
VITE_APP_UPLOAD_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.99:8080'
|
||||
|
@ -66,6 +66,13 @@ export function createInspectionResult(data) {
|
||||
data,
|
||||
});
|
||||
}
|
||||
// 巡查结果-批量新增(POST)
|
||||
export function createInspectionResultBatch(data) {
|
||||
return request('/land-resource/inspection/result/saveBatch', {
|
||||
method: 'POST',
|
||||
data,
|
||||
});
|
||||
}
|
||||
// 巡查结果-删除(DELETE)
|
||||
export function deleteInspectionResult(id) {
|
||||
return request(`/land-resource/inspection/result/${id}`, {
|
||||
|
@ -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>
|
@ -2,7 +2,7 @@ import Layout from '@/layouts/index.vue';
|
||||
// import annualplanRouters from './annualplan';
|
||||
import statisticsRoutes from './statisticAnalysis';
|
||||
import landsRoutes from './lands';
|
||||
import dictRoutes from './dict';
|
||||
// import dictRoutes from './dict';
|
||||
|
||||
export default [
|
||||
{
|
||||
@ -48,7 +48,7 @@ export default [
|
||||
// ...annualplanRouters,
|
||||
...landsRoutes,
|
||||
// ...statisticsRoutes,
|
||||
...dictRoutes,
|
||||
// ...dictRoutes,
|
||||
],
|
||||
},
|
||||
];
|
||||
|
@ -15,7 +15,7 @@
|
||||
<el-button type="success" icon="download" @click="handleExport">导出</el-button>
|
||||
</template>
|
||||
<template #menu="scope">
|
||||
<custom-table-operate :actions="crudOptions.actions" :data="scope" />
|
||||
<custom-table-operate :actions="getActions(scope.row)" :data="scope" />
|
||||
</template>
|
||||
</avue-crud>
|
||||
|
||||
@ -71,7 +71,7 @@
|
||||
<div v-for="(form, index) in illegalForms" :key="index" class="form-container">
|
||||
<div class="form-header">
|
||||
<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>
|
||||
|
||||
<el-form :model="form" :disabled="isReadonlyRegist" label-width="100px" class="form-item">
|
||||
@ -90,29 +90,27 @@
|
||||
</el-form-item>
|
||||
<el-form-item label="是否违法" prop="illegalFlag">
|
||||
<el-radio-group v-model="form.illegalFlag">
|
||||
<el-radio :label="1">是</el-radio>
|
||||
<el-radio :label="0">否</el-radio>
|
||||
<el-radio value="1">是</el-radio>
|
||||
<el-radio value="0">否</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
<!-- 违法时间 -->
|
||||
<el-form-item label="违法时间" prop="illegalDate">
|
||||
<el-date-picker v-model="form.illegalDate" type="datetime" placeholder="选择违法时间" />
|
||||
<el-form-item v-if="form.illegalFlag === '1'" label="违法时间" prop="illegalDate">
|
||||
<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 label="违法图片" prop="illegalImages">
|
||||
<el-upload
|
||||
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 v-if="form.illegalFlag === '1'" label="违法图片" prop="illegalImages">
|
||||
<file-uploader v-model="form.illegalImages" :limit="1" :readonly="isReadonlyRegist || form.illegalFlag === 0" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-col v-if="form.illegalFlag === '1'" :span="12">
|
||||
<el-form-item label="违法类型" prop="illegalType">
|
||||
<url-select
|
||||
v-model="form.illegalTypeCode"
|
||||
@ -121,10 +119,17 @@
|
||||
label-key="dictLabel"
|
||||
value-key="dictValue"
|
||||
:response-parser="(res) => res.data"
|
||||
:disabled="isReadonlyRegist || form.illegalFlag === 0"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="违法行为描述" prop="desc">
|
||||
<el-input v-model="form.desc" :autosize="{ minRows: 2, maxRows: 6 }" type="textarea" placeholder="请输入违法行为描述" />
|
||||
<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="请输入违法行为描述"
|
||||
:disabled="isReadonlyRegist || form.illegalFlag === 0"
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
@ -150,6 +155,7 @@ import { ref, reactive, watch, onMounted, computed, nextTick } from 'vue';
|
||||
import { CRUD_OPTIONS } from '@/config';
|
||||
import { ElMessage } from 'element-plus';
|
||||
import { useActionPermissions } from '@/hooks/useActionPermissions';
|
||||
import { useUserStore } from '@/store/modules/user';
|
||||
import {
|
||||
createLandInspection,
|
||||
deleteLandInspection,
|
||||
@ -159,6 +165,7 @@ import {
|
||||
fetchLandInspectionList,
|
||||
exportLandInspection,
|
||||
createInspectionResult,
|
||||
createInspectionResultBatch,
|
||||
deleteInspectionResult,
|
||||
getInspectionResultDetail,
|
||||
} from '@/apis/landResourceManagement/landInspection/index';
|
||||
@ -167,6 +174,9 @@ const dialogTitle = ref('新增');
|
||||
const visible = ref(false);
|
||||
const isReadonlyInfo = ref(false);
|
||||
const isReadonlyRegist = ref(false);
|
||||
const UserStore = useUserStore();
|
||||
const user = UserStore.getUserInfo();
|
||||
console.log('admin 属性:', user.admin);
|
||||
|
||||
const pageData = ref({
|
||||
currentPage: 1,
|
||||
@ -205,7 +215,7 @@ const illegalForm = ref({
|
||||
illegalTypeCode: '', // 违法类型代码
|
||||
illegalTypeName: '', // 违法类型名称
|
||||
desc: '', // 违法描述
|
||||
img: '111', // 违法图片
|
||||
img: '', // 违法图片
|
||||
status: '', // 状态
|
||||
});
|
||||
const illegalForms = ref([{ ...illegalForm.value }]);
|
||||
@ -224,7 +234,7 @@ const crudOptions = reactive({
|
||||
{ label: '巡查对象', prop: 'inspectionTarget' },
|
||||
{ label: '注意事项', prop: 'notes' },
|
||||
{ label: '是否违法', prop: 'isIllegal' },
|
||||
{ label: '状态', prop: 'inspectionStatus' },
|
||||
{ label: '状态', prop: 'inspectionStatusName' },
|
||||
],
|
||||
actions: [
|
||||
{
|
||||
@ -322,9 +332,17 @@ const handleView = async (id) => {
|
||||
const response = await getLandInspectionDetail(id);
|
||||
taskForm.value = response.data;
|
||||
const arr = response.data.inspectionResults;
|
||||
if (arr && Array.isArray(arr)) {
|
||||
illegalForms.value = arr;
|
||||
illegalForms.value = arr ? arr : [];
|
||||
illegalForms.value.forEach((item) => {
|
||||
// 如果后端只给了一个 img 字符串
|
||||
if (item.img) {
|
||||
// 直接包成数组
|
||||
item.illegalImages = [item.img];
|
||||
} else {
|
||||
// 没图时给空数组
|
||||
item.illegalImages = [];
|
||||
}
|
||||
});
|
||||
isReadonlyInfo.value = true;
|
||||
if (taskForm.value.inspectionUsers && Array.isArray(taskForm.value.inspectionUsers)) {
|
||||
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) => {
|
||||
if (illegalForms.value[index].id) {
|
||||
await deleteInspectionResult(illegalForms.value[index].id);
|
||||
} else {
|
||||
illegalForms.value.splice(index, 1);
|
||||
}
|
||||
};
|
||||
|
||||
const handleSubmit = async () => {
|
||||
@ -420,8 +442,30 @@ const handleSubmit = async () => {
|
||||
visible.value = false;
|
||||
await getData();
|
||||
} 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 || '结果登记成功');
|
||||
|
||||
// 4. 完成后重新拉列表、关闭弹窗
|
||||
await getData();
|
||||
}
|
||||
// 可刷新表格数据
|
||||
@ -467,7 +511,13 @@ function handleSizeChange(val) {
|
||||
// 页面权限控制相关
|
||||
// ---------------------------------------------------------------------
|
||||
|
||||
// 如果user.admin是true就是operator,否则是inspector
|
||||
const role = ref('operator');
|
||||
if (user.admin) {
|
||||
role.value = 'operator';
|
||||
} else {
|
||||
role.value = 'inspector';
|
||||
}
|
||||
// 所有操作项
|
||||
const allActions = [
|
||||
{ name: '查看', icon: 'view', key: 'view', event: ({ row }) => handleView(row.id) },
|
||||
@ -482,7 +532,7 @@ const allActions = [
|
||||
// 权限表(角色 -> 可操作项)
|
||||
const permissionMap = {
|
||||
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'],
|
||||
};
|
||||
// 状态控制表(状态码 -> 可操作项)
|
||||
@ -492,8 +542,36 @@ const statusMap = {
|
||||
'01': ['viewResult'],
|
||||
'02': ['view', 'edit', 'delete', 'rePublish'],
|
||||
};
|
||||
// 使用封装 Hook
|
||||
// const { actions } = useActionPermissions(role, status, allActions, permissionMap, statusMap);
|
||||
function getActions(row) {
|
||||
// 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>
|
||||
|
||||
<style scoped lang="scss">
|
||||
|
Loading…
x
Reference in New Issue
Block a user