feat:土地违法处理接口对接完成

This commit is contained in:
李想 2025-03-11 16:02:07 +08:00
parent 2dd8edd26a
commit d173c4205c
10 changed files with 395 additions and 147 deletions

View File

@ -15,8 +15,8 @@
@row-update="handleUpdete"
>
<template #menu="{ index, row }">
<el-dropdown popper-class="custom-table-operate">
<el-icon class="custom-table-operate__more"><More /></el-icon>
<el-dropdown>
<el-icon style="padding: 14px 0"><More /></el-icon>
<template #dropdown>
<el-dropdown-menu>
<template v-for="item in actions" :key="item.name">

View File

@ -64,12 +64,5 @@ watch(
}
}
}
::v-deep() {
.is-active {
.el-radio-button__inner {
background-color: rgb(255, 45, 45) !important;
}
}
}
}
</style>

View File

@ -0,0 +1,86 @@
<template>
<el-radio-group v-model="val" class="radio_group" style="margin-bottom: 30px" @change="emit('update:value', val)">
<el-radio-button v-for="item in options" :key="'radio_' + item.value" :value="item.value" color="red">
{{ item.label }}
</el-radio-button>
</el-radio-group>
</template>
<script setup>
import { ref, reactive, watch } from 'vue';
const props = defineProps({
value: {
type: String,
default: '1',
},
});
const emit = defineEmits(['update:value']);
/* --------------- data --------------- */
// #region
const val = ref('1');
watch(
() => props.value,
() => (val.value = props.value),
{
deep: true,
immediate: true,
}
);
const options = reactive([
{
value: '1',
label: '红榜',
},
{
value: '2',
label: '黑榜',
},
]);
// #endregion
/* --------------- methods --------------- */
// #region
// #endregion
</script>
<style lang="scss" scoped>
.radio_group {
justify-content: center;
width: 100%;
font-size: 18px;
> label {
width: 12%;
::v-deep() {
.el-radio-button__inner {
width: 100%;
}
}
}
::v-deep() {
.el-radio-button__inner {
font-size: 18px;
font-weight: bold;
font-family: '黑体';
}
.is-active {
.el-radio-button__inner {
background-color: unset !important;
}
}
&:nth-child(1) {
.el-radio-button__inner {
background-color: red !important;
color: #fff;
border-color: red !important;
}
}
&:nth-child(2) {
.el-radio-button__inner {
color: rgba(28, 111, 255, 0.77) !important;
border-color: #c5c5c5 !important;
}
}
}
}
</style>

View File

