合并 #2

Merged
shenhong merged 4 commits from fea into dev 2025-06-12 17:27:00 +08:00
23 changed files with 2364 additions and 1866 deletions
Showing only changes of commit 26e4c8c528 - Show all commits

View File

@ -59,7 +59,7 @@ export function fetchFarmerById(id) {
} }
/** /**
* 删除农户接口严格匹配文档规范 * 农户-删除
* @param {string|string[]} ids - 单个ID或ID数组会自动转为逗号分隔字符串 * @param {string|string[]} ids - 单个ID或ID数组会自动转为逗号分隔字符串
* @returns {Promise} 请求Promise * @returns {Promise} 请求Promise
*/ */
@ -75,29 +75,10 @@ export function deleteFarmers(ids) {
} }
/** /**
* 生产经营主体 - 审核 * 企业管理 - 列表查询
* @param {Object} data 审核数据
*/
export function checkBusinessSubject(data) {
return request({
url: '/product-business/business/businessCheck',
method: 'put',
data,
});
}
/**
* 经营主体审核 - 分页查询
* @param {Object} params 查询参数 * @param {Object} params 查询参数
* @returns {Promise} 请求Promise
*/ */
export function fetchBusinessCheckList(params) {
return request({
url: '/product-business/business/businessCheckPage',
method: 'get',
params,
});
}
// 农企合作社-列表查询/product-business/business/enter/businessPage
export function getEnterList(params) { export function getEnterList(params) {
return request({ return request({
url: '/product-business/business/enter/businessPage', url: '/product-business/business/enter/businessPage',
@ -105,3 +86,115 @@ export function getEnterList(params) {
params, params,
}); });
} }
/**
* 企业管理 - 详情查询
* @param {string} id 企业I
* @returns {Promise} 请求Promise
*/
export function getEnterById(id) {
return request({
url: `/product-business/business/enter/businessInfo/${id}`,
method: 'get',
});
}
/**
* 企业管理 - 新增
* @param {Object} data 企业数据
* @returns {Promise} 请求Promise
*/
export function addEnter(data) {
return request({
url: '/product-business/business/enter/businessSave',
method: 'post',
data,
});
}
/**
* 企业管理 - 编辑
* @param {Object} data 企业数据
* @returns {Promise} 请求Promise
*/
export function updateEnter(data) {
return request({
url: '/product-business/business/enter/businessEdit',
method: 'put',
data,
});
}
/**
* 企业管理 - 审核
* @param {Object} data 审核数据
*/
export function approvalEnter(data) {
return request({
url: '/product-business/business/enter/businessApproval',
method: 'put',
data,
});
}
/**
* 企业管理 - 删除
* @param {string|string[]} ids - 单个ID或ID数组会自动转为逗号分隔字符串
* @returns {Promise} 请求Promise
*/
export function deleteEnter(ids) {
// 统一参数格式:数组转逗号分隔字符串,非数组直接使用
const idStr = Array.isArray(ids) ? ids.join(',') : ids;
return request({
url: '/product-business/business/enter/deleteBusiness',
method: 'delete',
params: { businessId: idStr },
});
}
/**
* 社员列表查询
* @param {Object} params 查询参数
*/
export function getMemberList(params) {
return request({
url: '/product-business/business/member/memberPage',
method: 'get',
params,
});
}
/**
* 社员新增
* @param {Object} data 社员数据
*/
export function addMember(data) {
return request({
url: '/product-business/business/member/businessSave',
method: 'post',
data,
});
}
/**
* 社员编辑
* @param {Object} data 社员数据
*/
export function updateMember(data) {
return request({
url: '/product-business/business/member/memberEdit',
method: 'put',
data,
});
}
/**
* 社员删除
* @param {string|string[]} ids - 单个ID或ID数组会自动转为逗号分隔字符串
* @returns {Promise} 请求Promise
*/
export function deleteMembers(ids) {
// 统一参数格式:数组转逗号分隔字符串,非数组直接使用
const idStr = Array.isArray(ids) ? ids.join(',') : ids;
return request({
url: '/product-business/business/member/deleteMember',
method: 'delete',
params: { ids: idStr },
});
}

View File

@ -0,0 +1,29 @@
import request from '@/utils/axios';
/* 查询土地违法处理 */
export function getLandIllegal(params = {}) {
return request('land-resource/landViolation/page', {
method: 'GET',
params,
});
}
/* 新增土地违法处理 */
export function createLandIllegal(data = {}) {
return request('land-resource/landViolation/save', {
method: 'POST',
data,
});
}
/* 登记处理 */
export function registerLandIllegal(data = {}) {
return request('land-resource/landViolation/registResult', {
method: 'PUT',
data,
});
}
/* 违法详情 */
export function illegalInfo(id = '') {
return request('land-resource/landViolation/detail/' + id, {
method: 'GET',
});
}

View File

@ -0,0 +1,80 @@
// api/landInspection.js
import request from '@/utils/axios';
// 新增POST
export function createLandInspection(data) {
return request('land-resource/landInspection/save', {
method: 'POST',
data,
});
}
// 删除DELETE
export function deleteLandInspection(id) {
return request(`land-resource/landInspection/${id}`, {
method: 'DELETE',
});
}
// 修改PUT
export function updateLandInspection(data = {}) {
return request('/land-resource/landInspection/update', {
method: 'PUT',
data,
});
}
// 修改状态PUT
export function updateLandInspectionStatus(data = {}) {
return request('/land-resource/landInspection/updateStatus', {
method: 'PUT',
data,
});
}
// 查询详情GET
export function getLandInspectionDetail(id) {
return request(`land-resource/landInspection/${id}`, {
method: 'GET',
});
}
// 查询列表 admin GET
export function fetchLandInspectionList(params = {}) {
return request('land-resource/landInspection/page', {
method: 'GET',
params,
});
}
// 查询列表 执行人员 GET
export function fetchLandInspectionGen(params = {}) {
return request('/land-resource/landInspection/page/general', {
method: 'GET',
params,
});
}
// 导出GET + Blob
export function exportLandInspection(params = {}) {
return request('/land-resource/landInspection/export', {
method: 'GET',
params,
responseType: 'blob',
});
}
// 巡查结果-新增POST
export function createInspectionResult(data) {
return request('/land-resource/inspection/result/save', {
method: 'POST',
data,
});
}
// 巡查结果-删除DELETE
export function deleteInspectionResult(id) {
return request(`/land-resource/inspection/result/${id}`, {
method: 'DELETE',
});
}
// 巡查结果-违法事件查看GET
export function getInspectionResultDetail(id) {
return request(`/land-resource/inspection/result/${id}`, {
method: 'GET',
});
}

View File

@ -65,18 +65,19 @@ const fetchAreaData = async () => {
}, },
}); });
areaOptions.value = res.data ?? []; areaOptions.value = res.data ?? [];
console.log('AreaSelect区域数据', areaOptions.value);
} catch (err) { } catch (err) {
console.error('加载行政区域失败', err); console.error('加载行政区域失败', err);
} }
}; };
// => // // =>
watch( // watch(
() => props.modelValue, // () => props.modelValue,
(val) => { // (val) => {
selectedAreaPath.value = [...val]; // selectedAreaPath.value = [...val];
} // }
); // );
// => // =>
watch(selectedAreaPath, (val) => { watch(selectedAreaPath, (val) => {

View File

@ -54,6 +54,10 @@ const props = defineProps({
type: String, type: String,
default: 'value', default: 'value',
}, },
responseParser: {
type: Function,
default: (res) => res.data.records, //
},
}); });
// -------------- Events -------------- // -------------- Events --------------
@ -83,13 +87,13 @@ async function fetchOptions() {
if (!props.url) return; if (!props.url) return;
const res = await request.get(props.url, { params: props.params }); const res = await request.get(props.url, { params: props.params });
const records = res.data.records; const records = props.responseParser(res);
if (Array.isArray(records)) { if (Array.isArray(records)) {
options.value = records; options.value = records;
// console.log('option', options.value); // console.log('option', options.value);
} else { } else {
options.value = []; options.value = [];
console.log('UrlSelect接口返回数据格式不是数组无法解析成 options'); console.error('UrlSelect解析后的数据不是数组');
} }
} }

View File

@ -0,0 +1,35 @@
// src/hooks/useActionPermissions.js
import { computed } from 'vue';
function getBaseRoles(role, permissionMap) {
// 允许角色继承(如 admin 自动继承其他角色权限)
const inherited = permissionMap[role];
return inherited && Array.isArray(inherited) ? inherited : [role];
}
function getAllowedKeys(role, status, permissionMap, statusMap) {
const baseRoles = getBaseRoles(role, permissionMap);
const roleKeys = new Set(baseRoles.flatMap((r) => permissionMap[r] || []));
const statusKeys = new Set(statusMap[status] || []);
return [...roleKeys].filter((key) => statusKeys.has(key));
}
/**
* 通用权限控制 Hook
* @param {Ref<String>} roleRef 用户角色 ref
* @param {Ref<String>} statusRef 当前状态 ref
* @param {Array} actions 操作项列表必须含 key 字段
* @param {Object} permissionMap 角色权限表{ operator: ['edit', ...] }
* @param {Object} statusMap 状态权限表{ '00': ['edit', ...] }
*/
export function useActionPermissions(roleRef, statusRef, actions, permissionMap, statusMap) {
const filteredActions = computed(() => {
const allowedKeys = getAllowedKeys(roleRef.value, statusRef.value, permissionMap, statusMap);
return actions.filter((action) => allowedKeys.includes(action.key));
});
return {
actions: filteredActions,
};
}

View File

@ -1,26 +1,26 @@
import Views from '@/layouts/Views.vue'; // import Views from '@/layouts/Views.vue';
const annualplanRoutes = [ // const annualplanRoutes = [
{ // {
path: '/sub-government-affairs-service/annualPlan', // path: '/sub-government-affairs-service/annualPlan',
name: 'annualPlan', // name: 'annualPlan',
component: Views, // component: Views,
redirect: '/sub-government-affairs-service/annualPlans', // redirect: '/sub-government-affairs-service/annualPlans',
meta: { title: '种植进度网格化管理', icon: '' }, // meta: { title: '种植进度网格化管理', icon: '' },
children: [ // children: [
// { // {
// path: '/sub-government-affairs-service/annualPlans', // path: '/sub-government-affairs-service/annualPlans',
// name: 'annualPlans', // name: 'annualPlans',
// component: () => import('@/views/annualPlan/component/annualPlans/index.vue'), // component: () => import('@/views/annualPlan/component/annualPlans/index.vue'),
// meta: { title: '年度种植计划', icon: '' }, // meta: { title: '年度种植计划', icon: '' },
// }, // },
{ // {
path: '/sub-government-affairs-service/annualPlans', // path: '/sub-government-affairs-service/annualPlans',
name: 'annualPlans', // name: 'annualPlans',
component: () => import('@/views/annualPlan/component/annualPlans/index.vue'), // component: () => import('@/views/annualPlan/component/annualPlans/index.vue'),
meta: { title: '种植进度网格化管理', icon: 'Memo' }, // meta: { title: '种植进度网格化管理', icon: 'Memo' },
}, // },
], // ],
}, // },
]; // ];
export default annualplanRoutes; // export default annualplanRoutes;

View File

@ -1,5 +1,5 @@
import Layout from '@/layouts/index.vue'; 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';
@ -29,13 +29,13 @@ export default [
path: '/sub-government-affairs-service/add-grid', path: '/sub-government-affairs-service/add-grid',
component: () => import('@/views/resource/grid/AddGrid.vue'), component: () => import('@/views/resource/grid/AddGrid.vue'),
name: 'add', name: 'add',
meta: { title: '新增网格', icon: '' }, meta: { title: '网格管理', icon: '' },
}, },
{ {
path: '/sub-government-affairs-service/add--grid-member', path: '/sub-government-affairs-service/add--grid-member',
component: () => import('@/views/resource/grid/GridMember.vue'), component: () => import('@/views/resource/grid/GridMember.vue'),
name: 'member', name: 'member',
meta: { title: '新增网格员', icon: '' }, meta: { title: '网格员管理', icon: '' },
}, },
// { // {
// path: '/sub-government-affairs-service/grid--management', // path: '/sub-government-affairs-service/grid--management',

View File

