Merge remote-tracking branch 'origin/dev' into dev

This commit is contained in:
姚俊旭 2025-06-13 14:26:19 +08:00
commit b48ed6b5cb
22 changed files with 1041 additions and 738 deletions

View File

@ -4,7 +4,7 @@
基于 qiankun + vue2&vue3 + Vite + vite-plugin-qiankun 技术栈实现的前端微应用架构,实现了主子应用切换。 基于 qiankun + vue2&vue3 + Vite + vite-plugin-qiankun 技术栈实现的前端微应用架构,实现了主子应用切换。
1、主应用介绍 1、主应用介绍
技术栈 Vite+Vue3 + Element-plus + qiankun + Pinia 技术栈 Vite+Vue3 + Element-plus + qiankun + Pinia

View File

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

View File

@ -14,4 +14,4 @@ VITE_APP_UPLOAD_API = '/uploadApis'
# 内网接口地址 # 内网接口地址
VITE_APP_BASE_URL = 'http://192.168.18.99:8080' VITE_APP_BASE_URL = 'http://192.168.18.99:8080'
VITE_APP_UPLOAD_URL = 'http://192.168.18.99:8080' VITE_APP_UPLOAD_URL = 'http://192.168.18.74:8080'

View File

@ -0,0 +1,43 @@
import request from '@/utils/axios';
// 新增POST
export function createGrid(data = {}) {
return request('/land-resource/gridManage/save', {
method: 'POST',
data,
});
}
// 删除DELETE
export function deleteGrid(id) {
return request(`/land-resource/gridManage/${id}`, {
method: 'DELETE',
});
}
// 修改PUT
export function updateGrid(data = {}) {
return request('/land-resource/gridManage/edit', {
method: 'PUT',
data,
});
}
// 查询列表GET
export function fetchGridList(params) {
return request('/land-resource/gridManage/page', {
method: 'GET',
params,
});
}
// 获取详情GET
export function getGridDetail(id) {
return request(`/land-resource/gridManage/${id}`, {
method: 'GET',
});
}
// 导出GET + Blob
export function exportGrid(params = {}) {
return request('/land-resource/gridManage/export', {
method: 'GET',
params,
responseType: 'blob',
});
}

View File