@ -1,45 +1,62 @@
<template>
<section class="rank_content" :style="{ '--theme': props.type == 1 ? 'red' : 'black' }">
<!-- <h2>{{ props.type == '1' ? '红' : '黑' }}</h2> -->
<TypeRadio v-model:value="radio" :options="options" />
<section>{{ radio }}</section>
<div v-for="(item, i) in props.data" :key="`rank_${props.type}_${i}`" class="rank_item">
<div class="name">{{ item.name }}</div>
<div></div>
<div></div>
<div></div>
<section class="rank_content" :style="{ '--theme': radio == '1' ? 'red' : 'black' }">
<RankType v-model:value="radio" />
<div class="rank_item rank_header">
<div class="index_">排名</div>
<div>企业名称</div>
<div>上榜理由</div>
<div>企业类型</div>
</div>
<div v-for="(item, i) in radio == '1' ? props.data.red : props.data.black" :key="`rank_${props.type}_${i}`" class="rank_item">
<div class="index_">{{ i + 1 }}</div>
<div>{{ item.name }}</div>
<div>{{ item.reason }}</div>
<div>{{ item.type }}</div>
</div>
</section>
</template>
<script setup>
import { reactive, ref } from 'vue';
import TypeRadio from '../../common/TypeRadio.vue';
import RankType from './RankType.vue';
const props = defineProps({
type: {
type: String,
default: '1',
},
data: {
type: Array,
default: () => [],
type: Object,
default: () => {
return {
red: [
{
name: '企业1',
reason: '企业1',
type: '生产商',
},
{
name: '企业2',
reason: '好好好好好好好好好好好好好好好好好好好好好好好好好好好好好好好好好好好好好好好好好好好好好好好好',
type: '生产商',
},
{
name: '企业3',
reason: '2222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222',
type: '生产商',
},
],
black: [
{
name: '企业222',
reason: '不好不好不好不好不好不好不好不好不好不好不好不好不好不好不好不好不好不好不好不好不好不好不好不好不好不好不好不好不好不好不好',
type: '经销商',
},
],
};
},
},
});
/* --------------- data --------------- */
// #region
const radio = ref('1');
const options = reactive([
{
value: '1',
label: '红榜',
},
{
value: '2',
label: '黑榜',
},
]);
// #endregion
/* --------------- methods --------------- */
@ -49,8 +66,12 @@ const options = reactive([
</script>
<style lang="scss" scoped>
div,
section {
box-sizing: border-box;
}
.rank_content {
border: 1px solid skyblue;
font-size: 16px;
border-radius: 2px;
h2 {
padding: 4px 0;
@ -59,22 +80,33 @@ const options = reactive([
text-align: center;
color: var(--theme);
}
.rank_header {
> div {
background-color: var(--theme);
color: #fff;
}
}
> .rank_item {
display: grid;
grid-template-columns: repeat(4, 1fr);
border-top: 1px solid skyblue;
grid-template-columns: calc(13% + 1px) 39% 24% 24%;
border-top: 1px solid #c6c6c6;
> div {
padding: 6px 12px;
border-right: 1px solid skyblue;
border-right: 1px solid #c6c6c6;
text-align: center;
word-break: break-all;
}
:last-child {
border-right: none;
:first-child {
border-left: 1px solid #c6c6c6;
}
.name {
font-size: 18px;
color: var(--theme);
font-weight: bold;
.index_ {
color: #fff;
background-color: var(--theme);
}
}
.rank_item:last-child {
border-bottom: 1px solid #c6c6c6;
}
}
</style>

View File

@ -1,8 +1,8 @@
<template>
<CustomCard>
<section class="rank_container">
<RankCard type="1" :data="redData" />
<RankCard type="2" :data="blackData" />
<RankCard />
<RankCard />
</section>
</CustomCard>
</template>
@ -72,7 +72,7 @@ const blackData = ref(JSON.parse(JSON.stringify(redData.value)));
padding: 40px 0;
display: grid;
justify-content: center;
grid-template-columns: calc(30%) calc(30%);
grid-template-columns: calc(40%) calc(40%);
gap: 40px;
}
</style>

View File

@ -12,10 +12,10 @@
>
<el-icon class="custom-form__uploader__icon"><Plus /></el-icon>
</el-upload>
<div v-for="item in attrs_" :key="`attr_${item.id}`" class="attrs_content__item">
<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" />
<el-icon v-if="props.type != 'view'" class="clear_btn" @click="handleClearAttr(item.id)"><CircleCloseFilled /></el-icon>
<el-icon v-if="props.type != 'view'" class="clear_btn" @click="handleClearAttr(item.uid)"><CircleCloseFilled /></el-icon>
</div>
</section>
</template>
@ -54,8 +54,8 @@ watch(
},
{ deep: true, immediate: true }
);
function handleClearAttr(id) {
attrs_.value = attrs_.value.filter((item) => item.id !== id);
function handleClearAttr(uid) {
attrs_.value = attrs_.value.filter((item) => item.uid !== uid);
emit('update:attrs', attrs_.value);
}
async function rowUploadPicture({ file }) {
@ -65,7 +65,7 @@ async function rowUploadPicture({ file }) {
if (res.code === 200) {
attrs_.value.push({
...res.data,
id: 'id_' + Date.now(),
uid: 'id_' + Date.now(),
});
emit('update:attrs', attrs_.value);
}

View File

@ -1,22 +1,21 @@
<template>
<el-upload
ref="upload"
class="upload-demo"
:limit="props.limit"
:auto-upload="false"
:file-list="fileList"
:on-change="fileChange"
:before-remove="handleDelFile"
>
<el-upload ref="upload" :file-list="fileList" class="upload-demo" :limit="props.limit" :auto-upload="false" :on-change="fileChange">
<el-button type="primary" :disabled="fileList.length == 5">点击上传</el-button>
<template #tip>
<div v-if="props.format.length" class="el-upload__tip">只能上传{{ props.format.join() }} 文件且不超过20MB</div>
</template>
<template #file="{ file }">
<section class="file_line">
<span class="name_">{{ file.name }}</span>
<el-icon v-if="props.type == 'view'" @click="handleDown(file)"><Download /></el-icon>
<el-icon v-else @click="handleDelFile(file)"><Close /></el-icon>
</section>
</template>
</el-upload>
</template>
<script setup>
import { ref, watch } from 'vue';
import { ref, watch, nextTick } from 'vue';
import { ElMessage } from 'element-plus';
import { CommonUpload } from '@/apis';
@ -38,11 +37,15 @@ const props = defineProps({
type: Number,
default: 20,
},
type: {
type: String,
default: 'view',
},
});
/* --------------- data --------------- */
// #region
const upload = ref();
const fileList = ref([]);
watch(
() => props.attrs,
@ -80,7 +83,10 @@ function delAttr(uid, list = []) {
let i = list.findIndex((v) => v.uid == uid);
if (i < 0) return;
else list.splice(i, 1);
emit('update:attrs', fileList.value);
nextTick(() => {
fileList.value = JSON.parse(JSON.stringify(list));
emit('update:attrs', fileList.value);
});
}
async function rowUploadPicture({ raw, name, uid }) {
@ -97,8 +103,33 @@ async function rowUploadPicture({ raw, name, uid }) {
emit('update:attrs', fileList.value);
}
}
async function handleDown(file) {
let res = await fetch(file.url);
let blob = await res.blob();
let link = window.URL.createObjectURL(blob);
let a = document.createElement('a');
a.download = file.name;
a.href = link;
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
}
// #endregion
</script>
<style lang="scss" scoped></style>
<style lang="scss" scoped>
.file_line {
padding: 0 12px;
display: flex;
justify-content: space-between;
align-items: center;
.name_ {
flex: 1;
margin-right: 24px;
}
.el-icon {
font-size: 16px;
cursor: pointer;
}
}
</style>

View File

@ -7,23 +7,28 @@
:option="option"
:data="data"
:table-loading="_loading"
:before-open="handleOpenFrom"
:before-close="handleCloseFrom"
@current-change="handlePageChange"
@size-change="handleSizeChange"
@search-change="handleSearch"
@search-reset="handleResetSearch"
@row-save="handleRowSave"
@row-update="handleExamine"
@cell-click="handleCellClick"
>
<template #menu="{ row }">
<el-button type="primary" @click="handleInfo(row)">登记处理</el-button>
<el-button v-if="row.status == '0'" type="primary" @click="handleInfo(row)">登记处理</el-button>
</template>
<template #sceneProof-form>
<template #status="{ row }"> {{ row.status == '0' ? '未' : '已' }}处理 </template>
<template #sceneProof-form="{ row, type }">
<section class="proof_content_">
<span>照片视频</span>
<Attrs v-model:attrs="examineForm.proof" type="add" :limit="5" :file-num="5" accept="image/*,video/*" />
<span v-if="type == 'add'">照片视频</span>
<Attrs v-model:attrs="examineForm.proof" :type="type" :limit="5" :file-num="5" accept="image/*,video/*" />
</section>
</template>
<template #attrs_-form>
<FileUpload v-model:attrs="examineForm.attrs" :format="['rar', 'zip', 'doc', 'docx', 'pdf']" />
<template #attrs_-form="{ row, type }">
<FileUpload v-model:attrs="examineForm.attrs" :format="['rar', 'zip', 'doc', 'docx', 'pdf']" :type="type" />
</template>
</avue-crud>
</CustomCard>
@ -31,7 +36,7 @@
</template>
<script setup>
import { ref, reactive, h, onMounted } from 'vue';
import { ref, reactive, h, onMounted, watch } from 'vue';
import { CRUD_OPTIONS } from '@/config';
import CustomCard from '@/components/CustomCard.vue';
import { useUserStore } from '@/store/modules/user';
@ -40,20 +45,19 @@ import FileUpload from './common/FileUpload.vue';
import { getLandIllegal, createLandIllegal, registerLandIllegal, illegalInfo } from '@/apis/land';
import { ElMessage, ElMessageBox } from 'element-plus';
import Attrs from '../../common/Attrs.vue';
import { add } from 'lodash';
const { VITE_APP_BASE_API } = import.meta.env;
const UserStore = useUserStore();
onMounted(() => {
getList();
});
onMounted(getList);
/* --------------- data --------------- */
// #region
const crudRef = ref();
const searchData = ref({
caseId: '',
caseResult: '',
status: '',
});
const page = ref({
currentPage: 1,
@ -63,11 +67,52 @@ const page = ref({
const _loading = ref(false);
const data = ref([]);
const landsArr = ref([]);
const resultData = ref([
{
label: '正常营业,无违规行为',
value: 1,
},
{
label: '简易程序,当场行政处罚',
value: 2,
},
{
label: '普通程序,当场处罚立案审批',
value: 3,
},
{
label: '移送程序,案件移送',
value: 4,
},
{
label: '特殊程序,案件终止',
value: 5,
},
]);
const documentData = ref([
{
label: '协助调查函',
value: 1,
},
{
label: '抽样取样凭证',
value: 2,
},
{
label: '检测报告',
value: 3,
},
{
label: '其他文书',
value: 4,
},
]);
const option = ref({
...CRUD_OPTIONS,
refreshBtn: false,
rowKey: 'caseId',
editTitle: '案件登记处理',
selection: false,
column: [
{
label: '案件编号',
@ -179,16 +224,21 @@ const option = ref({
},
{
label: '案件进度',
prop: 'caseResult',
prop: 'status',
display: false,
search: true,
type: 'select',
dicData: [
{ label: '未处理', value: 0 },
{ label: '已处理', value: 1 },
],
addDisplay: true,
editDisplay: false,
viewDisplay: false,
},
{
label: '案件结果',
prop: 'caseResult',
prop: 'status',
display: false,
addDisplay: true,
editDisplay: false,
@ -232,9 +282,9 @@ const option = ref({
},
{
label: '关联地块',
prop: 'land',
prop: 'relatedLandname',
render: ({ row }) => {
return h('span', {}, row.land);
return h('span', {}, row.relatedLandname);
},
},
{
@ -281,6 +331,13 @@ const option = ref({
span: 24,
display: true,
editDisplay: true,
rules: [
{
required: true,
message: '请输入',
trigger: 'blur',
},
],
},
{
label: '现场取证',
@ -292,33 +349,34 @@ const option = ref({
{
label: '执法文书',
prop: 'lawDocument',
labelSuffix: '件',
span: 24,
display: true,
type: 'radio',
editDisplay: true,
dicData: [
viewDisplay: false,
addDisplay: false,
dicData: documentData.value,
rules: [
{
label: '协助调查函',
value: 1,
},
{
label: '抽样取样凭证',
value: 2,
},
{
label: '检测报告',
value: 3,
},
{
label: '其他文书',
value: 4,
required: true,
message: '请选择',
trigger: 'blur',
},
],
},
{
label: '执法文书',
prop: 'lawDocument',
span: 24,
addDisplay: false,
editDisplay: false,
viewDisplay: true,
render: ({ row }) => {
return h('span', {}, documentData.value.find((item) => item.value == row.lawDocument)?.label);
},
},
{
label: '',
prop: 'attrs_',
span: 24,
},
],
},
@ -331,32 +389,27 @@ const option = ref({
label: '案件处理结果',
prop: 'caseResult',
type: 'radio',
value: 1,
dicData: [
dicData: resultData.value,
span: 24,
addDisplay: false,
viewDisplay: false,
rules: [
{
label: '正常营业,无违规行为',
value: 1,
},
{
label: '简易程序,当场行政处罚',
value: 2,
},
{
label: '普通程序,当场处罚立案审批',
value: 3,
},
{
label: '移送程序,案件移送',
value: 4,
},
{
label: '特殊程序,案件终止',
value: 5,
required: true,
message: '请选择',
trigger: 'blur',
},
],
},
{
label: '案件处理结果',
prop: 'caseResult',
span: 24,
display: true,
editDisplay: true,
addDisplay: false,
editDisplay: false,
render: ({ row }) => {
return h('span', {}, resultData.value.find((item) => item.value == row.caseResult)?.label);
},
},
],
},
@ -370,6 +423,16 @@ const examineForm = reactive({
proof: [],
attrs: [],
});
watch(
() => examineForm,
() => {
console.log('examineForm', examineForm.attrs);
},
{
deep: true,
immediate: true,
}
);
// #endregion
/* --------------- methods --------------- */
@ -377,21 +440,21 @@ const examineForm = reactive({
// #region
async function getList() {
_loading.value = true;
let params = {
current: page.value.currentPage,
size: page.value.pageSize,
...searchData.value,
};
console.log('params -- ', params);
let res = await getLandIllegal(params);
console.log('res -- ', res);
_loading.value = false;
if (res.code == 200) {
data.value = res.data.records;
page.value.total = res.data.total;
}
}
function handlePageChange(val) {
console.log('page', val);
page.value.currentPage = val;
getList();
}
@ -407,13 +470,16 @@ function handleInfo(row) {
crudRef.value.rowEdit(row);
// crudRef.value.rowView(row);
}
function handleSearch(form, done) {
console.log('search', form);
let t = setTimeout(() => {
clearTimeout(t);
done();
}, 1000);
async function handleSearch(form, done) {
page.value.currentPage = 1;
await getList();
done();
}
async function handleResetSearch() {
page.value.currentPage = 1;
await getList();
}
async function handleRowSave(val, done, loading) {
let data = {
caseId: val.caseId,
@ -438,11 +504,9 @@ async function handleRowSave(val, done, loading) {
confirmButtonText: '是,现在添加',
cancelButtonText: '否,后续添加',
type: 'success',
})
.then(() => {
// getDetails('c-1');
})
.catch(() => {});
}).then(() => {
getDetails(val.caseId);
});
}
loading();
}
@ -460,18 +524,60 @@ async function handleExamine(val, done, loading) {
if (examineForm.attrs.length > 0) {
data.lawFile = examineForm.attrs.map((v) => `${v.name}&${v.url}`).join();
}
console.log('val', data);
let res = await registerLandIllegal(data);
console.log('res --', res);
loading();
if (res.code == 200) {
ElMessage.success('提交成功');
getList();
}
}
async function getDetails(id) {
async function getDetails(id, type = 'add') {
examineForm.caseId = id;
let res = await illegalInfo(id);
console.log('detaile', res);
if (res.code == 200) {
console.log('detaile', res);
if (res.data.evidenceFile) {
examineForm.proof = res.data.evidenceFile.split(',').map((v, i) => {
return {
url: v,
uid: `id_${i}_${Date.now()}`,
};
});
}
if (res.data.lawFile) {
examineForm.attrs = res.data.lawFile.split(',').map((v, i) => {
let [name, url] = v.split('&');
return {
name,
url,
uid: `id_${i}_${Date.now()}`,
status: 'success',
};
});
}
type == 'add' ? crudRef.value.rowEdit(res.data) : crudRef.value.rowView(res.data);
}
}
const cellClick = ref(['caseId', 'caseName']);
function handleCellClick(row, column) {
if (cellClick.value.includes(column.columnKey)) {
getDetails(row.caseId, 'view');
}
}
function handleOpenFrom(done, type) {
console.log('form open', type);
let lab = type == 'view' ? '执法文书附件' : '';
if (type == 'view') {
option.value.group.find((v) => v.prop == 'caseHandle').column.find((v) => v.prop == 'attrs_').label = lab;
}
done();
}
function handleCloseFrom(done) {
console.log('form close');
examineForm.caseId = '';
examineForm.proof = [];
examineForm.attrs = [];
done();
}
// #endregion
</script>

View File

@ -11,9 +11,9 @@
>
<el-icon class="custom-form__uploader__icon"><Plus /></el-icon>
</el-upload>
<div v-for="item in attrs_" :key="`attr_${item.id}`" class="attrs_content__item">
<div v-for="item in attrs_" :key="`attr_${item.uid}`" class="attrs_content__item">
<img :src="item.url" :alt="item.name" style="" />
<el-icon v-if="props.view != 'view'" class="clear_btn" @click="handleClearAttr(item.id)"><CircleCloseFilled /></el-icon>
<el-icon v-if="props.view != 'view'" class="clear_btn" @click="handleClearAttr(item.uid)"><CircleCloseFilled /></el-icon>
</div>
</section>
</template>
@ -44,8 +44,8 @@ watch(
},
{ deep: true, immediate: true }
);
function handleClearAttr(id) {
attrs_.value = attrs_.value.filter((item) => item.id !== id);
function handleClearAttr(uid) {
attrs_.value = attrs_.value.filter((item) => item.uid !== uid);
emit('update:attrs', attrs_.value);
}
async function rowUploadPicture({ file }) {
@ -55,7 +55,7 @@ async function rowUploadPicture({ file }) {
if (res.code === 200) {
attrs_.value.push({
...res.data,
id: 'id_' + Date.now(),
uid: 'id_' + Date.now(),
});
emit('update:attrs', attrs_.value);
}

View File

@ -469,7 +469,7 @@ function handleView(obj) {
return {
name: `产权附件_${i}`,
url: v,
id: 'id_' + Date.now(),
uid: 'id_' + Date.now(),
};
});
}
@ -478,7 +478,7 @@ function handleView(obj) {
return {
name: `使用信息附件_${i}`,
url: v,
id: 'id_' + Date.now(),
uid: 'id_' + Date.now(),
};
});
if (obj.landUrl) {
@ -486,7 +486,7 @@ function handleView(obj) {
return {
name: `位置附件_${i}`,
url: v,
id: 'id_' + Date.now(),
uid: 'id_' + Date.now(),
};
});
}