@ -1,659 +0,0 @@
<template>
<div class="custom-page">
<avue-crud
ref="crudRef"
v-model="state.form"
v-model:page="state.pageData"
:table-loading="state.loading"
:data="state.data"
:option="state.options"
@refresh-change="refreshChange"
@selection-change="selectionChange"
@current-change="currentChange"
@size-change="sizeChange"
>
<template #menu-left>
<el-button type="primary" icon="Plus" @click="onAdd">新增</el-button>
<el-button type="success" icon="download" @click="onExport">导出</el-button>
</template>
<template #menu="{ row }">
<custom-table-operate :actions="state.options.actions" :data="{ row }" />
</template>
<template #search>
<div class="custom-search">
<div class="search-fields">
<div class="search-item">
<AreaCascader
v-model:region-code="areaQuery.regionCode"
v-model:grid-id="areaQuery.gridId"
placeholder="选择行政区域与网格"
:show-separator="true"
:width="500"
/>
</div>
<div class="search-item">
<span>种植作物</span>
<el-select v-model="state.query.cropsId" placeholder="种植作物" :clearable="true">
<el-option v-for="item in cropsOptions" :key="item.id" :label="item.cropsName" :value="item.id" />
</el-select>
</div>
<div class="search-item">
<span>计划编号</span>
<el-input v-model="state.query.id" placeholder="计划编号" :clearable="true" />
</div>
<div class="search-item">
<span>计划名称</span>
<el-input v-model="state.query.planName" placeholder="计划名称" :clearable="true" />
</div>
</div>
<div class="search-buttons">
<el-button type="primary" @click="searchChange"> 查询 </el-button>
<el-button @click="resetSearch"> 重置 </el-button>
</div>
</div>
</template>
</avue-crud>
<el-dialog v-model="detailDialogVisible" title="年度种植计划详情页" width="800" class="detail-dialog">
<el-tabs v-model="activeTab">
<el-tab-pane label="年度种植计划" name="basic">
<h3>{{ currentDetailRow.planName }}</h3>
<div>所属行政区域{{ currentDetailRow.regionName }}</div>
<div>所属网格{{ currentDetailRow.gridName }}</div>
<div>计划编号{{ currentDetailRow.id }}</div>
<div>计划名称{{ currentDetailRow.planName }}</div>
<div>种植作物{{ currentDetailRow.cropsName }}</div>
<div>种植面积{{ currentDetailRow.planParameters?.plantingArea }}</div>
<div>种植月份{{ currentDetailRow.planParameters?.plantingMonths }}</div>
<div>
生长周期{{ currentDetailRow.planParameters?.growthCycle }}
{{ getGrowthCycleUnitName(currentDetailRow.planParameters?.growthCycleUnit) }}
</div>
</el-tab-pane>
<el-tab-pane label="实际种植情况" name="planting">
<h3>{{ currentDetailRow.planName }}</h3>
<div>所属行政区域{{ currentDetailRow.regionName }}</div>
<div>所属网格{{ currentDetailRow.gridName }}</div>
<div>计划编号{{ currentDetailRow.id }}</div>
<div>计划名称{{ currentDetailRow.planName }}</div>
<div>种植作物{{ currentDetailRow.cropsName }}</div>
<div>种植面积{{ currentDetailRow.actualParameters?.plantingArea }}</div>
<div>种植月份{{ currentDetailRow.actualParameters?.plantingMonths }}</div>
<div>
生长周期{{ currentDetailRow.actualParameters?.growthCycle }}
{{ getGrowthCycleUnitName(currentDetailRow.actualParameters?.growthCycleUnit) }}
</div>
<div>当前进度{{ currentDetailRow.currentProgress }}%</div>
</el-tab-pane>
</el-tabs>
<template #footer>
<span class="dialog-footer">
<el-button @click="detailDialogVisible = false">关闭</el-button>
</span>
</template>
</el-dialog>
<!-- 新增重新制定计划和填写实际种植信息操作的共用弹窗 -->
<el-dialog v-model="commonDialogVisible" :title="dialogTitle">
<template #default>
<el-form ref="planForm" :model="formData" :rules="formRules" label-width="120px" class="common-dialog">
<el-form-item label="" label-width="0px">
<AreaCascader v-model:value="areaFormData" split-rows label="所属行政区域-网格" :width="500" />
</el-form-item>
<!-- <AreaCascader v-model:value="areaFormData" split-rows label="所属行政区域-网格" :width="500" /> -->
<el-form-item label="计划名称">
<el-input v-model="formData.planName" style="width: 380px" />
</el-form-item>
<el-form-item label="种植作物" prop="cropsName">
<el-select v-model="formData.cropsId" placeholder="种植作物" style="width: 380px" :clearable="true">
<el-option v-for="item in cropsOptions" :key="item.id" :label="item.cropsName" :value="item.id" />
</el-select>
</el-form-item>
<el-form-item label="种植面积" prop="plantingArea">
<el-input v-model="formData.plantingArea" style="width: 380px" />
</el-form-item>
<el-form-item label="种植月份" prop="plantingMonths">
<el-select v-model="formData.plantingMonths" placeholder="请选择月份" style="width: 380px" :clearable="true">
<el-option v-for="item in monthsOptions" :key="item.value" :label="item.label" :value="item.value" />
</el-select>
</el-form-item>
<el-form-item label="生长周期" prop="growthCycle">
<el-input-number v-model="formData.growthCycle" :min="1" style="width: 300px" />
<el-select v-model="formData.growthCycleUnit" disabled style="width: 68px; margin: 0; padding: 0">
<el-option label="天" value="1" />
<el-option label="周" value="2" />
<el-option label="月" value="3" />
<el-option label="年" value="4" />
</el-select>
</el-form-item>
</el-form>
</template>
<template #footer>
<span class="dialog-footer">
<el-button @click="commonDialogVisible = false">取消</el-button>
<el-button type="primary" @click="submitForm">确定</el-button>
</span>
</template>
</el-dialog>
</div>
</template>
<script setup>
import { reactive, ref, computed, onMounted, watch } from 'vue';
import { useApp } from '@/hooks';
import { CRUD_OPTIONS } from '@/config';
import { isEmpty, downloadFile } from '@/utils';
import { useUserStore } from '@/store/modules/user';
import { getAnnualList, examineAnnual, delAnnual, exportAnnua } from '@/apis/land.js';
import { pageCropsList } from '@/apis/landResourceManagement/cropsManagement/index.js';
import { saveAnnual, editAnnual, saveActualProgress, getAnnualDetail } from '@/apis/landResourceManagement/plantingPlan/index.js';
const app = useApp();
const crudRef = ref(null);
const userStore = useUserStore();
// AreaCascader
const areaFormData = ref({
regionCode: '',
gridName: '',
gridId: '',
});
watch(
areaFormData,
(newVal) => {
formData.value.regionCode = newVal.regionCode;
formData.value.gridName = newVal.gridName;
formData.value.gridId = newVal.gridId;
},
{ deep: true }
);
const formRules = reactive({
// planName: [{ required: true, message: '', trigger: 'blur' }],
// cropsId: [{ required: true, message: '', trigger: 'change' }],
// plantingArea: [
// { required: true, message: '', trigger: 'blur' },
// { type: 'number', message: '', trigger: 'blur' },
// ],
// plantingMonths: [{ required: true, message: '', trigger: 'change' }],
// growthCycle: [
// { required: true, message: '', trigger: 'blur' },
// { type: 'number', message: '', trigger: 'blur' },
// ],
});
//
const cropsOptions = ref([]);
//
const fetchCropsList = async () => {
try {
// pageCropsList
const res = await pageCropsList({ status: '0' });
if (res.code === 200) {
console.log('res :>> ', res.data.records);
cropsOptions.value = res.data.records;
console.log('object :>> ', cropsOptions.value);
}
} catch (error) {
app.$message.error('获取种植作物列表失败');
}
};
onMounted(() => {
fetchCropsList();
});
//
const getGrowthCycleUnitName = (unit) => {
const unitMap = {
1: '天',
2: '周',
3: '月',
4: '年',
};
return unitMap[unit] || '';
};
//
const fetchDetailData = async (id) => {
try {
const res = await getAnnualDetail(id);
if (res.code === 200) {
currentDetailRow.value = res.data;
} else {
app.$message.error(res.msg || '获取详情数据失败');
}
} catch (error) {
console.error('获取详情数据出错:', error);
app.$message.error('获取详情数据失败,请稍后重试');
}
};
const openDetailDialog = async (row) => {
detailDialogVisible.value = true;
await fetchDetailData(row.id);
};
//
const detailDialogVisible = ref(false);
//
const activeTab = ref('basic');
const currentDetailRow = ref({});
//
const commonDialogVisible = ref(false);
//
const currentAction = ref('');
//
const dialogTitle = computed(() => {
if (currentAction.value === 'reCreate') {
return '重新制定计划';
} else if (currentAction.value === 'fillActual') {
return '填写实际种植信息';
} else if (currentAction.value === 'add') {
return '新增年度种植计划';
}
return '';
});
const monthsOptions = ref([
{ value: 1, label: '1月' },
{ value: 2, label: '2月' },
{ value: 3, label: '3月' },
{ value: 4, label: '4月' },
{ value: 5, label: '5月' },
{ value: 6, label: '6月' },
{ value: 7, label: '7月' },
{ value: 8, label: '8月' },
{ value: 9, label: '9月' },
{ value: 10, label: '10月' },
{ value: 11, label: '11月' },
{ value: 12, label: '12月' },
]);
//
const planForm = ref(null);
//
const isGridMember = computed(() => {
const userRoles = userStore.getUserInfo().roles;
console.log('当前用户角色:', userRoles);
return userRoles.some((role) => role.roleKey === 'gridMember');
// return true;
});
// 使 ref 使 v-model:value
const areaQuery = ref({
regionCode: '',
gridName: '',
gridId: '',
});
const state = reactive({
loading: false,
query: {
current: 1,
size: 10,
id: '',
planName: '',
cropsName: '',
cropsId: '',
},
form: {},
selection: [],
options: {
...CRUD_OPTIONS,
addBtnText: '',
addBtn: false,
searchBtn: false,
emptyBtn: false,
fit: true,
column: [
{ label: '计划编号', prop: 'id', minWidth: 100 },
{ label: '计划名称', prop: 'planName' },
{ label: '种植作物', prop: 'cropsName' },
{ label: '种植面积', prop: 'plantingArea', formatter: (row, column, cellValue) => `${cellValue}` },
{ label: '种植月份', prop: 'plantingMonths', formatter: (row, column, cellValue) => `${cellValue}` },
{
label: '生长周期',
prop: 'growthCycle',
formatter: (row, column, cellValue) => {
const unitMap = { 1: '天', 2: '周', 3: '月', 4: '年' };
const unit = unitMap[row.growthCycleUnit] || '';
return `${cellValue} ${unit}`;
},
},
{ label: '所属行政区域', prop: 'regionName' },
{ label: '所属网格', prop: 'gridName' },
{ label: '当前进度', prop: 'currentProgress' },
],
actions: [
{
name: '查看',
icon: 'view',
event: ({ row }) => {
openDetailDialog(row);
},
},
{
name: '重新制定计划',
icon: 'edit',
event: ({ row }) => {
currentAction.value = 'reCreate';
formData.value = { ...row };
if (isGridMember.value) {
formData.value.regionName = row.regionName;
formData.value.gridName = row.gridName;
}
formData.value.growthCycleUnit = row.growthCycleUnit || '1';
commonDialogVisible.value = true;
},
},
{
name: '填写实际种植信息',
icon: 'edit',
event: ({ row }) => {
currentAction.value = 'fillActual';
formData.value = { ...row };
if (isGridMember.value) {
formData.value.regionName = row.regionName;
formData.value.gridName = row.gridName;
}
formData.value.growthCycleUnit = row.growthCycleUnit || '1';
commonDialogVisible.value = true;
},
},
{
type: 'danger',
name: '删除',
icon: 'delete',
event: ({ row }) => rowDel(row),
},
],
},
pageData: {
total: 0,
currentPage: 1,
pageSize: 10,
},
data: [],
currentRow: {},
});
const formData = ref({
year: '',
regionCode: '',
gridId: '',
regionName: '',
gridName: '',
planName: '', //
cropsId: null,
cropsName: '',
plantingArea: null,
plantingMonths: '',
growthCycle: '',
growthCycleUnit: '1', //
note: '',
});
//
const submitForm = async () => {
try {
//
await planForm.value.validate();
//
console.log('表单数据:', formData.value);
if (currentAction.value === 'reCreate') {
//
await editAnnual(formData.value);
app.$message.success('重新制定计划成功');
} else if (currentAction.value === 'fillActual') {
//
await saveActualProgress(formData.value);
app.$message.success('填写实际种植信息成功');
} else if (currentAction.value === 'add') {
//
await saveAnnual(formData.value);
app.$message.success('新增年度种植计划成功');
}
commonDialogVisible.value = false;
loadData();
} catch (error) {
console.error('表单提交失败:', error);
if (error.errors) {
//
app.$message.error('请填写完整且正确的表单信息');
} else {
// API
app.$message.error('操作失败,请稍后重试');
}
}
};
const onAdd = () => {
currentAction.value = 'add';
formData.value = {
regionName: '',
gridName: '',
planName: '',
cropsName: '',
plantingArea: '',
plantingMonths: '',
growthCycle: '',
growthCycleUnit: '1',
};
commonDialogVisible.value = true;
};
//
const loadData = () => {
state.loading = true;
getAnnualList(state.query)
.then((res) => {
if (res.code === 200) {
const { current, size, total, records } = res.data;
state.data = records;
state.pageData = {
currentPage: current || 1,
pageSize: size || 10,
total: total,
};
}
})
.catch((err) => {
app.$message.error(err.msg);
state.data = [];
})
.finally(() => {
state.loading = false;
});
};
loadData();
//
const currentChange = (current) => {
state.query.current = current;
loadData();
};
//
const sizeChange = (size) => {
state.query.size = size;
loadData();
};
//
const searchChange = () => {
state.query = {
...state.query,
...areaQuery.value,
current: 1,
};
console.log('搜索参数', state.query);
loadData();
};
//
const resetSearch = () => {
state.query = {
current: 1,
size: 10,
id: '',
planName: '',
cropsName: '',
cropsId: '',
};
areaQuery.value.regionCode = '';
areaQuery.value.gridName = '';
areaQuery.value.gridId = '';
loadData();
};
//
const refreshChange = () => {
loadData();
app.$message.success('刷新成功');
};
//
const selectionChange = (rows) => {
state.selection = rows;
};
//
const rowDel = (row, index, done) => {
if (isEmpty(row)) return;
app
.$confirm(`删除后信息将不可查看,确认要删除吗?`, '确定删除', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning',
})
.then(() => {
console.info('删除');
delAnnual({ id: row.id })
.then((res) => {
if (res.code === 200) {
app.$message.success('删除成功!');
// done();
loadData();
}
})
.catch((err) => {
app.$message.error(err.msg);
});
})
.catch(() => {});
};
//
const onExport = () => {
if (isEmpty(state.data)) {
app.$message.error('当前暂时没有可供导出的数据!');
return;
}
state.loading = true;
const fileName = '年度计划明细表';
exportAnnua(state.query)
.then((res) => {
if (res.status === 200) {
downloadFile(res.data, `${fileName}.xlsx`, 'blob');
app.$message.success('导出成功!');
}
})
.catch((err) => {
app.$message.error('导出失败!');
})
.finally(() => {
state.loading = false;
});
};
</script>
<style scoped lang="scss">
.custom-page {
/* 详情弹窗样式 */
/* 表单弹窗样式 */
.el-dialog {
.el-form {
padding: 0 20px;
width: 100%;
// background-color: aqua;
display: flex;
flex-wrap: wrap;
justify-content: center;
&-item {
margin-bottom: 18px;
width: 60%;
// background-color: #606266;
&__label {
font-weight: 500;
color: #606266;
}
/* 输入框和选择器统一宽度 */
.el-input,
.el-select,
.el-cascader {
width: 100%;
max-width: 400px;
}
/* 数字输入框和单位选择器组合 */
.el-input-number {
margin-right: 10px;
& + .el-select {
width: 100px;
}
}
}
}
}
/* 按钮样式微调 */
.el-button {
padding: 8px 16px;
border-radius: 4px;
& + .el-button {
margin-left: 12px;
}
}
/* 搜索区域样式 */
.custom-search {
display: flex;
flex-direction: column;
align-items: flex-start;
padding: 16px;
border-radius: 8px;
// background-color: #f5f7fa;
.search-fields {
display: flex;
flex-wrap: wrap;
gap: 16px;
width: 100%;
margin-bottom: 16px;
}
.search-item {
display: flex;
align-items: center;
gap: 8px;
.el-input,
.el-select,
.el-cascader {
width: 200px;
}
span {
font-size: 14px;
color: #606266;
align-self: center;
}
}
.search-buttons {
display: flex;
align-self: center;
gap: 12px;
margin-left: 8px;
}
}
}
</style>

View File

@ -1,37 +0,0 @@
<template>
<div class="grid-records"></div>
</template>
<script setup>
import { ref } from 'vue';
import { ElMessage } from 'element-plus';
const records = ref([
{
createTime: '2025-05-26 09:58:29',
createUser: '1',
updateTime: '2025-05-26T10:02:02.000+08:00',
updateUser: '1',
tenantId: 0,
id: '1926820200675004417', //
year: null,
regionCode: null, //
cropsId: null, // id
gridId: null, // id
planName: '大兴乡2025水稻种植计划', //
plantingArea: 120, //
plantingAreaActual: 335, //
plantingMonths: '1', //
growthCycle: '20', //
growthCycleUnit: '1', // 1 2 3 4
note: '暂无备注', //
deleteFlag: '0', // 0 1
cropsName: '', //
gridName: null, //
regionName: null, //
currentProgress: 279.17, //
actualFlag: '1', // 0: 1
},
]);
</script>
<style scoped></style>

View File

@ -1,166 +0,0 @@
<template>
<div class="custom-page">
<avue-crud
ref="crudRef"
v-model="state.form"
v-model:search="state.query"
v-model:page="state.pageData"
:table-loading="state.loading"
:data="state.data"
:option="state.options"
@refresh-change="refreshChange"
@search-reset="searchChange"
@search-change="searchChange"
@selection-change="selectionChange"
@current-change="currentChange"
@size-change="sizeChange"
@row-save="rowSave"
@row-update="rowUpdate"
@row-del="rowDel"
>
<template #menu-left>
<el-button type="success" icon="download" @click="onExport">导出</el-button>
</template>
<template #menu="scope">
<custom-table-operate :actions="state.options.actions" :data="scope" />
</template>
</avue-crud>
</div>
</template>
<script setup>
import { reactive, ref } from 'vue';
import { useApp } from '@/hooks';
import { CRUD_OPTIONS } from '@/config';
import { isEmpty, downloadFile } from '@/utils';
import { useUserStore } from '@/store/modules/user';
import { compact } from 'lodash';
import { GetEntityList, AddEntity, UpdateEntity, DeleteEntity, ExportEntity } from '@/apis/resource/grid';
const { VITE_APP_BASE_API } = import.meta.env;
const app = useApp();
const UserStore = useUserStore();
const crudRef = ref(null);
const handleLandChange = async (value, form, done) => {
if (!value) return; //
state.form.address = value.item?.address || '';
};
const JobTypeChange = async (value, form, done) => {
if (!value) return;
state.form.productName = value.item?.productName || '';
};
const state = reactive({
loading: false,
query: {
current: 1,
size: 10,
},
form: {},
selection: [],
options: {
...CRUD_OPTIONS,
addBtnText: '',
addBtn: false,
column: [
{ label: '网格名称', prop: 'gridManager' },
{ label: '网格管理员', prop: 'gridManager' },
{ label: '联系方式', prop: 'gridManager' },
{ label: '网格名称', prop: 'gridManager' },
{ label: '网格名称', prop: 'gridManager' },
{ label: '种植总面积(亩)', prop: 'gridManager' },
{ label: '已种植总面积(亩)', prop: 'gridManager' },
{ label: '进度(%)', prop: 'gridManager' },
],
actions: [],
},
pageData: {
total: 0,
currentPage: 1,
pageSize: 10,
},
data: [],
currentRow: {},
});
//
const loadData = () => {
// state.loading = true;
// GetEntityList(state.query)
// .then((res) => {
// if (res.code === 200) {
// const { current, size, total, records } = res.data;
// state.data = records;
// state.pageData = {
// currentPage: current || 1,
// pageSize: size || 10,
// total: total,
// };
// }
// })
// .catch((err) => {
// app.$message.error(err.msg);
// state.data = [];
// })
// .finally(() => {
// state.loading = false;
// });
};
loadData();
//
const currentChange = (current) => {
state.query.current = current;
loadData();
};
//
const sizeChange = (size) => {
state.query.size = size;
loadData();
};
//
const searchChange = (params, done) => {
if (done) done();
state.query = params;
state.query.current = 1;
loadData();
};
//
const refreshChange = () => {
loadData();
app.$message.success('刷新成功');
};
//
const selectionChange = (rows) => {
state.selection = rows;
};
//
const onExport = () => {
if (isEmpty(state.data)) {
app.$message.error('当前暂时没有可供导出的数据!');
return;
}
state.loading = true;
const fileName = '网格种植记录明细表';
// ExportEntity(state.query)
// .then((res) => {
// if (res.status === 200) {
// downloadFile(res.data, `${fileName}.xlsx`, 'blob');
// app.$message.success('');
// }
// })
// .catch((err) => {
// app.$message.error('');
// })
// .finally(() => {
// state.loading = false;
// });
};
</script>