@ -1,40 +1,27 @@
<template> <template>
<div class="area-cascader-container" :style="{ width: width + 'px' }"> <div class="area-cascader-container" :style="containerStyle">
<!-- 一行显示模式 --> <!-- 一行显示模式 -->
<template v-if="!splitRows"> <template v-if="!splitRows">
<div v-if="label" class="area-cascader-label">{{ label }}</div> <div v-if="label" class="area-cascader-label">{{ label }}</div>
<div style="display: flex; gap: 8px; flex: 1"> <div class="controls">
<el-cascader <el-cascader v-model="regionModel" :options="areaOptions" :props="cascaderProps" :placeholder="areaPlaceholder" style="flex: 1" clearable />
v-model="selectedAreaCode"
:options="areaOptions"
:props="cascaderProps"
:placeholder="areaPlaceholder"
style="flex: 1"
clearable
/>
<span v-if="showSeparator" class="area-cascader-separator">{{ separator }}</span> <span v-if="showSeparator" class="area-cascader-separator">{{ separator }}</span>
<el-select v-model="selectedGridId" :placeholder="gridPlaceholder" style="flex: 1" clearable :disabled="!selectedAreaCode"> <el-select v-model="gridModel" :placeholder="gridPlaceholder" style="flex: 1" :disabled="!regionModel" clearable>
<el-option v-for="item in gridOptions" :key="item.gridName" :label="item.gridName" :value="item.id" /> <el-option v-for="item in gridOptions" :key="item.id" :label="item.gridName" :value="item.id" />
</el-select> </el-select>
</div> </div>
</template> </template>
<!-- 两行显示模式 --> <!-- 两行显示模式 -->
<template v-else> <template v-else>
<div class="area-item"> <div class="area-item">
<div class="area-cascader-label">所属行政区域</div> <div class="area-cascader-label">所属行政区域</div>
<el-cascader <el-cascader v-model="regionModel" style="flex: 1" :options="areaOptions" :props="cascaderProps" :placeholder="areaPlaceholder" clearable />
v-model="selectedAreaCode"
:options="areaOptions"
:props="cascaderProps"
:placeholder="areaPlaceholder"
style="flex: 1"
clearable
/>
</div> </div>
<div class="area-item"> <div class="area-item">
<div class="area-cascader-label">网格</div> <div class="area-cascader-label">网格</div>
<el-select v-model="selectedGridId" :placeholder="gridPlaceholder" style="flex: 1" clearable :disabled="!selectedAreaCode"> <el-select v-model="gridModel" style="flex: 1" :placeholder="gridPlaceholder" :disabled="!regionModel" clearable>
<el-option v-for="item in gridOptions" :key="item.gridName" :label="item.gridName" :value="item.id" /> <el-option v-for="item in gridOptions" :key="item.id" :label="item.gridName" :value="item.id" />
</el-select> </el-select>
</div> </div>
</template> </template>
@ -42,152 +29,49 @@
</template> </template>
<script setup> <script setup>
import { ref, watch, onMounted, computed } from 'vue'; import { ref, onMounted, computed } from 'vue';
import { ElCascader, ElSelect, ElOption } from 'element-plus';
import request from '@/utils/axios'; import request from '@/utils/axios';
import { useUserStore } from '@/store/modules/user'; import { useUserStore } from '@/store/modules/user';
const props = defineProps({ const props = defineProps({
regionCode: { regionCode: { type: String, default: '' },
type: String, gridId: { type: [String, Number], default: '' },
default: '', label: { type: String, default: '行政区域-网格:' },
}, areaPlaceholder: { type: String, default: '请选择区域' },
gridId: { gridPlaceholder: { type: String, default: '请选择网格' },
type: [String, Number], width: { type: [Number, String], default: 500 },
default: '', showSeparator: { type: Boolean, default: false },
}, separator: { type: String, default: '-' },
label: { splitRows: { type: Boolean, default: false },
type: String,
default: '行政区域-网格:',
},
areaPlaceholder: {
type: String,
default: '请选择区域',
},
gridPlaceholder: {
type: String,
default: '请选择网格',
},
width: {
type: [Number, String],
default: 500,
},
showSeparator: {
type: Boolean,
default: false,
},
separator: {
type: String,
default: '-',
},
splitRows: {
type: Boolean,
default: false,
},
}); });
const emit = defineEmits(['update:regionCode', 'update:gridId']); const emit = defineEmits(['update:regionCode', 'update:gridId']);
const userStore = useUserStore(); const userStore = useUserStore();
const areaOptions = ref([]); const areaOptions = ref([]);
const gridOptions = ref([]); const gridOptions = ref([]);
// // computed regionModel & gridModel
const selectedAreaCode = ref(props.regionCode); const regionModel = computed({
const selectedGridId = ref(props.gridId); get() {
return props.regionCode;
// },
const fetchAreaData = async () => { set(val) {
try { emit('update:regionCode', val);
// 使 request params // reset grid when region changes
const res = await request.get('/system/area/region', { emit('update:gridId', '');
params: { gridOptions.value = [];
areaCode: '530000', fetchGridList(val);
}, },
}); });
areaOptions.value = res.data ?? []; const gridModel = computed({
} catch (err) { get() {
console.error('区域数据加载失败', err); return props.gridId;
} },
}; set(val) {
emit('update:gridId', val);
// },
const fetchGridList = async (regionCode) => {
if (!regionCode) return;
try {
// 使 request params
const res = await request.get('/land-resource/gridManage/page', {
params: {
regionCode: regionCode,
},
});
gridOptions.value = res.data?.records ?? [];
} catch (err) {
console.error('网格数据加载失败', err);
}
};
const selectedAreaLabel = computed(() => {
const findLabel = (options, code) => {
for (const item of options) {
if (item.areaCode === code) return item.areaName;
if (item.areaChildVOS?.length) {
const res = findLabel(item.areaChildVOS, code);
if (res) return res;
}
}
return '';
};
return findLabel(areaOptions.value, selectedAreaCode.value);
}); });
const selectedGridLabel = computed(() => {
const item = gridOptions.value.find((g) => g.id === selectedGridId.value);
return item?.gridName || '';
});
//
watch(
() => props.regionCode,
(val) => {
selectedAreaCode.value = val;
}
);
watch(
() => props.gridId,
(val) => {
selectedGridId.value = val;
}
);
//
watch(selectedAreaCode, (val) => {
emit('update:regionCode', val);
selectedGridId.value = ''; // gridId
emit('update:gridId', '');
fetchGridList(val);
});
watch(selectedGridId, (val) => {
emit('update:gridId', val);
});
// v-model:value
// const updateValue = () => {
// console.log('update:value', selectedAreaCode.value, selectedGridName.value, selectedGridId.value);
// emit('update:value', {
// regionCode: selectedAreaCode.value,
// gridName: selectedGridName.value,
// gridId: selectedGridId.value,
// });
// };
onMounted(() => {
fetchAreaData();
});
//
const cascaderProps = computed(() => ({ const cascaderProps = computed(() => ({
label: 'areaName', label: 'areaName',
value: 'areaCode', value: 'areaCode',
@ -195,37 +79,62 @@ const cascaderProps = computed(() => ({
emitPath: false, emitPath: false,
expandTrigger: 'hover', expandTrigger: 'hover',
})); }));
async function fetchAreaData() {
try {
const res = await request.get('/system/area/region', { params: { areaCode: '530000' } });
areaOptions.value = res.data || [];
} catch (err) {
console.error('区域数据加载失败', err);
}
}
async function fetchGridList(regionCode) {
if (!regionCode) return;
try {
const res = await request.get('/land-resource/gridManage/page', { params: { regionCode } });
gridOptions.value = res.data?.records || [];
} catch (err) {
console.error('网格数据加载失败', err);
}
}
onMounted(fetchAreaData);
//
const containerStyle = computed(() => ({
width: typeof props.width === 'number' ? `${props.width}px` : props.width,
display: 'flex',
gap: '18px',
flexDirection: props.splitRows ? 'column' : 'row',
}));
</script> </script>
<style scoped> <style scoped>
.area-cascader-container { .area-cascader-container {
display: flex;
gap: 18px;
margin: 0; margin: 0;
padding: 0; padding: 0;
/* 分行显示时垂直排列 */
flex-direction: v-bind('splitRows ? "column" : "row"');
} }
.area-cascader-label { .area-cascader-label {
font-size: 14px; font-size: 14px;
color: #606266; color: #606266;
text-align: right; text-align: right;
line-height: 32px; line-height: 32px;
box-sizing: border-box;
width: 120px; width: 120px;
padding-right: v-bind('splitRows ? "12px" : "0"');
} }
.controls {
.area-cascader-separator { display: flex;
align-self: center; gap: 8px;
font-size: 16px; flex: 1;
color: #606266;
margin: 0;
padding: 0;
} }
.area-item { .area-item {
display: flex; display: flex;
gap: 0; gap: 0;
align-items: center;
/* background-color: antiquewhite; */
}
.area-cascader-separator {
align-self: center;
font-size: 16px;
color: #606266;
} }
</style> </style>

View File

@ -24,7 +24,7 @@ const props = defineProps({
default: false, default: false,
}, },
modelValue: { modelValue: {
type: Array, type: [Array, String],
default: () => [], default: () => [],
}, },
label: { label: {
@ -39,6 +39,10 @@ const props = defineProps({
type: [Number, String], type: [Number, String],
default: 500, default: 500,
}, },
emitPath: {
type: Boolean,
default: true,
},
}); });
const emit = defineEmits(['update:modelValue']); const emit = defineEmits(['update:modelValue']);
@ -46,14 +50,35 @@ const emit = defineEmits(['update:modelValue']);
const userStore = useUserStore(); const userStore = useUserStore();
const areaOptions = ref([]); const areaOptions = ref([]);
const selectedAreaPath = ref([...props.modelValue]);
//
// const selectedAreaPath = props.emitPath ? ref([].concat(props.modelValue)) : ref(props.modelValue);
const selectedAreaPath = computed({
get() {
// &
if (props.emitPath) {
return Array.isArray(props.modelValue) ? props.modelValue : [];
} else {
return typeof props.modelValue === 'string' ? props.modelValue : '';
}
},
set(val) {
//
if (props.emitPath) {
emit('update:modelValue', Array.isArray(val) ? val : []);
} else {
emit('update:modelValue', typeof val === 'string' ? val : '');
}
},
});
// //
const cascaderProps = computed(() => ({ const cascaderProps = computed(() => ({
label: 'areaName', label: 'areaName',
value: 'areaCode', value: 'areaCode',
children: 'areaChildVOS', children: 'areaChildVOS',
emitPath: true, emitPath: props.emitPath,
expandTrigger: 'hover', expandTrigger: 'hover',
})); }));
@ -70,7 +95,7 @@ const fetchAreaData = async () => {
console.error('加载行政区域失败', err); console.error('加载行政区域失败', err);
} }
}; };
// 使
// // => // // =>
// watch( // watch(
// () => props.modelValue, // () => props.modelValue,
@ -80,9 +105,19 @@ const fetchAreaData = async () => {
// ); // );
// => // =>
watch(selectedAreaPath, (val) => { watch(
emit('update:modelValue', val); selectedAreaPath,
}); (val) => {
if (props.emitPath) {
//
emit('update:modelValue', Array.isArray(val) ? val : []);
} else {
//
emit('update:modelValue', typeof val === 'string' ? val : '');
}
},
{ deep: true }
);
onMounted(() => { onMounted(() => {
fetchAreaData(); fetchAreaData();

View File

@ -12,6 +12,7 @@
:auto-upload="true" :auto-upload="true"
:disabled="readonly" :disabled="readonly"
:accept="accept" :accept="accept"
@preview="handlePreview"
> >
<el-icon v-if="fileList.length < limit"><Plus /></el-icon> <el-icon v-if="fileList.length < limit"><Plus /></el-icon>
</el-upload> </el-upload>
@ -24,78 +25,74 @@ import { ref, computed } from 'vue';
import { Plus } from '@element-plus/icons-vue'; import { Plus } from '@element-plus/icons-vue';
import { CommonUpload } from '@/apis/index'; import { CommonUpload } from '@/apis/index';
// 1. props & emit
const props = defineProps({ const props = defineProps({
modelValue: { modelValue: { type: [Array, String], default: () => [] },
type: Array, ossUrl: { type: String, default: 'http://gov-cloud.oss-cn-chengdu.aliyuncs.com/' },
default: () => [], limit: { type: Number, default: 5 },
}, accept: { type: String, default: 'image/*' },
ossUrl: { readonly: { type: Boolean, default: false },
type: String,
default: 'http://gov-cloud.oss-cn-chengdu.aliyuncs.com/',
},
limit: {
type: Number,
default: 5,
},
accept: {
type: String,
default: 'image/*',
},
readonly: {
type: Boolean,
default: false,
},
}); });
const emit = defineEmits(['update:modelValue']); const emit = defineEmits(['update:modelValue']);
// el-upload file-list // 2. computed limit
const fileList = computed(() => { const selectedFiles = computed({
return props.modelValue.map((path, idx) => ({ get() {
name: `image_${idx}`, // limit===1 1
url: props.ossUrl + path, if (props.limit === 1 && typeof props.modelValue === 'string' && props.modelValue) {
uid: `${idx}`, return [props.modelValue];
})); }
//
return Array.isArray(props.modelValue) ? props.modelValue : [];
},
set(val) {
//
if (props.limit === 1) {
emit('update:modelValue', val.length ? val[0] : '');
} else {
emit('update:modelValue', val);
}
},
}); });
// // 3. fileList & previewList selectedFiles
const fileList = computed(() =>
selectedFiles.value.map((path, idx) => ({
name: `file_${idx}`,
url: props.ossUrl + path,
uid: `${idx}`,
}))
);
const previewShow = ref(false); const previewShow = ref(false);
const previewList = computed(() => fileList.value.map((item) => item.url));
const previewIndex = ref(0); const previewIndex = ref(0);
const previewList = computed(() => fileList.value.map((f) => f.url));
// // 4. &
const customUploadRequest = async ({ file, onSuccess, onError }) => { const customUploadRequest = async ({ file, onSuccess, onError }) => {
const formData = new FormData(); const formData = new FormData();
formData.append('file', file); formData.append('file', file);
try { try {
const res = await CommonUpload(formData); const res = await CommonUpload(formData);
// { code:200, data: { url: 'relative/path.jpg' } }
onSuccess(res, file); onSuccess(res, file);
} catch (err) { } catch (err) {
onError(err); onError(err);
} }
}; };
// modelValue
function handleUploadSuccess(res) { function handleUploadSuccess(res) {
const relative = res.data?.url; const relative = res.data?.url;
if (relative) { if (!relative) return;
const newArr = [...props.modelValue, relative]; //
emit('update:modelValue', newArr); selectedFiles.value = [...selectedFiles.value, relative];
}
} }
//
function handleRemove(file) { function handleRemove(file) {
const fullUrl = file.url; const rel = file.url.replace(props.ossUrl, '');
const relative = fullUrl.replace(props.ossUrl, ''); selectedFiles.value = selectedFiles.value.filter((p) => p !== rel);
const newArr = props.modelValue.filter((path) => path !== relative);
emit('update:modelValue', newArr);
} }
// // 5.
function handlePreview(file) { function handlePreview(file) {
const idx = fileList.value.findIndex((item) => item.uid === file.uid); const idx = fileList.value.findIndex((item) => item.uid === file.uid);
if (idx !== -1) { if (idx >= 0) {
previewIndex.value = idx; previewIndex.value = idx;
previewShow.value = true; previewShow.value = true;
} }

View File

@ -0,0 +1,15 @@
import { defineStore } from 'pinia';
import { getEnterList } from '@/apis/businessEntity';
export const useCoop = defineStore('useCoop', {
state: () => ({
data: {},
}),
actions: {
//订单
getData(params) {
return Promise.resolve((useCoop().$state.data = params));
},
},
getters: {},
});

View File

@ -99,7 +99,13 @@
<template #default> <template #default>
<el-form ref="planForm" :model="formData" :rules="formRules" label-width="120px" class="common-dialog"> <el-form ref="planForm" :model="formData" :rules="formRules" label-width="120px" class="common-dialog">
<el-form-item label="" label-width="0px"> <el-form-item label="" label-width="0px">
<AreaCascader v-model:value="areaFormData" split-rows label="所属行政区域-网格" :width="500" /> <AreaCascader
v-model:region-code="formData.regionCode"
v-model:grid-id="formData.gridId"
split-rows
label="所属行政区域-网格"
:width="500"
/>
</el-form-item> </el-form-item>
<!-- <AreaCascader v-model:value="areaFormData" split-rows label="所属行政区域-网格" :width="500" /> --> <!-- <AreaCascader v-model:value="areaFormData" split-rows label="所属行政区域-网格" :width="500" /> -->
<el-form-item label="计划名称"> <el-form-item label="计划名称">
@ -215,6 +221,7 @@ const fetchDetailData = async (id) => {
const res = await getAnnualDetail(id); const res = await getAnnualDetail(id);
if (res.code === 200) { if (res.code === 200) {
currentDetailRow.value = res.data; currentDetailRow.value = res.data;
formData.value = res.data;
} else { } else {
app.$message.error(res.msg || '获取详情数据失败'); app.$message.error(res.msg || '获取详情数据失败');
} }
@ -332,8 +339,8 @@ const state = reactive({
currentAction.value = 'reCreate'; currentAction.value = 'reCreate';
formData.value = { ...row }; formData.value = { ...row };
if (isGridMember.value) { if (isGridMember.value) {
formData.value.regionName = row.regionName; formData.value.regionCode = row.regionCode;
formData.value.gridName = row.gridName; formData.value.gridId = row.gridId;
} }
formData.value.growthCycleUnit = row.growthCycleUnit || '1'; formData.value.growthCycleUnit = row.growthCycleUnit || '1';
commonDialogVisible.value = true; commonDialogVisible.value = true;
@ -349,6 +356,7 @@ const state = reactive({
formData.value.regionName = row.regionName; formData.value.regionName = row.regionName;
formData.value.gridName = row.gridName; formData.value.gridName = row.gridName;
} }
formData.value.plantingArea = row.plantingAreaActual;
formData.value.growthCycleUnit = row.growthCycleUnit || '1'; formData.value.growthCycleUnit = row.growthCycleUnit || '1';
commonDialogVisible.value = true; commonDialogVisible.value = true;
}, },
@ -399,6 +407,7 @@ const submitForm = async () => {
app.$message.success('重新制定计划成功'); app.$message.success('重新制定计划成功');
} else if (currentAction.value === 'fillActual') { } else if (currentAction.value === 'fillActual') {
// //
formData.value.planId = formData.value.id;
await saveActualProgress(formData.value); await saveActualProgress(formData.value);
app.$message.success('填写实际种植信息成功'); app.$message.success('填写实际种植信息成功');
} else if (currentAction.value === 'add') { } else if (currentAction.value === 'add') {

View File

@ -81,14 +81,7 @@
</el-form> </el-form>
</el-tab-pane> </el-tab-pane>
<el-tab-pane label="土地产权信息" name="property"> <el-tab-pane label="土地产权信息" name="property">
<el-form <el-form ref="propertyFormRef" :model="formDataProperty" :rules="propertyRules" label-width="120px" class="form-container">
ref="propertyFormRef"
:model="formDataProperty"
:rules="propertyRules"
:disabled="disabledProperty"
label-width="120px"
class="form-container"
>
<el-form-item label="地块名称"> <el-form-item label="地块名称">
<el-input v-model="formDataProperty.landName" disabled /> <el-input v-model="formDataProperty.landName" disabled />
</el-form-item> </el-form-item>
@ -102,16 +95,7 @@
<el-input v-model="formDataProperty.landCode" placeholder="请输入产权编号" /> <el-input v-model="formDataProperty.landCode" placeholder="请输入产权编号" />
</el-form-item> </el-form-item>
<el-form-item label="产权证书" prop="propertyCertificateUrl"> <el-form-item label="产权证书" prop="propertyCertificateUrl">
<el-upload <FileUploader v-model="formDataProperty.propertyCertificateUrl" :limit="1" />
:http-request="customUploadRequest"
:on-success="(res, file) => handleUploadSuccess(res, file, 'property')"
multiple
:show-file-list="true"
>
<template #trigger>
<el-button type="primary">点击上传</el-button>
</template>
</el-upload>
</el-form-item> </el-form-item>
</el-form> </el-form>
</el-tab-pane> </el-tab-pane>
@ -120,7 +104,7 @@
<template #footer> <template #footer>
<span class="dialog-footer"> <span class="dialog-footer">
<el-button @click="addDialogVisible = false">取消</el-button> <el-button @click="addDialogVisible = false">取消</el-button>
<el-button type="primary" @click="handleAddSubmit('basic')">提交</el-button> <el-button v-if="activeTab === 'basic'" type="primary" @click="handleAddSubmit('basic')">提交</el-button>
<el-button v-if="activeTab === 'basic'" :disabled="disabledProperty" @click="activeTab = 'property'">下一步</el-button> <el-button v-if="activeTab === 'basic'" :disabled="disabledProperty" @click="activeTab = 'property'">下一步</el-button>
<el-button v-else @click="activeTab = 'basic'">上一步</el-button> <el-button v-else @click="activeTab = 'basic'">上一步</el-button>
<el-button v-if="activeTab === 'property'" type="primary" @click="handleAddSubmit('property')"> 提交 </el-button> <el-button v-if="activeTab === 'property'" type="primary" @click="handleAddSubmit('property')"> 提交 </el-button>
@ -154,7 +138,7 @@
<el-input v-model="viewEditFormData.address" /> <el-input v-model="viewEditFormData.address" />
</el-form-item> </el-form-item>
<el-form-item label="所属网格" prop="gridId"> <el-form-item label="所属网格" prop="gridId">
<AreaCascader v-model:grid-id="viewEditFormData.gridId" :width="500" label="" /> <AreaCascader v-model="viewEditFormData.regionCode" v-model:grid-id="viewEditFormData.gridId" :width="500" label="" />
</el-form-item> </el-form-item>
<el-form-item label="土壤类型" prop="soilTypeId"> <el-form-item label="土壤类型" prop="soilTypeId">
<url-select <url-select
@ -167,20 +151,7 @@
/> />
</el-form-item> </el-form-item>
<el-form-item label="土地照片" prop="landUrl"> <el-form-item label="土地照片" prop="landUrl">
<template v-if="viewEditFormData.landUrl"> <FileUploader v-model="viewEditFormData.landUrl" :limit="1" />
<img :src="`${ossUrl}${viewEditFormData.landUrl}`" alt="土地照片" class="preview-image" />
</template>
<el-upload
v-if="!isView"
:http-request="customUploadRequest"
:on-success="(res, file) => handleUploadSuccess(res, file, 'viewEditBasic')"
multiple
:show-file-list="true"
>
<template #trigger>
<el-button type="primary">点击上传</el-button>
</template>
</el-upload>
</el-form-item> </el-form-item>
<el-form-item label="土地范围" prop="scope"> <el-form-item label="土地范围" prop="scope">
<el-input v-model="viewEditFormData.scope" /> <el-input v-model="viewEditFormData.scope" />
@ -197,20 +168,7 @@
<el-input v-model="viewEditFormData.landCode" /> <el-input v-model="viewEditFormData.landCode" />
</el-form-item> </el-form-item>
<el-form-item label="产权证书" prop="propertyCertificateUrl"> <el-form-item label="产权证书" prop="propertyCertificateUrl">
<template v-if="viewEditFormData.propertyCertificateUrl"> <FileUploader v-model="viewEditFormData.propertyCertificateUrl" :limit="1" />
<img :src="`${ossUrl}${viewEditFormData.propertyCertificateUrl}`" alt="产权证书" class="preview-image" />
</template>
<el-upload
v-if="!isView"
:http-request="customUploadRequest"
:on-success="(res, file) => handleUploadSuccess(res, file, 'viewEditProperty')"
multiple
:show-file-list="true"
>
<template #trigger>
<el-button type="primary">点击上传</el-button>
</template>
</el-upload>
</el-form-item> </el-form-item>
</el-form> </el-form>
@ -395,7 +353,7 @@ const option = reactive({
column: [ column: [
{ label: '地块名称', prop: 'landName' }, { label: '地块名称', prop: 'landName' },
{ label: '所属网格', prop: 'gridName' }, { label: '所属网格', prop: 'gridName' },
{ label: '面积', prop: 'area' }, { label: '面积', prop: 'area', formatter: (row, column, cellValue) => `${cellValue}` },
{ label: '土地类型', prop: 'landTypeName' }, { label: '土地类型', prop: 'landTypeName' },
{ label: '所属行政区域', prop: 'fullRegionName' }, { label: '所属行政区域', prop: 'fullRegionName' },
{ label: '具体位置', prop: 'address' }, { label: '具体位置', prop: 'address' },

View File

@ -25,12 +25,14 @@
> >
<el-icon><Plus /></el-icon> <el-icon><Plus /></el-icon>
</el-upload> </el-upload>
<!-- <FileUploader v-model="localForm.cooperativePhoto" :limit="1" /> -->
</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="地址">
<area-select v-model="localForm.addressArr" :disabled="readonly" :label="null" /> <area-select v-model="localForm.addressArr" :disabled="readonly" :label="null" />
<!-- <el-cascader v-model="localForm.addressArr" :options="options" @change="handleChange" /> -->
</el-form-item> </el-form-item>
<el-form-item label="经营产品"> <el-form-item label="经营产品">
<el-input v-model="localForm.primaryProduct" placeholder="请输入" /> <el-input v-model="localForm.primaryProduct" placeholder="请输入" />
@ -45,7 +47,7 @@
<el-row :gutter="20"> <el-row :gutter="20">
<el-col :span="24"> <el-col :span="24">
<el-form-item label="营业执照"> <el-form-item label="营业执照">
<el-upload <!-- <el-upload
action="#" action="#"
:http-request="customUploadRequest" :http-request="customUploadRequest"
:on-success="(res, file) => handleUploadSuccess(res, file, 'businessLicence')" :on-success="(res, file) => handleUploadSuccess(res, file, 'businessLicence')"
@ -56,7 +58,8 @@
:on-remove="() => handleRemove('businessLicence')" :on-remove="() => handleRemove('businessLicence')"
> >
<el-icon><Plus /></el-icon> <el-icon><Plus /></el-icon>
</el-upload> </el-upload> -->
<FileUploader v-model="localForm.businessLicence" :limit="1" />
</el-form-item> </el-form-item>
</el-col> </el-col>
</el-row> </el-row>
@ -70,6 +73,8 @@ import cloneDeep from 'lodash/cloneDeep';
import { CommonUpload } from '@/apis/index'; import { CommonUpload } from '@/apis/index';
import { ElMessage } from 'element-plus'; import { ElMessage } from 'element-plus';
import Attrs from './Attrs.vue'; import Attrs from './Attrs.vue';
import { useCoop } from '../../../../store/modules/coop';
const localForm = useCoop().$state.data;
const props = defineProps({ const props = defineProps({
modelValue: { modelValue: {
@ -77,7 +82,7 @@ const props = defineProps({
required: true, required: true,
default: () => ({}), default: () => ({}),
}, },
readonly: Boolean, // readonly: Boolean,
}); });
const ossUrl = 'http://gov-cloud.oss-cn-chengdu.aliyuncs.com/'; const ossUrl = 'http://gov-cloud.oss-cn-chengdu.aliyuncs.com/';
@ -87,16 +92,16 @@ const businessLicenceList = ref([]);
const emit = defineEmits(['update:modelValue']); const emit = defineEmits(['update:modelValue']);
// props // props
const localForm = ref({ ...props.modelValue }); // const localForm = ref({ ...props.modelValue });
// //
watch( // watch(
localForm, // localForm,
(newVal) => { // (newVal) => {
emit('update:modelValue', { ...newVal }); // emit('update:modelValue', { ...newVal });
}, // },
{ deep: true } // { deep: true }
); // );
// watch( // watch(
// () => props.modelValue, // () => props.modelValue,
// (newVal) => { // (newVal) => {
@ -149,21 +154,21 @@ const handleExceed = () => {
}; };
// //
if (localForm.value.cooperativePhoto) { if (localForm.cooperativePhoto) {
cooperativePhotoList.value = [ cooperativePhotoList.value = [
{ {
name: '合作社照片', name: '合作社照片',
url: ossUrl + localForm.value.cooperativePhoto, url: ossUrl + localForm.cooperativePhoto,
status: 'success', status: 'success',
}, },
]; ];
} }
if (localForm.value.businessLicence) { if (localForm.businessLicence) {
businessLicenceList.value = [ businessLicenceList.value = [
{ {
name: '营业执照', name: '营业执照',
url: ossUrl + localForm.value.businessLicence, url: ossUrl + localForm.businessLicence,
status: 'success', status: 'success',
}, },
]; ];

View File

@ -71,6 +71,8 @@
import { reactive, watch } from 'vue'; import { reactive, watch } from 'vue';
import { Plus } from '@element-plus/icons-vue'; import { Plus } from '@element-plus/icons-vue';
import cloneDeep from 'lodash/cloneDeep'; import cloneDeep from 'lodash/cloneDeep';
import { useCoop } from '../../../../store/modules/coop';
const localForm = useCoop().$state.data;
const props = defineProps({ const props = defineProps({
modelValue: { modelValue: {
@ -86,23 +88,23 @@ const props = defineProps({
const emit = defineEmits(['update:modelValue']); const emit = defineEmits(['update:modelValue']);
// //
const localForm = reactive(cloneDeep(props.modelValue)); // const localForm = reactive(cloneDeep(props.modelValue));
// watch // watch
watch( // watch(
() => localForm, // () => localForm,
(val) => { // (val) => {
emit('update:modelValue', { ...val }); // emit('update:modelValue', { ...val });
}, // },
{ deep: true } // { deep: true }
); // );
watch( // watch(
() => props.modelValue, // () => props.modelValue,
(newVal) => { // (newVal) => {
Object.assign(localForm, cloneDeep(newVal)); // Object.assign(localForm, cloneDeep(newVal));
}, // },
{ deep: true } // { deep: true }
); // );
// //
function downloadTemplate(type) { function downloadTemplate(type) {

View File

@ -28,6 +28,8 @@
<script setup> <script setup>
import { reactive, watch } from 'vue'; import { reactive, watch } from 'vue';
import cloneDeep from 'lodash/cloneDeep'; import cloneDeep from 'lodash/cloneDeep';
import { useCoop } from '../../../../store/modules/coop';
const localForm = useCoop().$state.data;
const props = defineProps({ const props = defineProps({
modelValue: { modelValue: {
@ -40,22 +42,22 @@ const props = defineProps({
const emit = defineEmits(['update:modelValue']); const emit = defineEmits(['update:modelValue']);
const localForm = reactive(cloneDeep(props.modelValue)); // const localForm = reactive(cloneDeep(props.modelValue));
watch( // watch(
localForm, // localForm,
(newVal) => { // (newVal) => {
emit('update:modelValue', { ...newVal }); // emit('update:modelValue', { ...newVal });
}, // },
{ deep: true } // { deep: true }
); // );
watch( // watch(
() => props.modelValue, // () => props.modelValue,
(newVal) => { // (newVal) => {
Object.assign(localForm, cloneDeep(newVal)); // Object.assign(localForm, cloneDeep(newVal));
}, // },
{ deep: true } // { deep: true }
); // );
</script> </script>
<style scoped lang="scss"> <style scoped lang="scss">
.credit-evaluation { .credit-evaluation {

View File

@ -105,6 +105,8 @@ import { ref, reactive, watch, onMounted, computed } from 'vue';
import { CRUD_OPTIONS } from '@/config'; import { CRUD_OPTIONS } from '@/config';
import { ElMessageBox, ElMessage } from 'element-plus'; import { ElMessageBox, ElMessage } from 'element-plus';
import { getMemberList, addMember, updateMember, deleteMembers } from '@/apis/businessEntity'; import { getMemberList, addMember, updateMember, deleteMembers } from '@/apis/businessEntity';
import { useCoop } from '../../../../store/modules/coop';
const defaultFormData = useCoop().$state.data;
const dialogTitle = ref('新增'); const dialogTitle = ref('新增');
const dialogVisible = ref(false); const dialogVisible = ref(false);
@ -124,31 +126,31 @@ const searchForm = ref({
}); });
const crudData = ref([]); const crudData = ref([]);
// //
const defaultFormData = { // const defaultFormData = {
id: '', // id: '',
entId: '', // entId: '',
name: '', // name: '',
idType: '101', // idType: '101',
idCard: '', // idCard: '',
sex: '1', // sex: '1',
age: '', // age: '',
phone: '', // phone: '',
provinceCode: '', // // provinceCode: '', //
cityCode: '', // // cityCode: '', //
countyCode: '', // // countyCode: '', //
townCode: '', // // townCode: '', //
street: '', // // street: '', //
addressArr: [], // addressArr: [],
detailAddress: '', // detailAddress: '',
area: '', // area: '',
planCrop: '', // planCrop: '',
planCropName: '', // planCropName: '',
address: '', // address: '',
createTime: '', // createTime: '',
createUser: '', // createUser: '',
updateTime: '', // updateTime: '',
updateUser: '', // updateUser: '',
}; // };
// 使 // 使
const formData = ref({ ...defaultFormData }); const formData = ref({ ...defaultFormData });
const resetForm = () => { const resetForm = () => {
@ -264,18 +266,18 @@ const handleSave = async () => {
} }
}; };
watch( // watch(
() => formData.value.addressArr, // () => formData.value.addressArr,
(newValue) => { // (newValue) => {
if (newValue.length <= 3) { // if (newValue.length <= 3) {
formData.value.provinceCode = '530000'; // formData.value.provinceCode = '530000';
formData.value.cityCode = '530900'; // formData.value.cityCode = '530900';
formData.value.countyCode = newValue[0]; // formData.value.countyCode = newValue[0];
formData.value.townCode = newValue[1]; // formData.value.townCode = newValue[1];
formData.value.street = newValue[2]; // formData.value.street = newValue[2];
} // }
} // }
); // );
const handleAdd = () => { const handleAdd = () => {
isReadonly.value = false; // isReadonly.value = false; //
resetForm(); resetForm();

View File

@ -73,6 +73,8 @@
<script setup> <script setup>
import { reactive, watch } from 'vue'; import { reactive, watch } from 'vue';
import cloneDeep from 'lodash/cloneDeep'; import cloneDeep from 'lodash/cloneDeep';
import { useCoop } from '../../../../store/modules/coop';
const localForm = useCoop().$state.data;
const props = defineProps({ const props = defineProps({
modelValue: { modelValue: {
@ -86,23 +88,23 @@ const props = defineProps({
const emit = defineEmits(['update:modelValue']); const emit = defineEmits(['update:modelValue']);
// props // props
const localForm = reactive(cloneDeep(props.modelValue)); // const localForm = reactive(cloneDeep(props.modelValue));
// //
watch( // watch(
localForm, // localForm,
(newVal) => { // (newVal) => {
emit('update:modelValue', { ...newVal }); // emit('update:modelValue', { ...newVal });
}, // },
{ deep: true } // { deep: true }
); // );
watch( // watch(
() => props.modelValue, // () => props.modelValue,
(newVal) => { // (newVal) => {
Object.assign(localForm, cloneDeep(newVal)); // Object.assign(localForm, cloneDeep(newVal));
}, // },
{ deep: true } // { deep: true }
); // );
</script> </script>
<style scoped lang="scss"> <style scoped lang="scss">

View File

@ -58,6 +58,9 @@ import TabCreditEvaluation from './components/TabCreditEvaluation.vue';
import TabMember from './components/TabMember.vue'; import TabMember from './components/TabMember.vue';
import { getEnterList, getEnterById, addEnter, updateEnter, approvalEnter, deleteEnter } from '@/apis/businessEntity'; import { getEnterList, getEnterById, addEnter, updateEnter, approvalEnter, deleteEnter } from '@/apis/businessEntity';
import { cloneDeep } from 'lodash'; import { cloneDeep } from 'lodash';
import { useCoop } from '../../../store/modules/coop';
const useCoopData = useCoop();
// //
const visible = ref(false); const visible = ref(false);
@ -128,6 +131,12 @@ const handleSubmit = async () => {
getData(); // getData(); //
} }
} else if (dialogTitle.value === '编辑') { } else if (dialogTitle.value === '编辑') {
formData.value.provinceCode = formData.value.addressArr[0];
formData.value.cityCode = formData.value.addressArr[1];
formData.value.countyCode = formData.value.addressArr[2];
formData.value.townCode = formData.value.addressArr[3];
formData.value.villageCode = formData.value.addressArr[4];
response = await updateEnter(formData.value); response = await updateEnter(formData.value);
if (response.code === 200) { if (response.code === 200) {
ElMessage.success('编辑成功'); ElMessage.success('编辑成功');
@ -336,6 +345,7 @@ function handleTabChange(tab) {
} }
const handleAdd = () => { const handleAdd = () => {
useCoopData.getData({});
isReadonly.value = false; isReadonly.value = false;
// resetForm(); // resetForm();
dialogTitle.value = '新增'; dialogTitle.value = '新增';
@ -358,6 +368,10 @@ const handleView = async (row) => {
// //
const handleEdit = async (row) => { const handleEdit = async (row) => {
console.log(row);
formData.value = row;
formData.value.addressArr = [row.provinceCode, row.cityCode, row.countyCode, row.townCode, row.villageCode];
useCoopData.getData(formData.value);
loading.value = true; loading.value = true;
dialogTitle.value = '编辑'; dialogTitle.value = '编辑';
try { try {

View File

@ -2,389 +2,266 @@
<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"
@row-del="rowDel"
> >
<template #search="{ size }"> <template #search>
<AreaCascader v-model:value="state.query" placeholder="选择行政区域与网格" :width="400" /> <div class="custom-search">
<AreaCascader v-model:region-code="searchForm.regionCode" v-model:grid-id="searchForm.id" :width="600" />
<el-button type="primary" @click="handleSearch"> 搜索 </el-button>
<el-button @click="resetSearch"> 重置 </el-button>
</div>
</template> </template>
<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 #detail="scope">
<el-tabs type="border-card">
<el-tab-pane label="基本信息">
<avue-detail :option="baseDetailOption" :data="scope.row"></avue-detail>
</el-tab-pane>
<el-tab-pane label="网格地图">
<div v-if="scope.row.mapUrl" style="height: 400px">
<img :src="scope.row.mapUrl" style="max-width: 100%; max-height: 100%" />
</div>
<el-empty v-else description="暂无地图数据"></el-empty>
</el-tab-pane>
<el-tab-pane label="其他信息">
<avue-detail :option="otherDetailOption" :data="scope.row"></avue-detail>
</el-tab-pane>
</el-tabs>
</template> </template>
</avue-crud> </avue-crud>
<el-dialog :key="dialogTitle" v-model="visible" :title="dialogTitle" width="60%" align-center :draggable="true">
<el-form ref="form" :model="formData" :rules="rules" :disabled="isReadonly" label-width="100px" class="form-item">
<p class="form-title">填写网格信息</p>
<el-form-item label="网格名称" prop="gridName">
<el-input v-model="formData.gridName" placeholder="请输入网格名称" />
</el-form-item>
<el-form-item label="所属行政区域" prop="gridAreaCode">
<AreaSelect v-model="formData.gridAreaCode" :label="null" :emit-path="false" />
</el-form-item>
<el-form-item label="网格化地图" prop="scopeImg">
<FileUploader v-model="formData.scopeImg" :limit="1" />
</el-form-item>
<el-form-item label="备注" prop="note">
<el-input v-model="formData.note" placeholder="请输入备注" />
</el-form-item>
</el-form>
<template #footer>
<div class="dialog-footer">
<el-button @click="handleCancel">取消</el-button>
<el-button v-if="!isReadonly" type="primary" @click="handleSubmit()"> 保存 </el-button>
</div>
</template>
</el-dialog>
</div> </div>
</template> </template>
<script setup> <script setup>
import { reactive, ref } from 'vue'; // ---------------------------------------------------------------------
import { useApp } from '@/hooks'; // avue-crud
// ---------------------------------------------------------------------
import { ref, reactive, watch, onMounted, computed, nextTick } from 'vue';
import { CRUD_OPTIONS } from '@/config'; import { CRUD_OPTIONS } from '@/config';
import { isEmpty, downloadFile } from '@/utils'; import { ElMessage, ElMessageBox } from 'element-plus';
import { useUserStore } from '@/store/modules/user'; 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 UserStore = useUserStore();
const crudRef = ref(null); const user = UserStore.getUserInfo();
const state = reactive({ console.log('admin 属性:', user.admin);
loading: false,
query: { const loading = ref(false);
current: 1,
size: 10, const visible = ref(false);
gridName: '', const isReadonly = ref(false);
regionCode: '', const dialogTitle = ref();
}, const formData = ref({
form: {}, gridName: '',
selection: [], gridAreaCode: '',
options: { scope: '',
...CRUD_OPTIONS, scopeImg: '',
addBtnText: '添加网格', note: '',
// detail: true,
// detailTitle: '',
column: [
{
label: '网格编号',
prop: 'id',
},
{
label: '网格名称',
prop: 'gridName',
rules: {
required: true,
message: '请输入',
trigger: 'blur',
},
},
{
label: '所属行政区域',
prop: 'gridAreaName',
addDisplay: false,
viewDisplay: true,
rules: {
required: true,
message: '请输入',
trigger: 'blur',
},
},
{
label: '所属行政区域',
prop: 'cities',
type: 'cascader',
hide: true,
span: 24,
width: 300,
addDisplay: true,
editDisplay: true,
viewDisplay: false,
emitPath: false,
props: {
label: 'areaName',
value: 'areaCode',
children: 'areaChildVOS',
},
dicUrl: `${VITE_APP_BASE_API}/system/area/region?areaCode=530000`,
dicHeaders: {
authorization: UserStore.token,
},
dicFormatter: (res) => res.data ?? [],
rules: {
required: true,
message: '请选择',
trigger: 'blur',
},
},
{
label: '网格地图',
prop: 'mapUrl',
type: 'upload',
hide: true,
// action: `${VITE_APP_BASE_API}/system/file/upload`,
},
// {
// label: '',
// prop: 'gridName',
// type: 'select',
// addDisplay: false,
// hide: true,
// // search: true,
// searchLabelWidth: 100,
// dicUrl: `${VITE_APP_BASE_API}/land-resource/gridManage/page?regionCode={{key}}`,
// props: {
// label: 'gridName',
// value: 'gridName',
// },
// dicHeaders: {
// authorization: UserStore.token,
// },
// dicFormatter: (res) => res.data?.records,
// },
{
label: '备注',
prop: 'note',
type: 'textarea',
span: 24,
rows: 4,
overHidden: true,
// width: 200,
},
{
label: '创建时间',
prop: 'createTime',
width: 200,
hide: true,
display: false,
},
],
actions: [
{
name: '查看',
icon: 'view',
event: ({ row }) => rowView(row),
},
{
name: '编辑',
icon: 'edit',
event: ({ row }) => rowEdit(row),
},
{
type: 'danger',
name: '删除',
icon: 'delete',
event: ({ row }) => rowDel(row),
},
],
},
pageData: {
total: 0,
currentPage: 1,
pageSize: 10,
},
data: [],
currentRow: {},
}); });
const baseDetailOption = { const initialFormData = { ...formData.value };
const resetForm = () => {
formData.value = { ...initialFormData };
};
const pageData = ref({
currentPage: 1,
pageSize: 10,
total: 0,
});
const searchForm = ref({
gridName: '',
keyword: '',
regionCode: '',
id: '',
status: -1,
});
const initialSearchForm = { ...searchForm.value };
const resetSearch = () => {
searchForm.value = { ...initialSearchForm };
};
//
const filterObject = (obj) => {
const newObj = {};
Object.keys(obj).forEach((key) => {
const value = obj[key];
// null undefined
if (value !== '' && value !== null && value !== undefined) {
newObj[key] = value;
}
});
return newObj;
};
const crudData = ref([]);
const crudOptions = reactive({
...CRUD_OPTIONS,
addBtn: false,
searchBtn: false,
emptyBtn: false,
column: [ column: [
{ label: '网格编号', prop: 'id' },
{ label: '网格名称', prop: 'gridName' },
{ label: '所属行政区域', prop: 'gridAreaName' },
{ label: '备注', prop: 'note' },
],
actions: [
{ {
label: '网格名称', name: '查看',
prop: 'gridName', icon: 'view',
event: ({ row }) => handleView(row),
}, },
{ {
label: '所属行政区域', name: '编辑',
prop: 'gridAreaName', icon: 'edit',
event: ({ row }) => handleEdit(row),
}, },
{ {
label: '备注', type: 'danger',
prop: 'note', name: '删除',
icon: 'delete',
event: ({ row }) => handleDelete(row),
}, },
], ],
});
const handleRefresh = async () => {
searchForm.value = { ...initialSearchForm };
getData();
}; };
const handleCurrentChange = (val) => {
const otherDetailOption = { pageData.value.currentPage = val;
column: [
{
label: '创建时间',
prop: 'createTime',
},
// ...
],
}; };
const handleSizeChange = (val) => {
// pageData.value.pageSize = val;
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;
});
}; };
const handleView = (row) => {
loadData(); isReadonly.value = true;
formData.value = { ...row };
// dialogTitle.value = '查看网格';
const currentChange = (current) => { visible.value = true;
state.query.current = current;
loadData();
}; };
const handleEdit = (row) => {
// isReadonly.value = false;
const sizeChange = (size) => { formData.value = { ...row };
state.query.size = size; dialogTitle.value = '编辑网格';
loadData(); visible.value = true;
}; };
const handleDelete = async (row) => {
// try {
const searchChange = (params, done) => { await ElMessageBox.confirm('确认删除该网格吗?', '提示', {
if (done) done();
state.query = params;
state.query.current = 1;
loadData();
};
//
const refreshChange = () => {
loadData();
app.$message.success('刷新成功');
};
//
const selectionChange = (rows) => {
state.selection = rows;
};
//
const rowView = (row) => {
crudRef.value.rowView(row);
};
const setCity = (row) => {
if (!isEmpty(row.cities)) {
row.provinceCode = row?.cities[0] ?? null;
row.cityCode = row?.cities[1] ?? null;
row.gridAreaCode = row?.cities[4] ?? null;
row.townCode = row?.cities[3] ?? null;
row.village = row?.cities[4] ?? null;
// row.village = row?.cities.join(',');
}
};
//
const rowSave = (row, done, loading) => {
setCity(row);
AddEntity(row)
.then((res) => {
if (res.code === 200) {
app.$message.success('添加成功!');
done();
loadData();
}
})
.catch((err) => {
app.$message.error(err.msg);
})
.finally(() => {
loading();
});
};
//
const rowEdit = (row) => {
const village = !isEmpty(row.village) ? row.village : [];
row.cities = compact([row.provinceCode, row.cityCode, row.gridAreaCode ?? '', row.townCode ?? '', ...village]);
crudRef.value.rowEdit(row);
};
const rowUpdate = (row, index, done, loading) => {
setCity(row);
UpdateEntity(row)
.then((res) => {
if (res.code === 200) {
app.$message.success('更新成功!');
done();
loadData();
}
})
.catch((err) => {
app.$message.error(err.msg);
})
.finally(() => {
loading();
});
};
//
const rowDel = (row, index, done) => {
if (isEmpty(row)) return;
app
.$confirm(`删除后信息将不可查看,确认要删除吗?`, '确定删除', {
confirmButtonText: '确定', confirmButtonText: '确定',
cancelButtonText: '取消', cancelButtonText: '取消',
type: 'warning', type: 'warning',
}) });
.then(() => {
DeleteEntity({ id: row.id }) const response = await deleteGrid(row.id);
.then((res) => {
if (res.code === 200) { ElMessage.success('删除成功');
app.$message.success('删除成功!'); getData();
loadData(); } catch (error) {
} if (error === 'cancel') {
}) ElMessage.info('已取消删除');
.catch((err) => { } else {
app.$message.error(err.msg); ElMessage.error('删除失败');
}); console.error('删除异常:', error);
}) }
.catch(() => {}); }
}; };
// const handleSubmit = async () => {
const onExport = () => { console.log('提交表单:', formData.value);
if (isEmpty(state.data)) { try {
app.$message.error('当前暂时没有可供导出的数据!'); if (dialogTitle.value === '新增网格') {
return; await createGrid(formData.value);
ElMessage.success('新增成功');
resetForm();
visible.value = false;
getData();
} else {
await updateGrid(formData.value);
ElMessage.success('更新成功');
resetForm();
visible.value = false;
getData();
}
} catch (error) {
ElMessage.error(error.message || '新增失败,请重试');
} }
state.loading = true; };
const fileName = '网格明细表';
ExportEntity(state.query) // ---------------------------------------------------------------------
.then((res) => { //
if (res.status === 200) { // ---------------------------------------------------------------------
downloadFile(res.data, `${fileName}.xlsx`, 'blob'); import { createGrid, updateGrid, deleteGrid, fetchGridList, getGridDetail, exportGrid } from '@/apis/landResourceManagement/gridManagement';
app.$message.success('导出成功!');
} onMounted(() => {
}) getData();
.catch((err) => { });
app.$message.error('导出失败!'); const getData = async () => {
}) const filteredParams = filterObject(searchForm.value);
.finally(() => { const response = await fetchGridList(filteredParams);
state.loading = false; crudData.value = Array.isArray(response.data.records) ? response.data.records : [];
}); };
const handleAdd = () => {
console.log('handleAdd');
resetForm();
isReadonly.value = false;
dialogTitle.value = '新增网格';
visible.value = true;
};
const handleSearch = () => {
getData();
};
const handleCancel = () => {
visible.value = false;
}; };
</script> </script>
<style scoped lang="scss">
:deep(.el-dialog__body) {
padding: 20px;
height: calc(100vh - 300px);
overflow-y: auto;
}
.form-title {
font-size: 16px;
font-weight: 500;
margin: 30px 0;
color: #333333;
}
.form-item {
width: 500px;
margin: 0 auto;
}
.dialog-footer {
text-align: center;
}
.custom-search {
display: flex;
align-items: center;
margin-bottom: 16px;
.el-button {
margin-left: 12px;
}
}
</style>

View File

@ -0,0 +1,392 @@
<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 #search="{ size }">
<AreaCascader v-model:value="state.query" placeholder="选择行政区域与网格" :width="400" />
</template>
<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 #detail="scope">
<el-tabs type="border-card">
<el-tab-pane label="基本信息">
<avue-detail :option="baseDetailOption" :data="scope.row"></avue-detail>
</el-tab-pane>
<el-tab-pane label="网格地图">
<div v-if="scope.row.mapUrl" style="height: 400px">
<img :src="scope.row.mapUrl" style="max-width: 100%; max-height: 100%" />
</div>
<el-empty v-else description="暂无地图数据"></el-empty>
</el-tab-pane>
<el-tab-pane label="其他信息">
<avue-detail :option="otherDetailOption" :data="scope.row"></avue-detail>
</el-tab-pane>
</el-tabs>
</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 state = reactive({
loading: false,
query: {
current: 1,
size: 10,
gridName: '',
regionCode: '',
},
form: {},
selection: [],
options: {
...CRUD_OPTIONS,
addBtnText: '添加网格',
// detail: true,
// detailTitle: '',
column: [
{
label: '网格编号',
prop: 'id',
addDisplay: false,
},
{
label: '网格名称',
prop: 'gridName',
rules: {
required: true,
message: '请输入',
trigger: 'blur',
},
},
{
label: '所属行政区域',
prop: 'gridAreaName',
addDisplay: false,
viewDisplay: true,
rules: {
required: true,
message: '请输入',
trigger: 'blur',
},
},
{
label: '所属行政区域',
prop: 'cities',
type: 'cascader',
hide: true,
span: 24,
width: 300,
addDisplay: true,
editDisplay: true,
viewDisplay: false,
emitPath: false,
props: {
label: 'areaName',
value: 'areaCode',
children: 'areaChildVOS',
},
dicUrl: `${VITE_APP_BASE_API}/system/area/region?areaCode=530000`,
dicHeaders: {
authorization: UserStore.token,
},
dicFormatter: (res) => res.data ?? [],
rules: {
required: true,
message: '请选择',
trigger: 'blur',
},
},
{
label: '网格地图',
prop: 'mapUrl',
type: 'upload',
hide: true,
// action: `${VITE_APP_BASE_API}/system/file/upload`,
},
// {
// label: '',
// prop: 'gridName',
// type: 'select',
// addDisplay: false,
// hide: true,
// // search: true,
// searchLabelWidth: 100,
// dicUrl: `${VITE_APP_BASE_API}/land-resource/gridManage/page?regionCode={{key}}`,
// props: {
// label: 'gridName',
// value: 'gridName',
// },
// dicHeaders: {
// authorization: UserStore.token,
// },
// dicFormatter: (res) => res.data?.records,
// },
{
label: '备注',
prop: 'note',
type: 'textarea',
span: 24,
rows: 4,
overHidden: true,
// width: 200,
},
{
label: '创建时间',
prop: 'createTime',
width: 200,
hide: true,
display: false,
},
],
actions: [
{
name: '查看',
icon: 'view',
event: ({ row }) => rowView(row),
},
{
name: '编辑',
icon: 'edit',
event: ({ row }) => rowEdit(row),
},
{
type: 'danger',
name: '删除',
icon: 'delete',
event: ({ row }) => rowDel(row),
},
],
},
pageData: {
total: 0,
currentPage: 1,
pageSize: 10,
},
data: [],
currentRow: {},
});
const baseDetailOption = {
column: [
{
label: '网格名称',
prop: 'gridName',
},
{
label: '所属行政区域',
prop: 'gridAreaName',
},
{
label: '备注',
prop: 'note',
},
],
};
const otherDetailOption = {
column: [
{
label: '创建时间',
prop: 'createTime',
},
// ...
],
};
//
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 rowView = (row) => {
crudRef.value.rowView(row);
};
const setCity = (row) => {
if (!isEmpty(row.cities)) {
row.provinceCode = row?.cities[0] ?? null;
row.cityCode = row?.cities[1] ?? null;
row.gridAreaCode = row?.cities[4] ?? null;
row.townCode = row?.cities[3] ?? null;
row.village = row?.cities[4] ?? null;
// row.village = row?.cities.join(',');
}
};
//
const rowSave = (row, done, loading) => {
setCity(row);
row.gridAreaCode = row.cities;
AddEntity(row)
.then((res) => {
if (res.code === 200) {
app.$message.success('添加成功!');
done();
loadData();
}
})
.catch((err) => {
app.$message.error(err.msg);
})
.finally(() => {
loading();
});
};
//
const rowEdit = (row) => {
const village = !isEmpty(row.village) ? row.village : [];
row.cities = compact([row.provinceCode, row.cityCode, row.gridAreaCode ?? '', row.townCode ?? '', ...village]);
crudRef.value.rowEdit(row);
};
const rowUpdate = (row, index, done, loading) => {
setCity(row);
UpdateEntity(row)
.then((res) => {
if (res.code === 200) {
app.$message.success('更新成功!');
done();
loadData();
}
})
.catch((err) => {
app.$message.error(err.msg);
})
.finally(() => {
loading();
});
};
//
const rowDel = (row, index, done) => {
if (isEmpty(row)) return;
app
.$confirm(`删除后信息将不可查看,确认要删除吗?`, '确定删除', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning',
})
.then(() => {
DeleteEntity({ id: row.id })
.then((res) => {
if (res.code === 200) {
app.$message.success('删除成功!');
loadData();
}
})
.catch((err) => {
app.$message.error(err.msg);
});
})
.catch(() => {});
};
//
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

@ -48,26 +48,27 @@
</template> </template>
</avue-crud> </avue-crud>
<el-dialog v-model="addDialogVisible" :title="isEdit ? '编辑网格员' : '新增网格员'" width="600px"> <el-dialog :key="dialogTitle" v-model="addDialogVisible" :title="isEdit ? '编辑网格员' : '新增网格员'" width="60%" align-center :draggable="true">
<el-form ref="addFormRef" :model="addForm" :rules="addFormRules" label-width="120px"> <el-form ref="addFormRef" :model="addForm" :rules="addFormRules" label-width="120px" class="form-item">
<p class="form-title">填写网格员信息</p>
<el-form-item label="网格员姓名" prop="memberName"> <el-form-item label="网格员姓名" prop="memberName">
<el-input v-model="addForm.memberName" style="width: 380px" /> <el-input v-model="addForm.memberName" />
</el-form-item> </el-form-item>
<el-form-item label="" prop="gridId" label-width="0px"> <el-form-item label="" prop="gridId" label-width="0px">
<!-- 假设 AreaCascader 是行政区域-网格的级联选择组件 --> <!-- 假设 AreaCascader 是行政区域-网格的级联选择组件 -->
<AreaCascader v-model:region-code="addForm.gridAreaCode" v-model:grid-id="addForm.gridId" split-rows label="" /> <AreaCascader v-model:region-code="addForm.gridAreaCode" v-model:grid-id="addForm.gridId" split-rows label="" />
</el-form-item> </el-form-item>
<el-form-item label="电话号码" prop="phone"> <el-form-item label="电话号码" prop="phone">
<el-input v-model="addForm.phone" style="width: 380px" /> <el-input v-model="addForm.phone" />
</el-form-item> </el-form-item>
<el-form-item label="备注" prop="note"> <el-form-item label="备注" prop="note">
<el-input v-model="addForm.note" type="textarea" style="width: 380px" /> <el-input v-model="addForm.note" type="textarea" />
</el-form-item> </el-form-item>
</el-form> </el-form>
<template #footer> <template #footer>
<span class="dialog-footer"> <span class="dialog-footer">
<el-button @click="addDialogVisible = false">取消</el-button> <el-button @click="addDialogVisible = false">取消</el-button>
<el-button type="primary" @click="submitAddForm">确定</el-button> <el-button type="primary" @click="submitForm">确定</el-button>
</span> </span>
</template> </template>
</el-dialog> </el-dialog>
@ -270,6 +271,7 @@ const selectionChange = (rows) => {
}; };
const rowView = (row) => { const rowView = (row) => {
isEdit.value = false;
crudRef.value.rowView(row); crudRef.value.rowView(row);
}; };
@ -280,6 +282,7 @@ const rowEdit = (row) => {
}; };
// //
const onAdd = () => { const onAdd = () => {
isEdit.value = false;
addDialogVisible.value = true; addDialogVisible.value = true;
// //
Object.keys(addForm).forEach((key) => { Object.keys(addForm).forEach((key) => {
@ -351,6 +354,11 @@ const onExport = () => {
</script> </script>
<style scoped lang="scss"> <style scoped lang="scss">
:deep(.el-dialog__body) {
padding: 20px;
height: calc(100vh - 300px);
overflow-y: auto;
}
.custom-page { .custom-page {
padding: 20px; padding: 20px;
.custom-search { .custom-search {
@ -394,4 +402,23 @@ const onExport = () => {
} }
} }
} }
.form-title {
font-size: 16px;
font-weight: 500;
margin: 30px 0;
color: #333333;
}
.form-item {
width: 500px;
margin: 0 auto;
}
.dialog-footer {
text-align: center;
}
:deep(.area-cascader-label) {
padding: 0 12px 0 0;
margin: 0;
width: 120px;
box-sizing: border-box;
}
</style> </style>

View File

@ -86,10 +86,10 @@
<el-button :disabled="data.length == 0" :type="data.length != 0 ? 'primary' : 'info'" @click="toSettlement">结算</el-button> <el-button :disabled="data.length == 0" :type="data.length != 0 ? 'primary' : 'info'" @click="toSettlement">结算</el-button>
</div> </div>
</div> </div>
<!-- <div class="pagination"> <div class="pagination">
<div style="color: #999999; font-size: 15px">{{ data.total }}</div> <div style="color: #999999; font-size: 15px">{{ total }}</div>
<el-pagination :page-size="20" :pager-count="11" layout="prev, pager, next" :total="data.total" /> <el-pagination :page-size="20" :pager-count="11" layout="prev, pager, next" :total="total" @change="pagination" />
</div> --> </div>
</div> </div>
</div> </div>
</template> </template>
@ -112,12 +112,12 @@ const route = useRoute();
const router = useRouter(); const router = useRouter();
let number = ref(1); let number = ref(1);
let total = ref(99); let total = ref(0);
let isAll = ref(false); let isAll = ref(false);
let data = ref([]); let data = ref([]);
let page = reactive({ let page = reactive({
current: 1, current: 1,
size: 100, size: 20,
}); });
let ids = ref([]); let ids = ref([]);
@ -157,10 +157,19 @@ let datalist = reactive([
onMounted(() => { onMounted(() => {
shoppingCart(page).then((res) => { shoppingCart(page).then((res) => {
data.value = res.data.records; data.value = res.data.records;
total.value = res.data.total;
addIsCheckProperty(data); addIsCheckProperty(data);
}); });
}); });
const pagination = (value) => {
page.current = value;
shoppingCart(page).then((res) => {
data.value = res.data.records;
addIsCheckProperty(data);
});
};
function addIsCheckProperty(data) { function addIsCheckProperty(data) {
if (Array.isArray(data)) { if (Array.isArray(data)) {
data.forEach((item) => { data.forEach((item) => {
@ -411,6 +420,7 @@ function removeCheckedItems(data) {
background: $color-fff; background: $color-fff;
} }
.fix-top { .fix-top {
z-index: 999;
top: 0; top: 0;
display: inline-flex; display: inline-flex;
justify-content: space-between; justify-content: space-between;
@ -461,8 +471,8 @@ function removeCheckedItems(data) {
bottom: 38px; bottom: 38px;
} }
.fix-bottom { .fix-bottom {
// bottom: 30px; bottom: 30px;
bottom: 0; // bottom: 0;
display: inline-flex; display: inline-flex;
justify-content: space-between; justify-content: space-between;
width: 100%; width: 100%;

View File

@ -40,6 +40,7 @@
</div> </div>
</el-scrollbar> </el-scrollbar>
</div> </div>
<!-- <div style="background-color: #fff; margin-bottom: 20px">订单备注</div> -->
<div class="order-info"> <div class="order-info">
<div class="order-info-top">确认订单信息</div> <div class="order-info-top">确认订单信息</div>

View File

@ -341,6 +341,9 @@ const back = () => {
.order-list-warp-left { .order-list-warp-left {
width: 55%; width: 55%;
height: 70vh; height: 70vh;
overflow: hidden;
overflow-y: scroll;
scrollbar-width: none;
.order-list-warp-left-title { .order-list-warp-left-title {
margin-top: 20px; margin-top: 20px;
font-size: 18px; font-size: 18px;