View File

@ -2,361 +2,529 @@
<div class="custom-page"> <div class="custom-page">
<avue-crud <avue-crud
ref="crudRef" ref="crudRef"
v-model="state.form" v-model:page="pageData"
v-model:search="state.query" :data="crudData"
v-model:page="state.pageData" :option="crudOptions"
:table-loading="state.loading" :table-loading="loading"
:data="state.data" @refresh-change="handleRefresh"
:option="state.options" @current-change="handleCurrentChange"
@refresh-change="refreshChange" @size-change="handleSizeChange"
@search-reset="searchChange"
@search-change="searchChange"
@selection-change="selectionChange"
@current-change="currentChange"
@size-change="sizeChange"
@row-save="rowSave"
@row-update="rowUpdate"
> >
<template #menu-left> <template #menu-left>
<el-button type="success" icon="download" @click="onExport">导出</el-button> <el-button type="primary" icon="Plus" @click="handleAdd">新增</el-button>
<el-button type="success" icon="download" @click="handleExport">导出</el-button>
</template> </template>
<template #menu="scope"> <template #menu="scope">
<custom-table-operate :actions="state.options.actions" :data="scope" /> <custom-table-operate :actions="crudOptions.actions" :data="scope" />
</template>
<template #isIllegal="{ row }">
<el-tag v-if="row.isIllegal == '1'" type="danger"></el-tag>
<el-tag v-if="row.isIllegal == '0'" type="success"></el-tag>
</template>
<template #inspectionStatus="{ row }">
<el-tag v-if="row.inspectionStatus == '1'" type="success">已结束</el-tag>
<el-tag v-if="row.inspectionStatus == '0'">进行中</el-tag>
</template> </template>
</avue-crud> </avue-crud>
<el-dialog v-model="infoVisible" title="巡查任务" width="800" center> <el-dialog :key="dialogTitle" v-model="visible" :title="dialogTitle" width="60%" align-center :draggable="true">
<el-form ref="infoRef" :model="infoData" :rules="infoRules"> <p class="form-group">任务信息</p>
<el-descriptions :title="infoData.planName || ''" :column="2"> <el-form :model="taskForm" :disabled="isReadonlyInfo" label-width="100px">
<el-descriptions-item label="任务编号">{{ infoData.id || '--' }}</el-descriptions-item>
<el-descriptions-item label="任务名称">{{ infoData.planName || '--' }}</el-descriptions-item>
<el-descriptions-item label="任务成员">{{ infoData.plantingArea || '--' }}</el-descriptions-item>
<el-descriptions-item label="巡查类型">{{ infoData.plantingMonths || '--' }}</el-descriptions-item>
<el-descriptions-item label="注意事项">{{ infoData.growthCycle || '--' }}</el-descriptions-item>
<el-descriptions-item label="巡查对象">{{ infoData.note || '--' }}</el-descriptions-item>
</el-descriptions>
<el-descriptions :title="'巡查信息登记'"> </el-descriptions>
<el-row :gutter="20"> <el-row :gutter="20">
<el-col :span="12"> <el-col :span="12">
<el-form-item label="是否违法:" prop="num"> <el-form-item label="任务编号" prop="taskCode">
<el-radio-group v-model="radio1"> <el-input v-model="taskForm.taskCode" placeholder="请输入任务编号" />
<el-radio value="1" size="large"></el-radio> </el-form-item>
<el-radio value="2" size="large"></el-radio> <el-form-item label="任务成员" prop="taskUserIds">
</el-radio-group> <!-- /land-resource/grid-member/current-user -->
<url-select
v-model="taskForm.taskUserIds"
url="/land-resource/grid-member/current-user"
placeholder="请选择任务成员"
multiple="true"
label-key="memberName"
value-key="id"
:response-parser="(res) => res.data.memberList"
/>
</el-form-item>
<el-form-item label="注意事项" prop="notes">
<el-input v-model="taskForm.notes" type="textarea" :autosize="{ minRows: 2, maxRows: 6 }" placeholder="请输入注意事项" />
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col :span="12"> <el-col :span="12">
<el-form-item label="巡查情况" prop="gridName"> <el-form-item label="任务名称" prop="taskName">
<el-input <el-input v-model="taskForm.taskName" placeholder="请输入任务名称" />
v-model="infoData.mark" </el-form-item>
:autosize="{ minRows: 2, maxRows: 4 }" <el-form-item label="巡查类型" prop="inspectionTypeCode">
type="textarea" <url-select
laceholder="请输入巡查情况" v-model="taskForm.inspectionTypeCode"
style="width: 240px" url="/system/dict/data/type/land_res_patrol_type"
></el-input> placeholder="请选择巡查类型"
label-key="dictLabel"
value-key="dictValue"
:response-parser="(res) => res.data"
/>
</el-form-item>
<el-form-item label="巡查对象" prop="inspectionTarget">
<el-input v-model="taskForm.inspectionTarget" placeholder="请输入巡查对象" />
</el-form-item> </el-form-item>
</el-col> </el-col>
</el-row> </el-row>
</el-form> </el-form>
<!-- 巡查信息登记只有进行过结果登记的才显示 -->
<template v-if="dialogTitle !== '查看' && dialogTitle !== '详情' && dialogTitle !== '新增' && dialogTitle !== '编辑'">
<p class="form-group">巡查信息登记</p>
<!-- 循环渲染多个表单 -->
<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)" />
</div>
<el-form :model="form" :disabled="isReadonlyRegist" label-width="100px" class="form-item">
<el-row :gutter="20">
<el-col :span="12">
<!-- 选择地块 -->
<el-form-item label="选择地块" prop="landId">
<url-select
v-model="form.landId"
url="/land-resource/landManage/page"
placeholder="请选择地块"
label-key="landName"
value-key="id"
:params="{ current: 1, size: 999 }"
/>
</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-group>
</el-form-item>
<!-- 违法时间 -->
<el-form-item label="违法时间" prop="illegalDate">
<el-date-picker v-model="form.illegalDate" type="datetime" placeholder="选择违法时间" />
</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>
</el-col>
<el-col :span="12">
<el-form-item label="违法类型" prop="illegalType">
<url-select
v-model="form.illegalTypeCode"
url="/system/dict/data/type/land_inspection_illegal_type"
placeholder="请选择违法类型"
label-key="dictLabel"
value-key="dictValue"
:response-parser="(res) => res.data"
/>
</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>
</el-col>
</el-row>
</el-form>
</div>
<div v-if="!isReadonlyRegist" class="form-footer">
<el-button type="primary" @click="handleAddForm"> 添加记录 </el-button>
</div>
</template>
<template #footer> <template #footer>
<div class="dialog-footer"> <div class="dialog-footer">
<el-button @click="infoCancel">取消</el-button> <!-- <el-button @click="infoCancel">取消</el-button> -->
<el-button type="primary" @click="subMitInfo(infoRef)"> 确认 </el-button> <el-button type="primary" @click="handleSubmit()"> 确认 </el-button>
</div> </div>
</template> </template>
</el-dialog> </el-dialog>
</div> </div>
</template> </template>
<script setup> <script setup>
import { reactive, ref, h } from 'vue'; import { ref, reactive, watch, onMounted, computed, nextTick } from 'vue';
import { useApp } from '@/hooks';
import { CRUD_OPTIONS } from '@/config'; import { CRUD_OPTIONS } from '@/config';
import { isEmpty, downloadFile } from '@/utils'; import { ElMessage } from 'element-plus';
import { useUserStore } from '@/store/modules/user'; import { useActionPermissions } from '@/hooks/useActionPermissions';
import { getlandInspection, savelandInspection, enrolllandInspection, exportlandInspection, getAddrCropByLand } from '@/apis/land'; import {
import { progressProps } from 'element-plus'; createLandInspection,
deleteLandInspection,
updateLandInspection,
updateLandInspectionStatus,
getLandInspectionDetail,
fetchLandInspectionList,
exportLandInspection,
createInspectionResult,
deleteInspectionResult,
getInspectionResultDetail,
} from '@/apis/landResourceManagement/landInspection/index';
const { VITE_APP_BASE_API } = import.meta.env; const dialogTitle = ref('新增');
const app = useApp(); const visible = ref(false);
const UserStore = useUserStore(); const isReadonlyInfo = ref(false);
const crudRef = ref(null); const isReadonlyRegist = ref(false);
const handleLandChange = async (value, form, done) => {
if (!value || !value.item || !value.item.id) return; //
let val = {};
getAddrCropByLand(value.item?.id || '')
.then((res) => {
if (res.code === 200) {
val = res.data || {};
}
})
.catch((err) => {
val = {};
})
.finally(() => {});
state.form.crop = val?.crop || value.item?.crop;
state.form.address = val?.county + val?.town + val?.village || value.item?.address;
};
const jobTypeOptions = reactive([ const pageData = ref({
{ label: '施肥', value: '0' }, currentPage: 1,
{ label: '杀虫', value: '1' }, pageSize: 10,
{ label: '灌溉', value: '2' }, total: 0,
]); });
const isDisabled = ref(false); const searchForm = ref({
const state = reactive({
loading: false,
query: {
current: 1,
size: 10,
taskCode: '', taskCode: '',
taskName: '', taskName: '',
taskMembers: '', userId: '',
}, inspectionTypeCode: '',
form: {}, gridId: '',
selection: [], });
options: {
const taskForm = ref({
id: '', // ID
taskCode: '', //
taskName: '', //
taskUserIds: [], // ID
taskMembers: '', //
inspectionTypeCode: '', //
inspectionType: '', //
inspectionTarget: '', //
inspectionStatus: '', //
notes: '', //
inspectionResults: [], //
});
const illegalForm = ref({
id: '', // ID
inspectionId: '', // ID
inspectionTaskName: '', //
landId: '', // ID
landName: '', //
illegalFlag: 0, //
illegalDate: '', //
illegalTypeCode: '', //
illegalTypeName: '', //
desc: '', //
img: '111', //
status: '', //
});
const illegalForms = ref([{ ...illegalForm.value }]);
const crudData = ref([]);
const loading = ref(false);
const crudOptions = reactive({
...CRUD_OPTIONS, ...CRUD_OPTIONS,
addBtnText: '新增', addBtn: false,
updateBtnText: '确定', searchBtn: false,
searchSpan: 6, emptyBtn: false,
searchGutter: 80,
searchMenuPosition: 'center',
index: true,
column: [ column: [
{ { label: '任务编号', prop: 'taskCode' },
label: '任务编号', { label: '任务名称', prop: 'taskName' },
prop: 'taskCode', { label: '任务成员', prop: 'taskMembers' },
}, { label: '巡查类型', prop: 'inspectionType' },
{ { label: '巡查对象', prop: 'inspectionTarget' },
label: '任务名称', { label: '注意事项', prop: 'notes' },
prop: 'taskName', { label: '是否违法', prop: 'isIllegal' },
}, { label: '状态', prop: 'inspectionStatus' },
{
label: '任务成员',
prop: 'taskMembers',
},
{
label: '巡查类型',
prop: 'inspectionType',
},
{
label: '巡查对象',
prop: 'inspectionTarget',
},
{
label: '注意事项',
prop: 'notes',
},
{
label: '是否违法',
prop: 'isIllegal',
},
{
label: '状态',
prop: 'inspectionStatus',
},
], ],
actions: [ actions: [
{ {
name: '登记结果', name: '查看',
icon: 'view',
event: ({ row }) => handleView(row.id),
},
{
name: '编辑',
icon: 'edit', icon: 'edit',
event: ({ row }) => doEnroll(row), event: ({ row }) => handleEdit(row.id),
},
{
type: 'danger',
name: '删除',
icon: 'delete',
event: ({ row }) => handleDelete(row.id),
},
//
{
name: '结果登记',
icon: 'result',
event: ({ row }) => handleResult(row.id),
},
//
{
name: '收回任务',
icon: 'back',
event: ({ row }) => handleBack(row.id),
},
//
{
name: '发布任务',
icon: 'publish',
event: ({ row }) => handlePublish(row.id),
},
//
{
name: '重新发布',
icon: 're-publish',
event: ({ row }) => handleRePublish(row.id),
},
//
{
name: '查看登记结果',
icon: 'view-result',
event: ({ row }) => handleViewResult(row),
}, },
], ],
},
pageData: {
total: 0,
currentPage: 1,
pageSize: 10,
},
data: [],
currentRow: {},
});
const infoVisible = ref(false);
const infoRef = ref();
const infoData = reactive({
num: '',
name: '',
member: [],
type: '',
mark: '',
target: '',
}); });
const infoRules = reactive({ onMounted(() => {
num: [{ required: true, message: '请选择是否违法', trigger: 'blur' }], getData();
mark: [{ required: true, message: '请输入巡查情况', trigger: 'blur' }],
}); });
const getData = async () => {
// loading.value = true;
const loadData = () => { try {
state.loading = true; const response = await fetchLandInspectionList({
getlandInspection(state.query) current: pageData.value.currentPage,
.then((res) => { size: pageData.value.pageSize,
if (res.code === 200) { ...searchForm.value,
const { current, size, total, records } = res.data; });
state.data = records; crudData.value = response.data.records;
state.pageData = { pageData.value.total = response.data.total;
currentPage: current || 1, pageData.value.currentPage = response.data.current;
pageSize: size || 10, pageData.value.pageSize = response.data.size;
total: total, } catch (error) {
}; ElMessage.error('加载数据失败');
} finally {
loading.value = false;
} }
})
.catch((err) => {
app.$message.error(err.msg);
state.data = [];
})
.finally(() => {
state.loading = false;
});
}; };
const handleAdd = () => {
loadData(); isReadonlyInfo.value = false;
// resetForm();
// dialogTitle.value = '新增';
const currentChange = (current) => { visible.value = true;
state.query.current = current;
loadData();
}; };
const handleEdit = async (id) => {
// console.log('编辑行:', id);
const sizeChange = (size) => { isReadonlyInfo.value = false;
state.query.size = size; const response = await getLandInspectionDetail(id);
loadData(); taskForm.value = response.data;
}; // inspectionUsers[]idtaskUserIds[]
if (taskForm.value.inspectionUsers && Array.isArray(taskForm.value.inspectionUsers)) {
// taskForm.value.taskUserIds = taskForm.value.inspectionUsers.map((user) => user.userId);
const searchChange = (params, done) => {
if (done) done();
state.query = params;
state.query.current = 1;
loadData();
};
//
const refreshChange = () => {
loadData();
app.$message.success('刷新成功');
};
//
const selectionChange = (rows) => {
state.selection = rows;
};
//
const rowSave = (row, done, loading) => {
// console.info('', row);
savelandInspection(row)
.then((res) => {
if (res.code === 200) {
app.$message.success('添加成功!');
done();
loadData();
}
})
.catch((err) => {
app.$message.error(err.msg);
})
.finally(() => {
loading();
});
};
//
const doEnroll = (row) => {
console.info('doEnroll', row);
// infoVisible.value = true;
isDisabled.value = row.inspectionStatus == '1';
crudRef.value.rowEdit(row);
};
const rowUpdate = (row, index, done, loading) => {
console.info('登记结果');
let parmer = {
id: row.id || '',
isIllegal: row.isIllegal || '0', //0 1
inspectionSituation: row.inspectionSituation || '', //
};
enrolllandInspection(parmer)
.then((res) => {
if (res.code === 200) {
app.$message.success('登记结果成功!');
done();
loadData();
}
})
.catch((err) => {
app.$message.error(err.msg);
})
.finally(() => {
loading();
});
};
//
const onExport = () => {
if (isEmpty(state.data)) {
app.$message.error('当前暂时没有可供导出的数据!');
return;
}
state.loading = true;
const fileName = '土地巡查明细表';
exportlandInspection(state.query)
.then((res) => {
if (res.status === 200) {
downloadFile(res.data, `${fileName}.xlsx`, 'blob');
app.$message.success('导出成功!');
}
})
.catch((err) => {
app.$message.error('导出失败!');
})
.finally(() => {
state.loading = false;
});
};
const subMitInfo = (formEl) => {
if (!formEl) return;
formEl.validate((valid) => {
if (valid) {
infoHide();
console.log('submit!');
} else { } else {
console.log('error submit!'); taskForm.value.taskUserIds = [];
} }
dialogTitle.value = '编辑';
visible.value = true;
};
const handleView = async (id) => {
console.log('查看行:', id);
const response = await getLandInspectionDetail(id);
taskForm.value = response.data;
const arr = response.data.inspectionResults;
if (arr && Array.isArray(arr)) {
illegalForms.value = arr;
}
isReadonlyInfo.value = true;
if (taskForm.value.inspectionUsers && Array.isArray(taskForm.value.inspectionUsers)) {
taskForm.value.taskUserIds = taskForm.value.inspectionUsers.map((user) => user.userId);
} else {
taskForm.value.taskUserIds = [];
}
dialogTitle.value = '查看';
visible.value = true;
};
const handleDelete = async (id) => {
console.log('删除ID:', id);
const response = await deleteLandInspection(id);
if (response?.code === 200) {
ElMessage.success(response?.msg || '删除成功');
getData(); //
}
};
const handleResult = async (id) => {
console.log('结果登记ID:', id);
await handleView(id);
isReadonlyRegist.value = false;
dialogTitle.value = '结果登记';
illegalForm.value.inspectionId = id;
nextTick(() => {
visible.value = true;
});
};
const handleBack = async (id) => {
console.log('收回任务ID:', id);
const response = await updateLandInspectionStatus({
id,
status: '02',
});
ElMessage.success(response?.msg || '发布成功');
await getData();
};
const handlePublish = async (id) => {
console.log('发布任务ID:', id);
// updateLandInspectionStatus : status -1 => 00
const response = await updateLandInspectionStatus({
id,
status: '00',
});
ElMessage.success(response?.msg || '发布成功');
await getData();
};
const handleRePublish = async (id) => {
console.log('重新发布ID:', id);
const response = await updateLandInspectionStatus({
id,
status: '00',
});
ElMessage.success(response?.msg || '发布成功');
await getData();
};
const handleViewResult = async (row) => {
console.log('查看登记结果ID:', row.id);
await handleView(row.id);
isReadonlyRegist.value = true;
// const response = await getInspectionResultDetail(row.id);
// illegalForm.value = response.data;
dialogTitle.value = '查看登记结果';
nextTick(() => {
visible.value = true;
}); });
}; };
const infoCancel = () => { //
infoHide(); const handleRemoveForm = (index) => {
illegalForms.value.splice(index, 1);
}; };
const infoHide = () => { const handleSubmit = async () => {
infoRef.value && infoRef.value.resetFields(); try {
infoVisible.value = false; console.log('表单数据:', taskForm.value);
}; console.log('表单数据:', illegalForm.value);
</script> // 1. refName
<style scoped> loading.value = true;
/* 使用 ::v-deep 深度选择器来穿透 scoped 样式 */ let response;
::v-deep .el-table .el-table__row { // 2.
height: 50px; /* 调整行高,间接控制行间距 */ if (dialogTitle.value === '新增') {
taskForm.value.id = '';
response = await createLandInspection(taskForm.value);
// 3. 200
ElMessage.success(response?.msg || '新增成功');
visible.value = false;
await getData();
} else if (dialogTitle.value === '编辑') {
response = await updateLandInspection(taskForm.value);
// 3. 200
ElMessage.success(response?.msg || '编辑成功');
visible.value = false;
await getData();
} else if (dialogTitle.value === '结果登记') {
response = await createInspectionResult(illegalForm.value);
ElMessage.success(response?.msg || '结果登记成功');
await getData();
} }
//
} catch (e) {
ElMessage.error('保存失败');
} finally {
loading.value = false;
}
};
const handleExport = async () => {
try {
const response = await exportLandInspection(searchForm.value);
if (response?.code === 200) {
//
const link = document.createElement('a');
link.href = response.data; // data
link.download = 'land_inspection_export.xlsx'; //
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
ElMessage.success('导出成功');
} else {
ElMessage.error(response?.msg || '导出失败');
}
} catch (error) {
ElMessage.error('导出失败,请稍后重试');
}
};
function handleRefresh() {
console.log('刷新数据');
}
function handleAddForm() {
console.log('添加记录');
illegalForms.value.push({ ...illegalForm.value });
}
function handleCurrentChange(val) {
console.log('当前页:', val);
}
function handleSizeChange(val) {
console.log('每页显示条数:', val);
}
// ---------------------------------------------------------------------
//
// ---------------------------------------------------------------------
::v-deep .el-table .el-table__row td { const role = ref('operator');
padding: 8px 0; /* 调整单元格内边距,进一步微调行间距 */ //
const allActions = [
{ name: '查看', icon: 'view', key: 'view', event: ({ row }) => handleView(row.id) },
{ name: '编辑', icon: 'edit', key: 'edit', event: ({ row }) => handleEdit(row.id) },
{ name: '删除', icon: 'delete', key: 'delete', type: 'danger', event: ({ row }) => handleDelete(row.id) },
{ name: '结果登记', icon: 'result', key: 'result', event: ({ row }) => handleResult(row.id) },
{ name: '收回任务', icon: 'back', key: 'back', event: ({ row }) => handleBack(row.id) },
{ name: '发布任务', icon: 'publish', key: 'publish', event: ({ row }) => handlePublish(row.id) },
{ name: '重新发布', icon: 're-publish', key: 'rePublish', event: ({ row }) => handleRePublish(row.id) },
{ name: '查看登记结果', icon: 'view-result', key: 'viewResult', event: ({ row }) => handleViewResult(row) },
];
// ->
const permissionMap = {
admin: ['operator', 'inspector'], // operator inspector
operator: ['view', 'edit', 'delete', 'publish', 'back', 'rePublish', 'result', 'viewResult'],
inspector: ['result', 'viewResult'],
};
// ->
const statusMap = {
'-1': ['view', 'edit', 'delete', 'publish'],
'00': ['result', 'back', 'viewResult'],
'01': ['viewResult'],
'02': ['view', 'edit', 'delete', 'rePublish'],
};
// 使 Hook
// const { actions } = useActionPermissions(role, status, allActions, permissionMap, statusMap);
</script>
<style scoped lang="scss">
:deep(.el-dialog__body) {
padding: 20px;
height: calc(100vh - 300px);
overflow-y: auto;
}
.form-container {
position: relative;
border: 1px solid #ebeef5;
border-radius: 4px;
padding: 15px;
margin-bottom: 20px;
}
.form-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 15px;
padding-bottom: 10px;
border-bottom: 1px solid #eee;
}
.form-footer {
margin-top: 20px;
text-align: center;
}
.form-group {
font-size: 16px;
font-weight: 500;
margin: 30px 0;
color: #333333;
} }
</style> </style>

View File

@ -0,0 +1,362 @@
<template>
<div class="custom-page">
<avue-crud
ref="crudRef"
v-model="state.form"
v-model:search="state.query"
v-model:page="state.pageData"
:table-loading="state.loading"
:data="state.data"
:option="state.options"
@refresh-change="refreshChange"
@search-reset="searchChange"
@search-change="searchChange"
@selection-change="selectionChange"
@current-change="currentChange"
@size-change="sizeChange"
@row-save="rowSave"
@row-update="rowUpdate"
>
<template #menu-left>
<el-button type="success" icon="download" @click="onExport">导出</el-button>
</template>
<template #menu="scope">
<custom-table-operate :actions="state.options.actions" :data="scope" />
</template>
<template #isIllegal="{ row }">
<el-tag v-if="row.isIllegal == '1'" type="danger"></el-tag>
<el-tag v-if="row.isIllegal == '0'" type="success"></el-tag>
</template>
<template #inspectionStatus="{ row }">
<el-tag v-if="row.inspectionStatus == '1'" type="success">已结束</el-tag>
<el-tag v-if="row.inspectionStatus == '0'">进行中</el-tag>
</template>
</avue-crud>
<el-dialog v-model="infoVisible" title="巡查任务" width="800" center>
<el-form ref="infoRef" :model="infoData" :rules="infoRules">
<el-descriptions :title="infoData.planName || ''" :column="2">
<el-descriptions-item label="任务编号">{{ infoData.id || '--' }}</el-descriptions-item>
<el-descriptions-item label="任务名称">{{ infoData.planName || '--' }}</el-descriptions-item>
<el-descriptions-item label="任务成员">{{ infoData.plantingArea || '--' }}</el-descriptions-item>
<el-descriptions-item label="巡查类型">{{ infoData.plantingMonths || '--' }}</el-descriptions-item>
<el-descriptions-item label="注意事项">{{ infoData.growthCycle || '--' }}</el-descriptions-item>
<el-descriptions-item label="巡查对象">{{ infoData.note || '--' }}</el-descriptions-item>
</el-descriptions>
<el-descriptions :title="'巡查信息登记'"> </el-descriptions>
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="是否违法:" prop="num">
<el-radio-group v-model="radio1">
<el-radio value="1" size="large"></el-radio>
<el-radio value="2" size="large"></el-radio>
</el-radio-group>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="巡查情况" prop="gridName">
<el-input
v-model="infoData.mark"
:autosize="{ minRows: 2, maxRows: 4 }"
type="textarea"
laceholder="请输入巡查情况"
style="width: 240px"
></el-input>
</el-form-item>
</el-col>
</el-row>
</el-form>
<template #footer>
<div class="dialog-footer">
<el-button @click="infoCancel">取消</el-button>
<el-button type="primary" @click="subMitInfo(infoRef)"> 确认 </el-button>
</div>
</template>
</el-dialog>
</div>
</template>
<script setup>
import { reactive, ref, h } from 'vue';
import { useApp } from '@/hooks';
import { CRUD_OPTIONS } from '@/config';
import { isEmpty, downloadFile } from '@/utils';
import { useUserStore } from '@/store/modules/user';
import { getlandInspection, savelandInspection, enrolllandInspection, exportlandInspection, getAddrCropByLand } from '@/apis/land';
import { progressProps } from 'element-plus';
const { VITE_APP_BASE_API } = import.meta.env;
const app = useApp();
const UserStore = useUserStore();
const crudRef = ref(null);
const handleLandChange = async (value, form, done) => {
if (!value || !value.item || !value.item.id) return; //
let val = {};
getAddrCropByLand(value.item?.id || '')
.then((res) => {
if (res.code === 200) {
val = res.data || {};
}
})
.catch((err) => {
val = {};
})
.finally(() => {});
state.form.crop = val?.crop || value.item?.crop;
state.form.address = val?.county + val?.town + val?.village || value.item?.address;
};
const jobTypeOptions = reactive([
{ label: '施肥', value: '0' },
{ label: '杀虫', value: '1' },
{ label: '灌溉', value: '2' },
]);
const isDisabled = ref(false);
const state = reactive({
loading: false,
query: {
current: 1,
size: 10,
taskCode: '',
taskName: '',
taskMembers: '',
},
form: {},
selection: [],
options: {
...CRUD_OPTIONS,
addBtnText: '新增',
updateBtnText: '确定',
searchSpan: 6,
searchGutter: 80,
searchMenuPosition: 'center',
index: true,
column: [
{
label: '任务编号',
prop: 'taskCode',
},
{
label: '任务名称',
prop: 'taskName',
},
{
label: '任务成员',
prop: 'taskMembers',
},
{
label: '巡查类型',
prop: 'inspectionType',
},
{
label: '巡查对象',
prop: 'inspectionTarget',
},
{
label: '注意事项',
prop: 'notes',
},
{
label: '是否违法',
prop: 'isIllegal',
},
{
label: '状态',
prop: 'inspectionStatus',
},
],
actions: [
{
name: '登记结果',
icon: 'edit',
event: ({ row }) => doEnroll(row),
},
],
},
pageData: {
total: 0,
currentPage: 1,
pageSize: 10,
},
data: [],
currentRow: {},
});
const infoVisible = ref(false);
const infoRef = ref();
const infoData = reactive({
num: '',
name: '',
member: [],
type: '',
mark: '',
target: '',
});
const infoRules = reactive({
num: [{ required: true, message: '请选择是否违法', trigger: 'blur' }],
mark: [{ required: true, message: '请输入巡查情况', trigger: 'blur' }],
});
//
const loadData = () => {
state.loading = true;
getlandInspection(state.query)
.then((res) => {
if (res.code === 200) {
const { current, size, total, records } = res.data;
state.data = records;
state.pageData = {
currentPage: current || 1,
pageSize: size || 10,
total: total,
};
}
})
.catch((err) => {
app.$message.error(err.msg);
state.data = [];
})
.finally(() => {
state.loading = false;
});
};
loadData();
//
const currentChange = (current) => {
state.query.current = current;
loadData();
};
//
const sizeChange = (size) => {
state.query.size = size;
loadData();
};
//
const searchChange = (params, done) => {
if (done) done();
state.query = params;
state.query.current = 1;
loadData();
};
//
const refreshChange = () => {
loadData();
app.$message.success('刷新成功');
};
//
const selectionChange = (rows) => {
state.selection = rows;
};
//
const rowSave = (row, done, loading) => {
// console.info('', row);
savelandInspection(row)
.then((res) => {
if (res.code === 200) {
app.$message.success('添加成功!');
done();
loadData();
}
})
.catch((err) => {
app.$message.error(err.msg);
})
.finally(() => {
loading();
});
};
//
const doEnroll = (row) => {
console.info('doEnroll', row);
// infoVisible.value = true;
isDisabled.value = row.inspectionStatus == '1';
crudRef.value.rowEdit(row);
};
const rowUpdate = (row, index, done, loading) => {
console.info('登记结果');
let parmer = {
id: row.id || '',
isIllegal: row.isIllegal || '0', //0 1
inspectionSituation: row.inspectionSituation || '', //
};
enrolllandInspection(parmer)
.then((res) => {
if (res.code === 200) {
app.$message.success('登记结果成功!');
done();
loadData();
}
})
.catch((err) => {
app.$message.error(err.msg);
})
.finally(() => {
loading();
});
};
//
const onExport = () => {
if (isEmpty(state.data)) {
app.$message.error('当前暂时没有可供导出的数据!');
return;
}
state.loading = true;
const fileName = '土地巡查明细表';
exportlandInspection(state.query)
.then((res) => {
if (res.status === 200) {
downloadFile(res.data, `${fileName}.xlsx`, 'blob');
app.$message.success('导出成功!');
}
})
.catch((err) => {
app.$message.error('导出失败!');
})
.finally(() => {
state.loading = false;
});
};
const subMitInfo = (formEl) => {
if (!formEl) return;
formEl.validate((valid) => {
if (valid) {
infoHide();
console.log('submit!');
} else {
console.log('error submit!');
}
});
};
const infoCancel = () => {
infoHide();
};
const infoHide = () => {
infoRef.value && infoRef.value.resetFields();
infoVisible.value = false;
};
</script>
<style scoped>
/* 使用 ::v-deep 深度选择器来穿透 scoped 样式 */
::v-deep .el-table .el-table__row {
height: 50px; /* 调整行高,间接控制行间距 */
}
::v-deep .el-table .el-table__row td {
padding: 8px 0; /* 调整单元格内边距,进一步微调行间距 */
}
</style>

View File

@ -0,0 +1,137 @@
<template>
<section class="custom_attrs_upload_content_lx" :style="{ '--columns': props.fileNum }">
<el-upload
v-if="props.type != 'view'"
class="custom-form__uploader"
action=""
:show-file-list="false"
:accept="props.accept"
:limit="props.limit"
:http-request="rowUploadPicture"
:disabled="attrs_.length >= props.limit"
>
<el-icon class="custom-form__uploader__icon"><Plus /></el-icon>
</el-upload>
<div v-for="item in attrs_" :key="`attr_${item.uid}`" class="attrs_content__item">
<video v-if="isMP4(item.url)" :src="item.url" controls />
<img v-else :src="item.url" :alt="item.name" @click="handlePreview(i)" />
<el-icon v-if="props.type != 'view'" class="clear_btn" @click="handleClearAttr(item.uid)"><CircleCloseFilled /></el-icon>
</div>
<el-image-viewer v-if="previewShow" :url-list="srcList" :initial-index="index" @close="previewShow = false" />
</section>
</template>
<script setup>
import { nextTick, ref, watch } from 'vue';
import { CommonUpload } from '@/apis';
const emit = defineEmits(['update:attrs']);
const props = defineProps({
accept: {
type: String,
default: 'image/*',
},
type: {
type: String,
default: 'view',
},
attrs: {
type: Array,
default: () => [],
},
limit: {
type: Number,
default: 20,
},
fileNum: {
type: Number,
default: 4,
},
});
const attrs_ = ref([]);
const srcList = ref([]);
srcList.value = attrs_.value.map((item) => item.url);
watch(
() => props.attrs,
(val) => {
attrs_.value = val;
},
{ deep: true, immediate: true }
);
const index = ref(0);
const previewShow = ref(false);
function handleClearAttr(uid) {
attrs_.value = attrs_.value.filter((item) => item.uid !== uid);
emit('update:attrs', attrs_.value);
}
async function rowUploadPicture({ file }) {
const formData = new FormData();
formData.append('file', file);
const res = await CommonUpload(formData);
if (res.code === 200) {
attrs_.value.push({
...res.data,
uid: 'id_' + Date.now(),
});
emit('update:attrs', attrs_.value);
}
}
function isMP4(filePath) {
// 使 .mp4
const regex = /\.mp4$/i;
return regex.test(filePath);
}
function handlePreview(i) {
previewShow.value = false;
nextTick(() => {
index.value = i;
previewShow.value = true;
});
}
</script>
<style lang="scss">
.custom_attrs_upload_content_lx {
display: grid;
flex-wrap: wrap;
grid-template-columns: repeat(var(--columns), 1fr);
box-sizing: border-box;
gap: 20px;
> div {
width: 100%;
height: 100%;
aspect-ratio: 1 / 1;
box-sizing: border-box;
}
.attrs_content__item {
aspect-ratio: 1 / 1;
box-sizing: border-box;
position: relative;
padding: 6px;
border: 1px solid #ccc;
border-radius: 4px;
img,
video {
vertical-align: middle;
width: 100%;
height: 100%;
border-radius: 2px;
}
.clear_btn {
position: absolute;
right: 0px;
top: 0px;
font-size: 18px;
color: #f15c5c;
opacity: 0;
cursor: pointer;
background-color: #fff;
border-radius: 50%;
}
&:hover {
.clear_btn {
opacity: 1;
}
}
}
}
</style>

View File

@ -1,12 +1,10 @@
<template> <template>
<el-form :model="localForm" label-width="120px" :disabled="readonly"> <el-form :model="localForm" label-width="120px" :disabled="readonly">
<el-row :gutter="20">
<el-col :span="24">
<h3>经营主体信息</h3> <h3>经营主体信息</h3>
</el-col> <el-row :gutter="20">
<el-col :span="12"> <el-col :span="12">
<el-form-item label="农企/合作社名称"> <el-form-item label="农企/合作社名称">
<el-input v-model="localForm.name" placeholder="请输入" /> <el-input v-model="localForm.businessName" placeholder="请输入" />
</el-form-item> </el-form-item>
<el-form-item label="面积"> <el-form-item label="面积">
<el-input v-model="localForm.area" placeholder="请输入" /> <el-input v-model="localForm.area" placeholder="请输入" />
@ -15,7 +13,16 @@
<el-input v-model="localForm.contactPerson" placeholder="请输入" /> <el-input v-model="localForm.contactPerson" placeholder="请输入" />
</el-form-item> </el-form-item>
<el-form-item label="农企/合作社照片"> <el-form-item label="农企/合作社照片">
<el-upload action="#" list-type="picture-card" :disabled="readonly" :auto-upload="false"> <el-upload
action="#"
:http-request="customUploadRequest"
:on-success="(res, file) => handleUploadSuccess(res, file, 'cooperativePhoto')"
:file-list="cooperativePhotoList"
list-type="picture-card"
:limit="1"
:on-exceed="handleExceed"
:on-remove="() => handleRemove('cooperativePhoto')"
>
<el-icon><Plus /></el-icon> <el-icon><Plus /></el-icon>
</el-upload> </el-upload>
</el-form-item> </el-form-item>
@ -23,19 +30,31 @@
<el-col :span="12"> <el-col :span="12">
<el-form-item label="地址"> <el-form-item label="地址">
<el-cascader v-model="localForm.address" :options="regionOptions" placeholder="请选择" /> <area-select v-model="localForm.addressArr" :disabled="readonly" :label="null" />
</el-form-item> </el-form-item>
<el-form-item label="经营产品"> <el-form-item label="经营产品">
<el-input v-model="localForm.product" placeholder="请输入" /> <el-input v-model="localForm.primaryProduct" placeholder="请输入" />
</el-form-item> </el-form-item>
<el-form-item label="联系电话"> <el-form-item label="联系电话">
<el-input v-model="localForm.phone" placeholder="请输入" /> <el-input v-model="localForm.phone" placeholder="请输入" />
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col :span="24"> </el-row>
<h3>证件资料</h3> <h3>证件资料</h3>
<el-row :gutter="20">
<el-col :span="24">
<el-form-item label="营业执照"> <el-form-item label="营业执照">
<el-upload action="#" list-type="picture-card" :disabled="readonly" :auto-upload="false"> <el-upload
action="#"
:http-request="customUploadRequest"
:on-success="(res, file) => handleUploadSuccess(res, file, 'businessLicence')"
:file-list="businessLicenceList"
list-type="picture-card"
:limit="1"
:on-exceed="handleExceed"
:on-remove="() => handleRemove('businessLicence')"
>
<el-icon><Plus /></el-icon> <el-icon><Plus /></el-icon>
</el-upload> </el-upload>
</el-form-item> </el-form-item>
@ -45,8 +64,12 @@
</template> </template>
<script setup> <script setup>
import { reactive, watch } from 'vue'; import { ref, reactive, watch } from 'vue';
import { Plus } from '@element-plus/icons-vue'; import { Plus } from '@element-plus/icons-vue';
import cloneDeep from 'lodash/cloneDeep';
import { CommonUpload } from '@/apis/index';
import { ElMessage } from 'element-plus';
import Attrs from './Attrs.vue';
const props = defineProps({ const props = defineProps({
modelValue: { modelValue: {
@ -57,10 +80,14 @@ const props = defineProps({
readonly: Boolean, readonly: Boolean,
}); });
const ossUrl = 'http://gov-cloud.oss-cn-chengdu.aliyuncs.com/';
const cooperativePhotoList = ref([]);
const businessLicenceList = ref([]);
const emit = defineEmits(['update:modelValue']); const emit = defineEmits(['update:modelValue']);
// props // props
const localForm = reactive({ ...props.modelValue }); const localForm = ref({ ...props.modelValue });
// //
watch( watch(
@ -70,18 +97,87 @@ watch(
}, },
{ deep: true } { deep: true }
); );
// watch(
// () => props.modelValue,
// (newVal) => {
// Object.assign(localForm, cloneDeep(newVal));
// },
// { deep: true }
// );
const regionOptions = [ const customUploadRequest = async (options) => {
const formData = new FormData();
formData.append('file', options.file);
try {
const response = await CommonUpload(formData);
options.onSuccess(response, options.file);
return response;
} catch (err) {
console.error('上传失败', err);
options.onError(err);
throw err;
}
};
const handleUploadSuccess = (res, file, fieldName) => {
localForm[fieldName] = res.data.url;
//
const previewItem = {
name: res.data.name,
url: ossUrl + res.data.url, // 访URL
status: 'success',
};
if (fieldName === 'cooperativePhoto') {
cooperativePhotoList.value = [previewItem];
} else {
businessLicenceList.value = [previewItem];
}
};
//
const handleRemove = (fieldName) => {
localForm[fieldName] = '';
if (fieldName === 'cooperativePhoto') {
cooperativePhotoList.value = [];
} else {
businessLicenceList.value = [];
}
};
//
const handleExceed = () => {
ElMessage.warning('只能上传一张图片,请先删除当前图片');
};
//
if (localForm.value.cooperativePhoto) {
cooperativePhotoList.value = [
{ {
label: '耿马县', name: '合作社照片',
value: '耿马县', url: ossUrl + localForm.value.cooperativePhoto,
children: [ status: 'success',
{
label: '耿马镇',
value: '耿马镇',
children: [{ label: '新城村', value: '新城村' }],
},
],
}, },
]; ];
}
if (localForm.value.businessLicence) {
businessLicenceList.value = [
{
name: '营业执照',
url: ossUrl + localForm.value.businessLicence,
status: 'success',
},
];
}
</script> </script>
<style scoped lang="scss">
h3 {
margin-top: 20px;
margin-bottom: 20px;
font-size: 16px;
font-weight: 500;
color: #333333;
width: 110px;
text-align: right;
}
</style>

View File

@ -1,12 +1,11 @@
<template> <template>
<div class="tab-business"> <div class="tab-business">
<el-form :model="localForm" label-width="140px"> <el-form :model="localForm" label-width="0">
<el-row :gutter="24"> <el-row :gutter="24">
<!-- 负债表 --> <!-- 负债表 -->
<el-col :span="24"> <el-col :span="8">
<el-form-item label="负债表"> <h3>负债表</h3>
<el-button type="text" @click="downloadTemplate('debt')"> 下载模板 </el-button> <!-- <el-upload
<el-upload
class="upload-btn" class="upload-btn"
action="#" action="#"
:auto-upload="false" :auto-upload="false"
@ -14,16 +13,20 @@
:before-upload="(file) => handleImport('debt', file)" :before-upload="(file) => handleImport('debt', file)"
:disabled="readonly" :disabled="readonly"
> >
<el-icon><Plus /></el-icon>
<el-button size="small" :disabled="readonly">导入表格</el-button> <el-button size="small" :disabled="readonly">导入表格</el-button>
</el-upload> </el-upload> -->
</el-form-item> <div class="view-file"></div>
<div class="upload-btn">
<el-button type="primary" :disabled="readonly">导入表格</el-button>
<el-button type="success" @click="downloadTemplate('debt')"> 下载模板 </el-button>
</div>
</el-col> </el-col>
<!-- 利润表 --> <!-- 利润表 -->
<el-col :span="24"> <el-col :span="8">
<el-form-item label="利润表"> <h3>利润表</h3>
<el-button type="text" @click="downloadTemplate('profit')"> 下载模板 </el-button> <!-- <el-upload
<el-upload
class="upload-btn" class="upload-btn"
action="#" action="#"
:auto-upload="false" :auto-upload="false"
@ -32,15 +35,18 @@
:disabled="readonly" :disabled="readonly"
> >
<el-button size="small" :disabled="readonly">导入表格</el-button> <el-button size="small" :disabled="readonly">导入表格</el-button>
</el-upload> </el-upload> -->
</el-form-item> <div class="view-file"></div>
<div class="upload-btn">
<el-button type="primary" :disabled="readonly">导入表格</el-button>
<el-button type="success" @click="downloadTemplate('profit')"> 下载模板 </el-button>
</div>
</el-col> </el-col>
<!-- 现金流量表 --> <!-- 现金流量表 -->
<el-col :span="24"> <el-col :span="8">
<el-form-item label="现金流量表"> <h3>现金流量表</h3>
<el-button type="text" @click="downloadTemplate('cashflow')"> 下载模板 </el-button> <!-- <el-upload
<el-upload
class="upload-btn" class="upload-btn"
action="#" action="#"
:auto-upload="false" :auto-upload="false"
@ -49,23 +55,22 @@
:disabled="readonly" :disabled="readonly"
> >
<el-button size="small" :disabled="readonly">导入表格</el-button> <el-button size="small" :disabled="readonly">导入表格</el-button>
</el-upload> </el-upload> -->
</el-form-item> <div class="view-file"></div>
<div class="upload-btn">
<el-button type="primary" :disabled="readonly">导入表格</el-button>
<el-button type="success" @click="downloadTemplate('cashflow')"> 下载模板 </el-button>
</div>
</el-col> </el-col>
</el-row> </el-row>
</el-form> </el-form>
<!-- 底部按钮 -->
<div class="business-footer" style="text-align: right; margin-top: 20px">
<el-button :disabled="readonly" @click="$emit('prev')">上一步</el-button>
<el-button v-if="!readonly" type="primary" @click="$emit('next', localForm)"> 下一步 </el-button>
<el-button v-if="readonly" type="warning" @click="$emit('edit')"> 修改 </el-button>
</div>
</div> </div>
</template> </template>
<script setup> <script setup>
import { reactive, watch } from 'vue'; import { reactive, watch } from 'vue';
import { Plus } from '@element-plus/icons-vue';
import cloneDeep from 'lodash/cloneDeep';
const props = defineProps({ const props = defineProps({
modelValue: { modelValue: {
@ -78,19 +83,10 @@ const props = defineProps({
}, },
}); });
const emit = defineEmits([ const emit = defineEmits(['update:modelValue']);
'update:modelValue',
'prev', //
'next', //
'edit', //
]);
// //
const localForm = reactive({ const localForm = reactive(cloneDeep(props.modelValue));
debtFiles: props.modelValue.debtFiles || [],
profitFiles: props.modelValue.profitFiles || [],
cashflowFiles: props.modelValue.cashflowFiles || [],
});
// watch // watch
watch( watch(
@ -100,6 +96,13 @@ watch(
}, },
{ deep: true } { deep: true }
); );
watch(
() => props.modelValue,
(newVal) => {
Object.assign(localForm, cloneDeep(newVal));
},
{ deep: true }
);
// //
function downloadTemplate(type) { function downloadTemplate(type) {
@ -130,10 +133,31 @@ function handleImport(type, file) {
</script> </script>
<style scoped> <style scoped>
h3 {
margin-top: 20px;
margin-bottom: 20px;
font-size: 16px;
font-weight: 500;
color: #606266;
width: 100%;
text-align: center;
}
.upload-btn { .upload-btn {
margin-left: 16px; margin: 20px 0;
display: flex;
justify-content: space-around;
} }
.business-footer el-button + el-button { .business-footer el-button + el-button {
margin-left: 8px; margin-left: 8px;
} }
.view-file {
height: 400px;
border: 1px solid #dcdfe6;
border-radius: 4px;
margin-bottom: 10px;
display: flex;
align-items: center;
justify-content: center;
color: #909399;
}
</style> </style>

View File

@ -1,35 +1,33 @@
<template> <template>
<el-form :model="localForm" label-width="160px" :disabled="readonly"> <el-form :model="localForm" label-width="160px" :disabled="readonly">
<el-row :gutter="20"> <div class="credit-evaluation">
<el-col :span="12"> <h3>信用评级</h3>
<el-form-item label="信用评价"> <el-form-item label="信用评价">
<el-rate v-model="localForm.creditRating" allow-half show-score score-template="{value} 分" /> <el-rate v-model="localForm.creditEvaluation" allow-half show-score score-template="{value} 分" />
</el-form-item> </el-form-item>
<el-form-item label="带动周边农户"> <el-form-item label="带动周边农户">
<el-rate v-model="localForm.farmersSupport" allow-half show-score score-template="{value} 分" /> <el-rate v-model="localForm.supportedFarmers" allow-half show-score score-template="{value} 分" />
</el-form-item> </el-form-item>
<el-form-item label="社会效益"> <el-form-item label="社会效益">
<el-rate v-model="localForm.socialBenefit" allow-half show-score score-template="{value} 分" /> <el-rate v-model="localForm.socialImpact" allow-half show-score score-template="{value} 分" />
</el-form-item> </el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="高新技术应用"> <el-form-item label="高新技术应用">
<el-rate v-model="localForm.techApplication" allow-half show-score score-template="{value} 分" /> <el-rate v-model="localForm.techApplication" allow-half show-score score-template="{value} 分" />
</el-form-item> </el-form-item>
<el-form-item label="产品质量及服务保障"> <el-form-item label="产品质量及服务保障">
<el-rate v-model="localForm.qualityService" allow-half show-score score-template="{value} 分" /> <el-rate v-model="localForm.productQuality" allow-half show-score score-template="{value} 分" />
</el-form-item> </el-form-item>
</el-col> </div>
</el-row>
</el-form> </el-form>
</template> </template>
<script setup> <script setup>
import { reactive, watch } from 'vue'; import { reactive, watch } from 'vue';
import cloneDeep from 'lodash/cloneDeep';
const props = defineProps({ const props = defineProps({
modelValue: { modelValue: {
@ -42,13 +40,43 @@ const props = defineProps({
const emit = defineEmits(['update:modelValue']); const emit = defineEmits(['update:modelValue']);
const localForm = reactive({ ...props.modelValue }); const localForm = reactive(cloneDeep(props.modelValue));
watch( watch(
localForm, localForm,
(val) => { (newVal) => {
emit('update:modelValue', { ...val }); emit('update:modelValue', { ...newVal });
},
{ deep: true }
);
watch(
() => props.modelValue,
(newVal) => {
Object.assign(localForm, cloneDeep(newVal));
}, },
{ deep: true } { deep: true }
); );
</script> </script>
<style scoped lang="scss">
.credit-evaluation {
width: 600px;
margin: 0 auto;
display: flex;
flex-direction: column;
gap: 20px;
.el-rate {
font-size: 16px;
color: #f90;
}
}
h3 {
margin-top: 20px;
margin-bottom: 20px;
font-size: 16px;
font-weight: 500;
color: #333333;
width: 110px;
text-align: right;
}
</style>

View File

@ -0,0 +1,323 @@
<template>
<div>
<avue-crud ref="crudRef" v-model:page="pageData" :data="crudData" :option="crudOptions" :table-loading="loading">
<template #menu-left>
<el-button type="primary" icon="Plus" @click="handleAdd">新增</el-button>
</template>
<template #menu="scope">
<custom-table-operate :actions="crudOptions.actions" :data="scope" />
</template>
</avue-crud>
<el-dialog :key="dialogTitle" v-model="dialogVisible" :title="dialogTitle" width="80%">
<el-form :model="formData" label-width="120px" class="custom-form" :disabled="isReadonly">
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="姓名" prop="name">
<el-input v-model="formData.name" placeholder="请输入姓名" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="证件类型" prop="idType">
<el-select v-model="formData.idType" placeholder="请选择证件类型" disabled>
<el-option label="身份证" value="101" />
<el-option label="护照" value="2" />
<el-option label="港澳身份证" value="3" />
</el-select>
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="证件号码" prop="idCard">
<el-input v-model="formData.idCard" placeholder="请输入证件号码" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="性别" prop="sex">
<el-radio-group v-model="formData.sex">
<el-radio label="1"></el-radio>
<el-radio label="0"></el-radio>
</el-radio-group>
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="年龄" prop="age">
<el-input v-model="formData.age" placeholder="请输入年龄" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="联系方式" prop="phone">
<el-input v-model="formData.phone" placeholder="请输入联系方式" />
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="居住地行政区划" prop="addressArr">
<area-select v-model="formData.addressArr" :label="null" />
<!-- <el-input v-model="formData.detailAddress" placeholder="请选择居住地行政区划" /> -->
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="具体地址" prop="detailAddress">
<el-input v-model="formData.detailAddress" placeholder="请输入具体地址" />
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="种植面积" prop="area">
<el-input v-model="formData.area" placeholder="请输入种植面积" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="种植作物" prop="planCrop">
<!-- <el-select v-model="formData.planCrop" placeholder="种植作物" style="width: 380px" :clearable="true">
<el-option v-for="item in cropsOptions" :key="item.id" :label="item.cropsName" :value="item.id" />
</el-select> -->
<url-select
v-model="formData.planCrop"
url="/land-resource/crops/page"
:params="{ status: '0' }"
label-key="cropsName"
value-key="id"
placeholder="请选择种植作物"
/>
</el-form-item>
</el-col>
</el-row>
</el-form>
<template #footer>
<div class="dialog-footer">
<el-button @click="dialogVisible = false">取消</el-button>
<el-button v-if="!isReadonly" type="primary" @click="handleSave">保存</el-button>
</div>
</template>
</el-dialog>
</div>
</template>
<script setup>
import { ref, reactive, watch, onMounted, computed } from 'vue';
import { CRUD_OPTIONS } from '@/config';
import { ElMessageBox, ElMessage } from 'element-plus';
import { getMemberList, addMember, updateMember, deleteMembers } from '@/apis/businessEntity';
const dialogTitle = ref('新增');
const dialogVisible = ref(false);
const isReadonly = ref(false);
const loading = ref(false);
const crudRef = ref();
//
const pageData = ref({
currentPage: 1,
pageSize: 10,
total: 0,
});
const searchForm = ref({
entId: '',
userId: '',
});
const crudData = ref([]);
//
const defaultFormData = {
id: '',
entId: '',
name: '',
idType: '101',
idCard: '',
sex: '1',
age: '',
phone: '',
provinceCode: '', //
cityCode: '', //
countyCode: '', //
townCode: '', //
street: '', //
addressArr: [],
detailAddress: '',
area: '',
planCrop: '',
planCropName: '',
address: '',
createTime: '',
createUser: '',
updateTime: '',
updateUser: '',
};
// 使
const formData = ref({ ...defaultFormData });
const resetForm = () => {
formData.value = { ...defaultFormData };
};
const crudOptions = reactive({
...CRUD_OPTIONS,
addBtn: false,
searchBtn: false,
emptyBtn: false,
refreshBtn: false,
column: [
{ label: '姓名', prop: 'name' },
{
label: '证件类型',
prop: 'idType',
formatter: (row, column, cellValue) => {
return cellValue === '101' ? '身份证' : cellValue === '2' ? '护照' : cellValue === '3' ? '港澳身份证' : '';
},
},
{ label: '证件号码', prop: 'idCardEncrypt' },
{
label: '性别',
prop: 'sex',
formatter: (row, column, cellValue) => {
return cellValue === '1' ? '男' : cellValue === '0' ? '女' : '';
},
},
{ label: '年龄', prop: 'age' },
{ label: '联系方式', prop: 'phone' },
{ label: '居住地行政区划', prop: 'address' },
{ label: '种植作物', prop: 'planCrop' },
],
actions: [
{
name: '查看',
icon: 'view',
event: ({ row }) => handleView(row),
},
{
name: '编辑',
icon: 'edit',
event: ({ row }) => handleEdit(row),
},
{
type: 'danger',
name: '删除',
icon: 'delete',
event: ({ row }) => handleDelete(row),
},
],
});
async function getData() {
loading.value = true;
try {
const params = {
...searchForm.value,
current: pageData.value.currentPage,
size: pageData.value.pageSize,
};
const response = await getMemberList(params);
if (response.code === 200 && response.data) {
crudData.value = response.data.records;
console.log('获取数据成功:', crudData.value);
pageData.value = {
currentPage: response.data.current,
pageSize: response.data.size,
total: response.data.total,
};
} else {
ElMessage.error(response.msg || '获取数据失败');
}
} catch (error) {
ElMessage.error('获取数据失败,请稍后重试');
} finally {
loading.value = false;
}
}
onMounted(() => {
getData();
});
const handleSave = async () => {
try {
let response;
if (dialogTitle.value === '新增') {
// saveFarmerList
response = await addMember(formData.value);
if (response.code === 200) {
ElMessage.success('新增成功');
}
} else if (dialogTitle.value === '编辑') {
// editFarmer
response = await updateMember(formData.value);
if (response.code === 200) {
ElMessage.success('编辑成功');
}
}
if (response && response.code === 200) {
dialogVisible.value = false;
getData(); //
}
} catch (error) {
if (dialogTitle.value === '新增') {
ElMessage.error('新增失败,请稍后重试');
} else {
ElMessage.error('编辑失败,请稍后重试');
}
}
};
watch(
() => formData.value.addressArr,
(newValue) => {
if (newValue.length <= 3) {
formData.value.provinceCode = '530000';
formData.value.cityCode = '530900';
formData.value.countyCode = newValue[0];
formData.value.townCode = newValue[1];
formData.value.street = newValue[2];
}
}
);
const handleAdd = () => {
isReadonly.value = false; //
resetForm();
dialogTitle.value = '新增';
dialogVisible.value = true;
};
function handleView(row) {
console.log('查看', row);
dialogTitle.value = '查看';
isReadonly.value = true; //
dialogVisible.value = true;
const addressArr = [row.countyCode, row.townCode, row.street].filter(Boolean);
formData.value = {
...row,
addressArr,
};
//
}
async function handleEdit(row) {
dialogTitle.value = '编辑';
isReadonly.value = false;
dialogVisible.value = true;
const addressArr = [row.countyCode, row.townCode, row.street].filter(Boolean);
formData.value = {
...row,
addressArr,
};
}
async function handleDelete(row) {
try {
await ElMessageBox.confirm('确定删除该条记录?', '删除提示');
console.log(`删除 ID=${row.id}`);
await deleteMembers(row.id); // ID
await getData();
ElMessage.success('已删除');
} catch (error) {
if (error !== 'cancel') {
ElMessage.error(`删除失败: ${error.message || '请稍后重试'}`);
}
}
}
</script>
<style scoped lang="scss"></style>

View File

@ -1,46 +1,58 @@
<template> <template>
<el-form :model="localForm" label-width="150px" :disabled="readonly"> <el-form :model="localForm" label-width="150px" :disabled="readonly">
<h3>登记注册信息</h3>
<el-row :gutter="20"> <el-row :gutter="20">
<!-- 左列 --> <!-- 左列 -->
<el-col :span="12"> <el-col :span="12">
<el-form-item label="企业名称"> <el-form-item label="企业名称">
<el-input v-model="localForm.companyName" placeholder="请输入" /> <el-input v-model="localForm.businessName" placeholder="请输入" />
</el-form-item> </el-form-item>
<el-form-item label="法定代表人"> <el-form-item label="法定代表人">
<el-input v-model="localForm.legalPerson" placeholder="请输入" /> <el-input v-model="localForm.legalRep" placeholder="请输入" />
</el-form-item> </el-form-item>
<el-form-item label="企业类型"> <el-form-item label="企业类型">
<el-select v-model="localForm.companyType" placeholder="请选择"> <el-select v-model="localForm.comType" placeholder="请选择">
<el-option label="农民专业合作社" value="农民专业合作社" /> <el-option label="农民专业合作社" value="农民专业合作社" />
<el-option label="农业公司" value="农业公司" /> <el-option label="农业公司" value="农业公司" />
<el-option label="个体工商户" value="个体工商户" /> <el-option label="个体工商户" value="个体工商户" />
</el-select> </el-select>
</el-form-item> </el-form-item>
<el-form-item label="登记机关"> <el-form-item label="登记机关">
<el-input v-model="localForm.registerOrg" placeholder="请输入" /> <el-input v-model="localForm.regAuthority" placeholder="请输入" />
</el-form-item> </el-form-item>
<el-form-item label="核准日期"> <el-form-item label="核准日期">
<el-date-picker v-model="localForm.approvalDate" type="date" placeholder="请选择" format="YYYY年MM月DD日" value-format="YYYY-MM-DD" /> <el-date-picker
</el-form-item> v-model="localForm.approveDate"
<el-form-item label="经营范围"> style="width: 100%"
<el-input v-model="localForm.businessScope" type="textarea" placeholder="请输入" :rows="4" /> type="date"
placeholder="请选择"
format="YYYY年MM月DD日"
value-format="YYYY-MM-DD"
/>
</el-form-item> </el-form-item>
</el-col> </el-col>
<!-- 右列 --> <!-- 右列 -->
<el-col :span="12"> <el-col :span="12">
<el-form-item label="统一社会信用代码"> <el-form-item label="统一社会信用代码">
<el-input v-model="localForm.creditCode" placeholder="请输入" /> <el-input v-model="localForm.uscc" placeholder="请输入" />
</el-form-item> </el-form-item>
<el-form-item label="登记状态"> <el-form-item label="登记状态">
<el-select v-model="localForm.registerStatus" placeholder="请选择"> <el-select v-model="localForm.registrationStatus" placeholder="请选择">
<el-option label="存续" value="存续" /> <el-option label="存续" value="存续" />
<el-option label="注销" value="注销" /> <el-option label="注销" value="注销" />
<el-option label="吊销" value="吊销" /> <el-option label="吊销" value="吊销" />
</el-select> </el-select>
</el-form-item> </el-form-item>
<el-form-item label="成立日期"> <el-form-item label="成立日期">
<el-date-picker v-model="localForm.establishDate" type="date" placeholder="请选择" format="YYYY年MM月DD日" value-format="YYYY-MM-DD" /> <el-date-picker
v-model="localForm.estDate"
style="width: 100%"
type="date"
placeholder="请选择"
format="YYYY年MM月DD日"
value-format="YYYY-MM-DD"
/>
</el-form-item> </el-form-item>
<el-form-item label="成员出资总额"> <el-form-item label="成员出资总额">
<el-input v-model="localForm.totalCapital" placeholder="请输入" /> <el-input v-model="localForm.totalCapital" placeholder="请输入" />
@ -49,12 +61,18 @@
<el-input v-model="localForm.address" placeholder="请输入" /> <el-input v-model="localForm.address" placeholder="请输入" />
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col :span="24">
<el-form-item label="经营范围">
<el-input v-model="localForm.businessScope" type="businessScope" placeholder="请输入" :rows="4" />
</el-form-item>
</el-col>
</el-row> </el-row>
</el-form> </el-form>
</template> </template>
<script setup> <script setup>
import { reactive, watch } from 'vue'; import { reactive, watch } from 'vue';
import cloneDeep from 'lodash/cloneDeep';
const props = defineProps({ const props = defineProps({
modelValue: { modelValue: {
@ -68,7 +86,7 @@ const props = defineProps({
const emit = defineEmits(['update:modelValue']); const emit = defineEmits(['update:modelValue']);
// props // props
const localForm = reactive({ ...props.modelValue }); const localForm = reactive(cloneDeep(props.modelValue));
// //
watch( watch(
@ -78,4 +96,23 @@ watch(
}, },
{ deep: true } { deep: true }
); );
watch(
() => props.modelValue,
(newVal) => {
Object.assign(localForm, cloneDeep(newVal));
},
{ deep: true }
);
</script> </script>
<style scoped lang="scss">
h3 {
margin-top: 20px;
margin-bottom: 20px;
font-size: 16px;
font-weight: 500;
color: #333333;
width: 110px;
text-align: right;
}
</style>

View File

@ -1,35 +1,47 @@
<template> <template>
<section class="custom-page"> <section class="custom-page">
<!-- 四个固定 Tabs -->
<el-tabs v-model="activeCrudTab" @tab-click="handleTabChange">
<el-tab-pane label="待提交" name="0" />
<el-tab-pane label="待审核" name="1" />
<el-tab-pane label="已通过" name="2" />
<el-tab-pane label="已驳回" name="3" />
</el-tabs>
<!-- 表格 -->
<avue-crud ref="crudRef" v-model:page="pageData" :data="crudData" :option="crudOptions" :table-loading="loading"> <avue-crud ref="crudRef" v-model:page="pageData" :data="crudData" :option="crudOptions" :table-loading="loading">
<template v-if="activeCrudTab === '0'" #menu-left>
<el-button type="primary" icon="Plus" @click="handleAdd">新增</el-button>
</template>
<template #menu="scope"> <template #menu="scope">
<custom-table-operate :actions="crudOptions.actions" :data="scope" /> <custom-table-operate :actions="crudOptions.actions" :data="scope" />
</template> </template>
</avue-crud> </avue-crud>
<el-dialog v-model="visible" title="农企合作社详情" width="80%" :draggable="true"> <el-dialog :key="dialogTitle" v-model="visible" :title="dialogTitle" width="60%" align-center :draggable="true">
<el-tabs v-model="activeTab" class="tabs-wrapper"> <el-tabs v-model="activeTab" class="tabs-wrapper">
<el-tab-pane label="1. 基础信息" name="basic"> <el-tab-pane label="基础信息" name="basic">
<TabBasicInfo v-model="formData.basicInfo" :readonly="isReadonly" /> <TabBasicInfo v-model="formData" :readonly="isReadonly" />
</el-tab-pane> </el-tab-pane>
<el-tab-pane label="2. 登记注册信息" name="register"> <el-tab-pane label="登记注册信息" name="register">
<TabRegister v-model="formData.registerInfo" /> <TabRegister v-model="formData" />
</el-tab-pane> </el-tab-pane>
<el-tab-pane label="3. 经营信息" name="business"> <el-tab-pane label="经营信息" name="business">
<TabBusinessInfo <TabBusinessInfo v-model="formData" :readonly="isReadonly" />
v-model="formData.business"
:readonly="isReadonly"
@prev="activeTab = 'register'"
@next="handleNext"
@edit="isReadonly = false"
/>
</el-tab-pane> </el-tab-pane>
<el-tab-pane label="4. 信用评级" name="credit"> <el-tab-pane label="信用评级" name="credit">
<TabCreditEvaluation v-model="formData.credit" :readonly="isReadonly" /> <TabCreditEvaluation v-model="formData" :readonly="isReadonly" />
</el-tab-pane>
<el-tab-pane v-if="dialogTitle === '查看'" label="职工/社员管理" name="employee">
<TabMember :readonly="isReadonly" />
</el-tab-pane> </el-tab-pane>
</el-tabs> </el-tabs>
<template #footer> <template v-if="dialogTitle !== '查看'" #footer>
<el-button @click="visible = false">关闭</el-button> <el-button v-if="!isFirstTab" type="primary" @click="handlePrev">上一步</el-button>
<el-button v-if="!isReadonly" type="primary" @click="handleSubmit">保存</el-button> <el-button v-if="!isLastTab" type="primary" @click="handleNext">下一步</el-button>
<el-button v-if="!isFirstTab && !isLastTab" type="info" @click="handleSkip">跳过</el-button>
<el-button v-if="isLastTab" type="primary" @click="handleSubmit">保存</el-button>
<el-button v-if="isLastTab" type="info" @click="handleSkipSave">跳过并保存</el-button>
</template> </template>
</el-dialog> </el-dialog>
</section> </section>
@ -43,65 +55,86 @@ import TabBasicInfo from './components/TabBasicInfo.vue';
import TabRegister from './components/TabRegister.vue'; import TabRegister from './components/TabRegister.vue';
import TabBusinessInfo from './components/TabBusinessInfo.vue'; import TabBusinessInfo from './components/TabBusinessInfo.vue';
import TabCreditEvaluation from './components/TabCreditEvaluation.vue'; import TabCreditEvaluation from './components/TabCreditEvaluation.vue';
import { getEnterList } from '@/apis/businessEntity'; import TabMember from './components/TabMember.vue';
import { getEnterList, getEnterById, addEnter, updateEnter, approvalEnter, deleteEnter } from '@/apis/businessEntity';
import { cloneDeep } from 'lodash';
// //
const visible = ref(false); const visible = ref(false);
// tab const activeCrudTab = ref('0');
const activeTab = ref('basic'); const activeTab = ref('basic');
const dialogTitle = ref('新增');
const isReadonly = ref(false);
//
const searchForm = ref({
businessName: '',
uscc: '',
productType: '',
primaryProduct: '',
});
// //
const formData = ref({ const formData = ref({
// id: '',
basicInfo: { // basicInfo
name: '', businessName: '',
area: '', area: '',
contactPerson: '', contactPerson: '',
address: [], cooperativePhoto: '', //
product: '', addressArr: [],
primaryProduct: '',
phone: '', phone: '',
photoUrl: '', businessLicence: '', //
businessLicenseUrl: '', provinceCode: '',
}, cityCode: '',
// countyCode: '',
registerInfo: { townCode: '',
companyName: '', villageCode: '',
legalPerson: '', // registerInfo
companyType: '', // businessName: '',
registerOrg: '', legalRep: '',
approvalDate: '', comType: '',
creditCode: '', regAuthority: '',
registerStatus: '', approveDate: '',
establishDate: '', uscc: '',
registrationStatus: '',
estDate: '',
totalCapital: '', totalCapital: '',
address: '', address: '',
businessScope: '', businessScope: '',
}, //
business: {
debtFiles: [], debtFiles: [],
profitFiles: [], profitFiles: [],
cashflowFiles: [], cashflowFiles: [],
}, //
credit: { creditEvaluation: 5,
creditRating: 5, supportedFarmers: 4,
farmersSupport: 4, socialImpact: 3,
socialBenefit: 3,
techApplication: 2, techApplication: 2,
qualityService: 1, productQuality: 1,
},
}); });
//
const isReadonly = ref(false);
// //
const handleSubmit = async () => { const handleSubmit = async () => {
try { try {
loading.value = true; loading.value = true;
// ID formData.value.id let response;
await api.updateById(formData.value.id, formData.value); if (dialogTitle.value === '新增') {
ElMessage.success('保存成功'); formData.value.id = '';
response = await addEnter(formData.value);
if (response.code === 200) {
ElMessage.success('新增成功');
visible.value = false; visible.value = false;
getData(); //
}
} else if (dialogTitle.value === '编辑') {
response = await updateEnter(formData.value);
if (response.code === 200) {
ElMessage.success('编辑成功');
visible.value = false;
getData(); //
}
}
// //
} catch (e) { } catch (e) {
ElMessage.error('保存失败'); ElMessage.error('保存失败');
@ -116,68 +149,7 @@ const pageData = ref({
total: 0, total: 0,
}); });
const crudData = ref([ const crudData = ref([]);
{
cooperativeName: '华祥种植专业合作社',
location: '耿马县/耿马镇/新城村',
area: '300亩',
products: '小葱、大白菜',
contactPerson: '张强',
contactPhone: '13384041642',
employeeCount: '50人',
status: '待审核',
createTime: '2024年8月21日16:20:41',
updateTime: '2024年8月21日16:20:51',
},
{
cooperativeName: '春林农业合作社',
location: '耿马县/耿马镇/和平村',
area: '200亩',
products: '西红柿、黄瓜',
contactPerson: '李梅',
contactPhone: '13812345678',
employeeCount: '30人',
status: '审核通过',
createTime: '2024年7月15日09:30:12',
updateTime: '2024年7月15日10:02:00',
},
{
cooperativeName: '绿源蔬菜种植基地',
location: '耿马县/芒洪乡/新村',
area: '150亩',
products: '辣椒、豆角',
contactPerson: '王伟',
contactPhone: '13987654321',
employeeCount: '25人',
status: '待审核',
createTime: '2024年9月01日14:45:20',
updateTime: '2024年9月01日14:46:30',
},
{
cooperativeName: '金丰农作物专业合作社',
location: '耿马县/勐简乡/丰收村',
area: '400亩',
products: '玉米、大豆',
contactPerson: '赵敏',
contactPhone: '13699887766',
employeeCount: '60人',
status: '待审核',
createTime: '2024年6月10日08:10:50',
updateTime: '2024年6月10日08:12:20',
},
{
cooperativeName: '恒泰水果种植农场',
location: '耿马县/勐永镇/红星村',
area: '500亩',
products: '香蕉、芒果',
contactPerson: '周强',
contactPhone: '13711223344',
employeeCount: '80人',
status: '审核不通过',
createTime: '2024年5月25日11:20:15',
updateTime: '2024年5月25日11:22:00',
},
]);
const loading = ref(false); const loading = ref(false);
@ -187,13 +159,13 @@ const crudOptions = reactive({
searchBtn: false, searchBtn: false,
emptyBtn: false, emptyBtn: false,
column: [ column: [
{ label: '农企/合作社名称', prop: 'cooperativeName' }, { label: '农企/合作社名称', prop: 'businessName' },
{ label: '地点', prop: 'location' }, { label: '地点', prop: 'regAddress' },
{ label: '面积', prop: 'area' }, { label: '面积', prop: 'area' },
{ label: '经营产品', prop: 'products' }, { label: '经营产品', prop: 'businessScope' },
{ label: '联系人', prop: 'contactPerson' }, { label: '联系人', prop: 'contactPerson' },
{ label: '联系电话', prop: 'contactPhone' }, { label: '联系电话', prop: 'phone' },
{ label: '聘工人数', prop: 'employeeCount' }, { label: '聘工人数', prop: 'villageCount' },
{ label: '状态', prop: 'status' }, { label: '状态', prop: 'status' },
{ label: '信息录入时间', prop: 'createTime' }, { label: '信息录入时间', prop: 'createTime' },
{ label: '信息更新时间', prop: 'updateTime' }, { label: '信息更新时间', prop: 'updateTime' },
@ -215,16 +187,94 @@ const crudOptions = reactive({
icon: 'delete', icon: 'delete',
event: ({ row }) => handleDelete(row.id), event: ({ row }) => handleDelete(row.id),
}, },
// showRejectReason
{
name: '驳回原因',
icon: 'warning',
event: ({ row }) => {
showRejectReason(row);
},
},
// handleSubmit
{
name: '提交审核',
icon: 'check',
event: ({ row }) => {
if (row.status === '待提交') {
handleSubmit();
} else {
ElMessage.warning('当前状态不允许提交审核');
}
},
},
// handleWithdraw
{
name: '撤销',
icon: 'undo',
event: ({ row }) => {
handleWithdraw(row);
},
},
// handleResubmit
{
name: '重新提交',
icon: 'resubmit',
event: (row) => {
handleResubmit(row);
},
},
// handleApprove
{
name: '通过',
icon: 'check-circle',
event: ({ row }) => {
handleApprove(row);
},
},
// handleReject
{
name: '驳回',
icon: 'close-circle',
event: ({ row }) => {
handleReject(row);
},
},
], ],
}); });
// watch(
// () => formData.value.addressArr,
// (newValue) => {
// if (newValue.length === 5) {
// formData.value.provinceCode = newValue[0] || '';
// formData.value.cityCode = newValue[1] || '';
// formData.value.countyCode = newValue[2] || '';
// formData.value.townCode = newValue[3] || '';
// formData.value.villageCode = newValue[4] || '';
// } else {
// ElMessageBox.alert('');
// }
// }
// );
onMounted(() => {
getData();
});
//
const getData = async () => { const getData = async () => {
loading.value = true; loading.value = true;
try { try {
const response = await getEnterList(pageData.value.currentPage, pageData.value.pageSize); const response = await getEnterList({
crudData.value = response.data; ...searchForm.value,
pageData.value.total = response.total; status: activeCrudTab.value,
page: pageData.value.currentPage,
size: pageData.value.pageSize,
});
console.log('response', response);
crudData.value = response.data.records;
pageData.value.total = response.data.total;
pageData.value.currentPage = response.data.current;
pageData.value.pageSize = response.data.size;
} catch (error) { } catch (error) {
ElMessage.error('加载数据失败'); ElMessage.error('加载数据失败');
} finally { } finally {
@ -232,12 +282,72 @@ const getData = async () => {
} }
}; };
const getEnterDetail = async (id) => {
try {
const response = await getEnterById(id);
if (response?.code === 200 && response.data) {
// 使
formData.value = {
...cloneDeep(response.data),
// addressArr5
addressArr: [
response.data.provinceCode || '',
response.data.cityCode || '',
response.data.countyCode || '',
response.data.townCode || '',
response.data.villageCode || '',
],
};
// //
// if (response.data.cooperativePhoto) {
// cooperativePhotoList.value = [
// {
// name: '',
// url: response.data.cooperativePhoto,
// status: 'success',
// },
// ];
// }
// if (response.data.businessLicence) {
// businessLicenceList.value = [
// {
// name: '',
// url: response.data.businessLicence,
// status: 'success',
// },
// ];
// }
console.log('详情数据加载完成', formData.value);
} else {
ElMessage.error(response?.msg || '获取详情失败:服务器未返回有效数据');
}
} catch (error) {
console.error('获取详情失败:', error);
ElMessage.error(`获取详情失败:${error.message || '请稍后重试'}`);
}
};
function handleSearch() {
getData();
}
function handleTabChange(tab) {
handleSearch();
}
const handleAdd = () => {
isReadonly.value = false;
// resetForm();
dialogTitle.value = '新增';
visible.value = true;
};
// //
const handleView = async (row) => { const handleView = async (row) => {
loading.value = true; loading.value = true;
dialogTitle.value = '查看';
formData.value = null;
try { try {
const data = await api.getDetailById(row.id); await getEnterDetail(row.id);
formData.value = data;
isReadonly.value = true; isReadonly.value = true;
activeTab.value = 'basic'; activeTab.value = 'basic';
visible.value = true; visible.value = true;
@ -249,9 +359,9 @@ const handleView = async (row) => {
// //
const handleEdit = async (row) => { const handleEdit = async (row) => {
loading.value = true; loading.value = true;
dialogTitle.value = '编辑';
try { try {
const data = await api.getDetailById(row.id); await getEnterById(row.id);
formData.value = data;
isReadonly.value = false; isReadonly.value = false;
activeTab.value = 'basic'; activeTab.value = 'basic';
visible.value = true; visible.value = true;
@ -259,7 +369,106 @@ const handleEdit = async (row) => {
loading.value = false; loading.value = false;
} }
}; };
//
function handleResubmit(row) {
ElMessageBox.confirm('确认重新提交吗?', '重新提交').then(() => {
const params = {
id: row.id,
status: '1', //
reason: '重新提交审核',
};
approvalEnter(params)
.then(() => {
console.log(`ID=${row.id} 重新提交审核`);
row.status = '1';
row.rejectReason = '';
getData();
ElMessage.success('已重新提交,状态已变为"待审核"');
})
.catch((error) => {
console.error('重新提交失败:', error);
ElMessage.error(error.response?.data?.msg || '重新提交失败');
});
});
}
//
function handleWithdraw(row) {
ElMessageBox.confirm('确认撤销本次审核吗?', '撤销').then(() => {
const params = {
id: row.id,
status: '0', //
reason: '用户主动撤销',
};
approvalEnter(params)
.then(() => {
console.log(`ID=${row.id} 撤销审核`);
row.status = '0';
getData();
ElMessage.success('已撤销,状态已变为"待提交"');
})
.catch((error) => {
console.error('撤销失败:', error);
ElMessage.error(error.response?.data?.msg || '撤销失败');
});
});
}
//
function handleApprove(row) {
ElMessageBox.confirm('确认通过审核?', '审核通过').then(() => {
const params = {
id: row.id,
status: '2', //
reason: '审核通过',
};
approvalEnter(params)
.then(() => {
console.log(`ID=${row.id} 审核通过`);
row.status = '2';
getData();
ElMessage.success('审核已通过');
})
.catch((error) => {
console.error('审核通过操作失败:', error);
ElMessage.error(error.response?.data?.msg || '审核操作失败');
});
});
}
//
function handleReject(row) {
ElMessageBox.prompt('请输入驳回原因', '审核驳回', {
confirmButtonText: '确定',
cancelButtonText: '取消',
inputPattern: /.+/, //
inputErrorMessage: '驳回原因不能为空',
})
.then(({ value }) => {
const params = {
id: row.id,
status: '3', //
reason: value.trim(),
};
return approvalEnter(params).then(() => {
console.log(`ID=${row.id} 驳回,原因:${value.trim()}`);
row.status = '3';
row.rejectReason = value.trim();
getData();
ElMessage.success('已驳回');
});
})
.catch((error) => {
if (error !== 'cancel') {
console.error('驳回操作失败:', error);
ElMessage.error(error.response?.data?.msg || '驳回操作失败');
}
});
}
// /
function showRejectReason(row) {
ElMessageBox.alert(row.reason || '无驳回原因', '驳回原因');
}
// //
const handleDelete = async (id) => { const handleDelete = async (id) => {
try { try {
@ -267,9 +476,13 @@ const handleDelete = async (id) => {
type: 'warning', type: 'warning',
}); });
loading.value = true; loading.value = true;
await api.deleteById(id); const res = await deleteEnter(id);
if (res.code === 200) {
ElMessage.success('删除成功'); ElMessage.success('删除成功');
// getData(); //
} else {
ElMessage.error(res.msg || '删除失败');
}
} catch (e) { } catch (e) {
if (e !== 'cancel') { if (e !== 'cancel') {
ElMessage.error('删除失败'); ElMessage.error('删除失败');
@ -278,63 +491,35 @@ const handleDelete = async (id) => {
loading.value = false; loading.value = false;
} }
}; };
// tabs
const tabOrder = ['basic', 'register', 'business', 'credit'];
// API const currentTabIndex = computed(() => tabOrder.indexOf(activeTab.value));
const api = { const isFirstTab = computed(() => currentTabIndex.value === 0);
// const isLastTab = computed(() => currentTabIndex.value === tabOrder.length - 1);
getDetailById: async (id) => { /** 跳转到下一 Tab */
// formData function handleNext() {
return { if (currentTabIndex.value < tabOrder.length - 1) {
basicInfo: { activeTab.value = tabOrder[currentTabIndex.value + 1];
name: '绿源蔬菜种植基地', }
area: '150亩', }
contactPerson: '王伟',
address: ['耿马县', '芒洪乡', '新村'],
product: '辣椒、豆角',
phone: '13987654321',
photoUrl: '',
businessLicenseUrl: '',
},
registerInfo: {
companyName: '绿源蔬菜种植基地',
legalPerson: '王伟',
companyType: '合作社',
registerOrg: '耿马县工商局',
approvalDate: '2022-03-01',
creditCode: '123456789000000000',
registerStatus: '存续',
establishDate: '2020-01-01',
totalCapital: '200万',
address: '耿马县芒洪乡新村',
businessScope: '蔬菜种植销售',
},
business: {
debtFiles: [],
profitFiles: [],
cashflowFiles: [],
},
credit: {
creditRating: 4,
farmersSupport: 3,
socialBenefit: 4,
techApplication: 3,
qualityService: 4,
},
};
},
// /** 跳转到上一 Tab */
updateById: async (id, data) => { function handlePrev() {
console.log('更新请求', id, data); if (currentTabIndex.value > 0) {
return true; activeTab.value = tabOrder[currentTabIndex.value - 1];
}, }
}
// /** 跳过当前步骤 */
deleteById: async (id) => { function handleSkip() {
console.log('删除请求', id); handleNext();
return true; }
}, /** 跳过并保存 */
}; function handleSkipSave() {
handleSkip();
handleSubmit();
}
</script> </script>
<style scoped lang="scss"> <style scoped lang="scss">
@ -342,12 +527,29 @@ const api = {
width: 100%; width: 100%;
display: flex; display: flex;
align-items: center; align-items: center;
background-color: #fff; // background-color: #7daaaa;
:deep(.el-tabs__item) { :deep(.el-tabs__item) {
font-size: 24px; font-size: 16px;
font-weight: 700; color: #555555;
font-weight: 500;
// border: 1 solid #f000; // border: 1 solid #f000;
} }
:deep(.el-tabs__content) {
padding: 20px;
width: 100%;
// background-color: #f5f5f5;
border-radius: 4px;
height: calc(100vh - 300px);
overflow-y: auto;
}
:deep(.el-tab-pane) {
margin: 0 auto;
width: 80%;
}
:deep(.el-tab-pane:nth-child(5)) {
margin: 0 auto;
width: 100%;
}
} }
</style> </style>

View File

@ -20,7 +20,7 @@
</el-tabs> </el-tabs>
<!-- 表格 --> <!-- 表格 -->
<avue-crud ref="crudRef" v-model:page="pageData" :data="filteredData" :option="crudOptions" :table-loading="loading"> <avue-crud ref="crudRef" v-model:page="pageData" :data="crudData" :option="crudOptions" :table-loading="loading">
<template v-if="activeTab === '0'" #menu-left> <template v-if="activeTab === '0'" #menu-left>
<el-button type="primary" icon="Plus" @click="handleAdd">新增</el-button> <el-button type="primary" icon="Plus" @click="handleAdd">新增</el-button>
</template> </template>
@ -30,7 +30,7 @@
</avue-crud> </avue-crud>
<!-- 新增弹窗 --> <!-- 新增弹窗 -->
<el-dialog :key="dialogTitle" v-model="dialogVisible" :title="dialogTitle" width="80%"> <el-dialog :key="dialogTitle" v-model="dialogVisible" :title="dialogTitle" width="80%" align-center :draggable="true">
<el-form :model="formData" label-width="120px" class="custom-form" :disabled="isReadonly"> <el-form :model="formData" label-width="120px" class="custom-form" :disabled="isReadonly">
<el-row :gutter="20"> <el-row :gutter="20">
<el-col :span="12"> <el-col :span="12">
@ -57,8 +57,8 @@
<el-col :span="12"> <el-col :span="12">
<el-form-item label="性别" prop="sex"> <el-form-item label="性别" prop="sex">
<el-radio-group v-model="formData.sex"> <el-radio-group v-model="formData.sex">
<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-col> </el-col>
@ -77,8 +77,8 @@
</el-row> </el-row>
<el-row :gutter="20"> <el-row :gutter="20">
<el-col :span="12"> <el-col :span="12">
<el-form-item label="居住地行政区划" prop="address"> <el-form-item label="居住地行政区划" prop="addressArr">
<area-select v-model="formData.address" :label="null" /> <area-select v-model="formData.addressArr" :label="null" />
<!-- <el-input v-model="formData.detailAddress" placeholder="请选择居住地行政区划" /> --> <!-- <el-input v-model="formData.detailAddress" placeholder="请选择居住地行政区划" /> -->
</el-form-item> </el-form-item>
</el-col> </el-col>
@ -122,7 +122,7 @@
</template> </template>
<script setup> <script setup>
import { ref, computed, reactive, onMounted, watch } from 'vue'; import { ref, computed, reactive, onMounted, watch, nextTick } from 'vue';
import { ElMessageBox, ElMessage } from 'element-plus'; import { ElMessageBox, ElMessage } from 'element-plus';
import { CRUD_OPTIONS } from '@/config'; import { CRUD_OPTIONS } from '@/config';
import { fetchFarmerList, fetchFarmerById, saveFarmerList, editFarmer, approveFarmer, deleteFarmers } from '@/apis/businessEntity'; import { fetchFarmerList, fetchFarmerById, saveFarmerList, editFarmer, approveFarmer, deleteFarmers } from '@/apis/businessEntity';
@ -161,7 +161,7 @@ const pageData = ref({
total: 0, total: 0,
}); });
// //
const allData = ref([]); const crudData = ref([]);
// //
const dialogVisible = ref(false); const dialogVisible = ref(false);
@ -177,8 +177,9 @@ const defaultFormData = {
cityCode: '', // cityCode: '', //
countyCode: '', // countyCode: '', //
townCode: '', // townCode: '', //
street: '', // villageCode: '', //
address: [], address: '',
addressArr: [],
detailAddress: '', detailAddress: '',
area: '', area: '',
planCrop: '', planCrop: '',
@ -192,20 +193,6 @@ const resetForm = () => {
formData.value = { ...defaultFormData }; formData.value = { ...defaultFormData };
}; };
// tab +
const filteredData = computed(() => {
return allData.value.filter((row) => {
//
if (String(row.status) !== activeTab.value) return false;
// //
const kw = searchForm.value.name.trim();
if (kw) {
return row.name.includes(kw) || row.idCard.includes(kw) || row.phone.includes(kw);
}
return true;
});
});
// ============================== // ==============================
// CRUD // CRUD
// ============================== // ==============================
@ -255,8 +242,8 @@ async function getData() {
}; };
const response = await fetchFarmerList(params); const response = await fetchFarmerList(params);
if (response.code === 200 && response.data) { if (response.code === 200 && response.data) {
allData.value = response.data.records; crudData.value = response.data.records;
console.log('获取数据成功:', allData.value); console.log('获取数据成功:', crudData.value);
pageData.value = { pageData.value = {
currentPage: response.data.current, currentPage: response.data.current,
pageSize: response.data.size, pageSize: response.data.size,
@ -288,9 +275,6 @@ const fetchCropsList = async () => {
} }
}; };
function handleSearch() { function handleSearch() {
// filteredData
// activeTab + keyword
console.log('搜索关键词:', searchForm.value.keyword);
getData(); getData();
} }
function handleReset() { function handleReset() {
@ -309,14 +293,16 @@ const handleAdd = () => {
}; };
// address // address
watch( watch(
() => formData.value.address, () => formData.value.addressArr,
(newValue) => { (newValue) => {
if (newValue.length <= 3) { if (newValue.length === 5) {
formData.value.provinceCode = '530000'; formData.value.provinceCode = newValue[0] || '';
formData.value.cityCode = '530900'; formData.value.cityCode = newValue[1] || '';
formData.value.countyCode = newValue[0]; formData.value.countyCode = newValue[2] || '';
formData.value.townCode = newValue[1]; formData.value.townCode = newValue[3] || '';
formData.value.street = newValue[2]; formData.value.villageCode = newValue[4] || '';
} else {
ElMessageBox.alert('行政区划数据错误');
} }
} }
); );
@ -326,6 +312,7 @@ const handleSave = async () => {
try { try {
let response; let response;
if (dialogTitle.value === '新增') { if (dialogTitle.value === '新增') {
console.log('新增formData.value.arr :>> ', formData.value.addressArr);
// saveFarmerList // saveFarmerList
response = await saveFarmerList(formData.value); response = await saveFarmerList(formData.value);
if (response.code === 200) { if (response.code === 200) {
@ -366,26 +353,29 @@ const getFarmerById = async (id) => {
} }
}; };
// //
function handleView(row) { async function handleView(row) {
console.log('查看', row); console.log('查看', row);
dialogTitle.value = '查看'; dialogTitle.value = '查看';
isReadonly.value = true; // isReadonly.value = true; //
dialogVisible.value = true;
getFarmerById(row.id).then((data) => { const data = await getFarmerById(row.id);
if (data) { if (data) {
const address = [data.countyCode, data.townCode, data.street].filter(Boolean); console.log('data :>> ', data);
const addressArr = [data.provinceCode, data.cityCode, data.countyCode, data.townCode, data.villageCode].filter(Boolean);
console.log('addressArr :>> ', addressArr);
formData.value = { formData.value = {
...data, ...data,
address, addressArr: addressArr,
}; };
} }
console.log('cc formData.value :>> ', formData.value.addressArr);
nextTick(() => {
dialogVisible.value = true;
}); });
//
} }
// / // /
async function handleEdit(row) { async function handleEdit(row) {
//
if (row.status === '2') { if (row.status === '2') {
try { try {
await ElMessageBox.confirm('编辑后数据将需要重新审核,是否继续?', '确认编辑', { await ElMessageBox.confirm('编辑后数据将需要重新审核,是否继续?', '确认编辑', {
@ -394,7 +384,7 @@ async function handleEdit(row) {
type: 'warning', type: 'warning',
}); });
} catch { } catch {
return; // return;
} }
} }
dialogTitle.value = '编辑'; dialogTitle.value = '编辑';
@ -402,10 +392,8 @@ async function handleEdit(row) {
dialogVisible.value = true; dialogVisible.value = true;
getFarmerById(row.id).then((data) => { getFarmerById(row.id).then((data) => {
if (data) { if (data) {
const address = [data.countyCode, data.townCode, data.street].filter(Boolean);
formData.value = { formData.value = {
...data, ...data,
address,
}; };
} }
}); });
@ -431,7 +419,6 @@ function handleSubmit(row) {
}); });
} }
//
// //
function handleResubmit(row) { function handleResubmit(row) {
ElMessageBox.confirm('确认重新提交吗?', '重新提交').then(() => { ElMessageBox.confirm('确认重新提交吗?', '重新提交').then(() => {
@ -601,7 +588,7 @@ function getActions(row) {
} }
// --------------------------------------------------------------------- // ---------------------------------------------------------------------
// 4. allData // 4. crudData
// --------------------------------------------------------------------- // ---------------------------------------------------------------------
onMounted(() => { onMounted(() => {
getData(); getData();
@ -622,6 +609,11 @@ onMounted(() => {
margin-bottom: 20px; margin-bottom: 20px;
} }
} }
:deep(.el-dialog__body) {
padding: 20px;
height: calc(100vh - 300px);
overflow-y: auto;
}
.custom-form { .custom-form {
padding: 20px; padding: 20px;

View File

@ -1,254 +0,0 @@
<template>
<div class="custom-page">
<avue-crud
ref="crudRef"
v-model="state.form"
v-model:page="state.pageData"
:table-loading="state.loading"
:data="state.data"
:option="state.options"
@refresh-change="refreshChange"
@selection-change="selectionChange"
@current-change="currentChange"
@size-change="sizeChange"
@row-save="rowSave"
@row-update="rowUpdate"
@row-del="rowDel"
>
<template #menu-left>
<!-- <el-button type="primary" icon="Upload" @click="onImport">导入</el-button> -->
<!-- <el-button type="danger" icon="Delete" @click="onBatchDel">批量删除</el-button> -->
</template>
<!-- <template #operationDate-search>
<el-date-picker v-model="timeVal" type="daterange" style="width: 230px" start-placeholder="开始" end-placeholder="结束" />
</template> -->
<template #menu="scope">
<custom-table-operate :actions="state.options.actions" :data="scope" />
</template>
</avue-crud>
</div>
</template>
<script setup>
import { reactive, ref } from 'vue';
import { useApp } from '@/hooks';
import { CRUD_OPTIONS } from '@/config';
import { isEmpty, downloadFile } from '@/utils';
import { useUserStore } from '@/store/modules/user';
import {
fetchBusinessSubjectList,
saveBusinessSubject,
editBusinessSubject,
deleteBusinessSubject,
fetchBusinessSubjectInfo,
} from '@/apis/businessEntity';
const { VITE_APP_BASE_API } = import.meta.env;
const app = useApp();
const UserStore = useUserStore();
const crudRef = ref(null);
const state = reactive({
loading: false,
query: { current: 1, size: 10, businessType: 0 },
form: {},
selection: [],
pageData: { currentPage: 1, pageSize: 10, total: 0 },
data: [],
options: {
...CRUD_OPTIONS,
addBtnText: '添加',
column: [
{ label: '主体代码', prop: 'id' },
{ label: '主体名称', prop: 'businessName' },
{
label: '经营产品种类',
prop: 'productType',
type: 'select',
dicData: [
{ label: '蔬菜', value: '0' },
{ label: '水果', value: '1' },
{ label: '畜产品', value: '2' },
{ label: '水产品', value: '3' },
{ label: '谷物', value: '4' },
{ label: '农资', value: '5' },
{ label: '种源', value: '6' },
{ label: '农产品加工', value: '7' },
{ label: '其他', value: '8' },
],
},
{ label: '主要经营产品', prop: 'primaryProduct' },
{ label: '户主身份证号', prop: 'idCard' },
{
label: '联系地址',
prop: 'address',
type: 'cascader',
props: { label: 'areaName', value: 'areaCode', children: 'areaChildVOS' },
dicUrl: `${VITE_APP_BASE_API}/system/area/region?areaCode=530000`,
dicHeaders: { authorization: UserStore.token },
},
{ label: '详细地址', prop: 'detailAddress' },
{ label: '联系电话', prop: 'phone' },
{
label: '审核状态',
prop: 'status',
type: 'select',
dicData: [
{ label: '未审核', value: 0 },
{ label: '通过', value: 1 },
{ label: '拒绝', value: 2 },
],
},
{ label: '审核意见', prop: 'reviewSuggestion' },
{ label: '创建时间', prop: 'createTime', type: 'datetime', format: 'YYYY-MM-DD HH:mm:ss' },
],
actions: [
{ name: '详情', event: ({ row }) => viewRow(row) },
{ name: '编辑', event: ({ row }) => editRow(row) },
{ type: 'danger', name: '删除', event: ({ row }) => deleteRow(row) },
],
},
});
//
const loadData = () => {
state.loading = true;
fetchBusinessSubjectList(state.query)
.then((res) => {
if (res.code === 200) {
const { current, size, total, records } = res.data;
state.data = records;
state.pageData = {
currentPage: current || 1,
pageSize: size || 10,
total: total,
};
}
})
.catch((err) => {
app.$message.error(err.msg);
state.data = [];
})
.finally(() => {
state.loading = false;
});
};
loadData();
const editRow = (row) => {
fetchBusinessSubjectInfo(row.id).then((res) => {
crudRef.value.rowEdit(res.data);
});
};
const viewRow = (row) => {
fetchBusinessSubjectInfo(row.id).then((res) => {
crudRef.value.rowView(res.data);
});
};
const deleteRow = (row) => {
app
.$confirm('确认删除?', '删除', { type: 'warning' })
.then(() =>
deleteBusinessSubject(row.id).then(() => {
app.$message.success('删除成功');
loadData();
})
)
.catch(() => {});
};
//
const currentChange = (current) => {
state.query.current = current;
loadData();
};
//
const sizeChange = (size) => {
state.query.size = size;
loadData();
};
//
const searchChange = (params, done) => {
if (done) done();
state.query = params;
state.query.current = 1;
loadData();
};
//
const refreshChange = () => {
loadData();
app.$message.success('刷新成功');
};
//
const selectionChange = (rows) => {
state.selection = rows;
};
const handleIds = () => {
let datalist = state.selection.map((m) => {
return { landId: m.landId, landName: m.landName };
});
let selectIdlist = uniqueObjects(datalist, 'landId');
let selectIdsVal = selectIdlist.map((n) => {
return n.landId;
});
return selectIdsVal.toString() || '';
};
function uniqueObjects(arr, key) {
return arr.reduce((acc, current) => {
const duplicate = acc.find((element) => element[key] === current[key]);
if (!duplicate) {
acc.push(current);
}
return acc;
}, []);
}
//
const rowSave = (row, done, loading) => {
saveBusinessSubject(row)
.then(() => {
app.$message.success('添加成功');
done();
loadData();
})
.catch((e) => app.$message.error(e.msg))
.finally(() => loading());
};
const rowUpdate = (row, index, done, loading) => {
console.info('更新');
editBusinessSubject(row)
.then((res) => {
if (res.code === 200) {
app.$message.success('更新成功!');
done();
loadData();
}
})
.catch((err) => {
app.$message.error(err.msg);
})
.finally(() => {
loading();
});
};
const onBatchDel = () => {
let ids = handleIds();
if (!ids.length || ids.length <= 0) {
return app.$message.error('请先选择要删除的数据');
}
};
</script>

View File

@ -38,7 +38,7 @@ const res = [
name: `1号基地`, name: `1号基地`,
area: 100, area: 100,
status: 1, status: 1,
location: '东经 92°45至 99°23北纬 20°27至 18°35F', location: '99°24\'31.280"E, 23°31\'39.990"N',
type: 1, type: 1,
p1: 1, p1: 1,
p2: 100, p2: 100,
@ -52,7 +52,7 @@ const res = [
name: `2号基地`, name: `2号基地`,
area: 211, area: 211,
status: 1, status: 1,
location: '东经 92°44至 99°24北纬 20°23至 18°31F', location: '99°23\'56.224"E, 23°32\'8.225"N',
type: 1, type: 1,
p1: 1, p1: 1,
p2: 120, p2: 120,
@ -66,7 +66,7 @@ const res = [
name: `3号基地`, name: `3号基地`,
area: 121, area: 121,
status: 1, status: 1,
location: '东经 92°43至 99°25北纬 20°21至 18°31F', location: '99°25\'32.574"E, 23°38\'23.701"N',
type: 1, type: 1,
p1: 1, p1: 1,
p2: 56, p2: 56,
@ -80,7 +80,7 @@ const res = [
name: `4号基地`, name: `4号基地`,
area: 231, area: 231,
status: 2, status: 2,
location: '东经 92°42至 99°26北纬 21°20至 18°32F', location: '99°25\'19.027"E, 23°31\'59.693"N',
type: 2, type: 2,
p1: 2, p1: 2,
p2: 145, p2: 145,
@ -94,7 +94,7 @@ const res = [
name: `5号基地`, name: `5号基地`,
area: 231, area: 231,
status: 2, status: 2,
location: '东经 92°43至 99°26北纬 21°21至 18°22F', location: '99°30\'50.886"E, 23°37\'14.542"N',
type: 2, type: 2,
p1: 2, p1: 2,
p2: 145, p2: 145,
@ -177,6 +177,9 @@ const state = reactive({
message: '请输入', message: '请输入',
trigger: 'blur', trigger: 'blur',
}, },
formatter: (row) => {
return row.location.replace(',', '\n'); //
},
}, },
{ {
label: '土壤类型', label: '土壤类型',