This commit is contained in:
lzc 2025-03-21 16:48:43 +08:00
commit deb882fa58
20 changed files with 448 additions and 143 deletions

View File

@ -2,14 +2,18 @@
<div :class="`custom-table-tree ${shadow ? 'custom-table-tree__shadow' : ''}`">
<div v-if="title" class="title">{{ title }}</div>
<el-tree
node-key="id"
:data="data"
:node-key="option.nodeKey"
:show-checkbox="option.showCheckbox"
:default-expanded-keys="option.defaultExpandedKeys"
:default-checked-keys="option.defaultCheckedKeys"
:props="option.defaultProps"
:props="option.props ?? option.defaultProps"
@node-click="handleNodeClick"
/>
>
<template #default="{ data: rows }">
<slot :data="rows"></slot>
</template>
</el-tree>
</div>
</template>
<script setup name="custom-table-tree">
@ -21,7 +25,9 @@ const props = defineProps({
type: Object,
default: () => {
return {
nodeKey: 'id',
showCheckbox: false,
props: {},
defaultProps: {
children: 'children',
label: 'label',
@ -34,8 +40,8 @@ const props = defineProps({
});
const emit = defineEmits(['node-click']);
const handleNodeClick = (data) => {
emit('node-click', data);
const handleNodeClick = (data, node) => {
emit('node-click', data, node);
};
</script>
<style lang="scss" scoped>

View File

@ -1,4 +1,4 @@
import request from '@/utils/request';
import request from '@/utils/request'
// 登录方法
export function login(username, password, code, uuid) {
@ -10,7 +10,7 @@ export function login(username, password, code, uuid) {
},
method: 'post',
data: { username, password, code, uuid },
});
})
}
// 注册方法
@ -22,7 +22,7 @@ export function register(data) {
},
method: 'post',
data: data,
});
})
}
// 刷新方法
@ -30,7 +30,7 @@ export function refreshToken() {
return request({
url: '/auth/refresh',
method: 'post',
});
})
}
// 获取用户详细信息
@ -38,7 +38,7 @@ export function getInfo() {
return request({
url: '/system/user/getInfo',
method: 'get',
});
})
}
// 退出方法
@ -46,7 +46,7 @@ export function logout() {
return request({
url: '/auth/logout',
method: 'delete',
});
})
}
// 获取验证码
@ -58,5 +58,5 @@ export function getCodeImg() {
},
method: 'get',
timeout: 20000,
});
})
}

View File

@ -7,14 +7,13 @@ const TokenKey = 'Admin-Token';
const ExpiresInKey = 'Admin-Expires-In';
export function getToken() {
return true
// let token = Cookies.get(TokenKey);
// if (undefined === token || null == token || 'null' === token) {
// token = getQueryString('Authorization');
// if (null != token || 'null' !== token) Cookies.set(TokenKey, token);
// }
// if (undefined === token || null == token || 'null' === token) token = false;
// return token;
let token = Cookies.get(TokenKey);
if (undefined === token || null == token || 'null' === token) {
token = getQueryString('Authorization');
if (null != token || 'null' !== token) Cookies.set(TokenKey, token);
}
if (undefined === token || null == token || 'null' === token) token = false;
return token;
}
export function setToken(token) {

View File

@ -28,7 +28,7 @@ service.interceptors.request.use(
// 是否需要防止数据重复提交
const isRepeatSubmit = (config.headers || {}).repeatSubmit === false;
if (getToken() && !isToken) {
config.headers['Authorization'] = 'Bearer ' + getToken(); // 让每个请求携带自定义token 请根据实际情况自行修改
config.headers['Authorization'] = getToken(); // 让每个请求携带自定义token 请根据实际情况自行修改
}
// get请求映射params参数
if (config.method === 'get' && config.params) {

View File

@ -18,7 +18,7 @@ module.exports = {
// 部署生产环境和开发环境下的URL。
// 默认情况下Vue CLI 会假设你的应用是被部署在一个域名的根路径上
// 例如 https://www.ruoyi.vip/。如果应用被部署在一个子路径上,你就需要用这个选项指定这个子路径。例如,如果你的应用被部署在 https://www.ruoyi.vip/admin/,则设置 baseUrl 为 /admin/。
publicPath: `/sub-admin/`,
publicPath: './',
// 在npm run build 或 yarn build 时 生成文件的目录名称要和baseUrl的生产环境路径一致默认dist
outputDir: 'dist',
// 用于放置生成的静态资源 (js、css、img、fonts) 的;(项目打包之后,静态资源会放在这个文件夹下)
@ -68,7 +68,7 @@ module.exports = {
libraryTarget: 'umd', // 把微应用打包成 umd 库格式
jsonpFunction: `${name}`,
filename: `[name].[hash].js`,
chunkFilename: `[name].[hash].js`
chunkFilename: `[name].[hash].js`,
},
plugins: [
new CompressionPlugin({

View File

@ -1,9 +1,11 @@
import * as redBlackApi from './redAndBlank';
import * as materialApi from './material';
import * as knowledgeApi from './knowledge';
import * as leaseSuperviseApi from './leaseSupervise';
export default {
...materialApi,
...redBlackApi,
...knowledgeApi,
...leaseSuperviseApi,
};

View File

@ -0,0 +1,16 @@
import request from '@/utils/axios';
/* 租赁列表 */
export function getLeaseSuperviseList(params) {
return request('/input/machineLease/page', {
params,
});
}
/* 新增租赁 */
export function addLeaseSupervise(data) {
return request('/input/machineLease/save', {
method: 'POST',
data,
});
}

View File

@ -40,3 +40,32 @@ export const CRUD_VIEW_OPTIONS = {
selection: false,
menu: false,
};
/**
* @Title: 生成avue校验规则
* @param {Object} set 校验配置对象
* @param {string} set.msg 校验失败提示
* @param {Array<string>} set.trigger 校验触发条件
* @param {Array} set.otherRules 其他校验规则
* @returns {Array} 校验规则数组
*/
export function customRules(set = {}) {
const obj = Object.assign(
{
msg: '必要参数,不能为空',
trigger: ['change', 'blur'],
otherRules: [],
},
set
);
const { msg, trigger, otherRules } = obj;
let rulesArr = [
{
required: true,
message: msg,
trigger,
},
...otherRules,
];
return rulesArr;
}

View File

@ -3,14 +3,14 @@
* @Author: zenghua.wang
* @Date: 2023-06-20 14:29:45
* @LastEditors: zenghua.wang
* @LastEditTime: 2025-02-13 16:02:18
* @LastEditTime: 2025-03-20 14:04:09
-->
<template>
<el-breadcrumb class="layout-breadcrumb" separator="/">
<transition-group name="breadcrumb">
<el-breadcrumb-item v-if="matched[0].meta.title !== '首页'" key="home" :to="{ path: '/' }">
<el-breadcrumb-item v-if="matched[0].meta.title !== '政务服务'" key="home" :to="{ path: '/' }">
<div class="layout-breadcrumb-item">
<span class="layout-breadcrumb-title">首页</span>
<span class="layout-breadcrumb-title">政务服务</span>
</div>
</el-breadcrumb-item>
<el-breadcrumb-item v-for="(item, index) in matched" :key="item.name">

View File

@ -3,7 +3,7 @@
* @Author: zenghua.wang
* @Date: 2023-06-20 11:48:41
* @LastEditors: zenghua.wang
* @LastEditTime: 2025-03-12 11:10:12
* @LastEditTime: 2025-03-20 14:40:44
*/
import { createRouter, createWebHistory } from 'vue-router';
import Layout from '@/layouts/index.vue';

View File

@ -99,24 +99,24 @@ const inputSuppliesRoutes = [
// },
// ],
// },
{
path: '/sub-government-affairs-service/enterpriseDealerCheck',
name: 'enterpriseDealerCheck',
component: () => import('@/views/inputSuppliesManage/enterpriseDealerCheck/index.vue'),
meta: { title: '企业经销商抽检', icon: 'Document' },
},
// {
// path: '/sub-government-affairs-service/enterpriseDealerCheck',
// name: 'enterpriseDealerCheck',
// component: () => import('@/views/inputSuppliesManage/enterpriseDealerCheck/index.vue'),
// meta: { title: '企业经销商抽检', icon: 'Document' },
// },
// {
// path: '/sub-government-affairs-service/useSupervise',
// name: 'useSupervise',
// component: () => import('@/views/inputSuppliesManage/useSupervise/index.vue'),
// meta: { title: '使用监管', icon: 'Document' },
// },
// {
// path: '/sub-government-affairs-service/leaseSupervise',
// name: 'leaseSupervise',
// component: () => import('@/views/inputSuppliesManage/leaseSupervise/index.vue'),
// meta: { title: '农机租赁监管', icon: 'Document' },
// },
{
path: '/sub-government-affairs-service/leaseSupervise',
name: 'leaseSupervise',
component: () => import('@/views/inputSuppliesManage/leaseSupervise/index.vue'),
meta: { title: '农机租赁监管', icon: 'Document' },
},
{
path: '/sub-government-affairs-service/redBlackRank',
name: 'redBlackRank',

View File

@ -3,13 +3,14 @@
<div>
<el-row :gutter="20">
<el-col :span="4">
<el-tree
<!-- <el-tree
style="max-width: 600px"
:data="typeTree"
node-key="areaCode"
:props="{ children: 'areaChildVOS', label: 'areaName' }"
@node-click="handleNodeClick"
/>
/> -->
<custom-table-tree title="行政区域" :data="typeTree" :option="treeOption" @node-click="handleNodeClick" />
</el-col>
<el-col :span="20">
<avue-crud
@ -126,35 +127,13 @@ const state = reactive({
currentRow: {},
});
let typeTree = ref([
// {
// label: '',
// id: '0',
// level: '0',
// children: [
// {
// label: '1',
// level: '1',
// id: '01',
// children: [
// { label: '1', children: [], id: '0101', pId: '01', level: '2' },
// { label: '2', children: [], id: '0102', pId: '01', level: '2' },
// ],
// pId: '0',
// },
// { label: '2', level: '1', children: [], id: '02', pId: '0' },
// ],
// },
// {
// label: '1',
// id: '1',
// level: '0',
// children: [{ label: '1', children: [], id: '11', pId: '10', level: '1' }],
// },
]);
let townOptions = reactive([]);
let infoData = reactive({
const typeTree = ref([]);
const treeOption = ref({
nodeKey: 'areaCode',
props: { children: 'areaChildVOS', label: 'areaName' },
});
const townOptions = reactive([]);
const infoData = reactive({
countyId: '',
townId: '',
name: '',

View File

@ -1,3 +0,0 @@
<template>
<div>开发中</div>
</template>

View File

@ -1,5 +1,5 @@
<template>
<section class="custom_attrs_upload_content_lx" :style="{ '--columns': props.fileNum }">
<section class="custom_attrs_upload_content_lx" :style="{ '--columns': props.fileNum, padding: props.type == 'view' ? '20px 0' : '0px' }">
<el-upload
v-if="props.type != 'view' && props.upBtn"
class="custom-form__uploader"
@ -39,7 +39,7 @@ const props = defineProps({
},
limit: {
type: Number,
default: 1,
default: 5,
},
fileNum: {
type: Number,

View File

@ -20,8 +20,8 @@
@row-save="handleRowSave"
@row-update="handleRowUpdate"
>
<template #emnu="{ row }">
<el-button>button</el-button>
<template #menu="{ row }">
<el-button type="primary">详情</el-button>
</template>
</avue-crud>
</CustomCard>
@ -51,12 +51,15 @@ const data = ref([]);
const option = reactive({
...CRUD_OPTIONS,
selection: false,
refreshBtn: false,
column: [
{
hide: true,
search: true,
label: '关键字',
prop: 'keywords',
addDisplay: false,
viewDisplay: false,
},
{
label: '任务编号',

View File

@ -1,19 +1,262 @@
<template>
<CustomCard>租赁监管</CustomCard>
<CustomCard>
<h2>农机租赁管理</h2>
<br />
<avue-crud
ref="crudRef"
v-model:search="searchCondition"
v-model:page="pageData"
:data="data"
:option="option"
:table-loading="_loading"
:before-close="handleDialogClose"
@search-change="
(form, done) => {
getData(1);
done();
}
"
@search-reset="() => getData(1)"
@current-change="getData"
@size-change="getData"
@row-save="handleRowSave"
>
<template #menu="{ row }">
<el-button type="primary" @click="handleView(row)">详情</el-button>
</template>
<template #certiUrl-form="{ type }">
<Attrs v-model:attrs="certiAttrs" :type="type" :file-num="2" />
</template>
<template #contractUrl-form="{ type }">
<Attrs v-model:attrs="contractAttrs" :type="type" :file-num="2" />
</template>
</avue-crud>
</CustomCard>
</template>
<script setup>
import { ref } from 'vue';
import { ref, reactive, onMounted, h } from 'vue';
import CustomCard from '@/components/CustomCard.vue';
import { CRUD_OPTIONS, customRules } from '@/config';
import Attrs from '../common/Attrs.vue';
import inputSuppliesApi from '@/apis/inputSuppliesApi';
import { ElMessage } from 'element-plus';
onMounted(getData);
/* --------------- data --------------- */
// #region
const crudRef = ref();
const _loading = ref(false);
const searchCondition = ref({
tenant: '',
});
const pageData = ref({
currentPage: 1,
pageSize: 10,
total: 0,
});
const data = ref([]);
const option = reactive({
...CRUD_OPTIONS,
selection: false,
refreshBtn: false,
dialogWidth: '50%',
column: [
{
hide: true,
search: true,
label: '关键字',
prop: 'tenant',
addDisplay: false,
viewDisplay: false,
},
{
label: '承租方',
prop: 'tenant',
rules: customRules({ msg: '请输入承租方姓名' }),
},
{
hide: true,
label: '出租方',
prop: 'lessor',
rules: customRules({ msg: '请输入出租方姓名' }),
},
{
label: '承租方联系方式',
prop: 'tenantPhone',
rules: customRules({ msg: '请输入承租方联系方式' }),
},
{
hide: true,
label: '出租方联系方式',
prop: 'lessorPhone',
rules: customRules({ msg: '请输入出租方联系方式' }),
},
{
label: '租赁设备',
prop: 'leaseEquipment',
rules: customRules({ msg: '请输入租赁设备' }),
},
{
label: '租赁数量',
prop: 'leaseNumber',
type: 'number',
min: 1,
step: 1,
stepStrictly: true,
suffix: '台',
viewDisplay: false,
rules: customRules({ msg: '请输入租赁数量' }),
render: ({ row }) => `${row.leaseNumber}`,
},
{
hide: true,
label: '租赁数量',
prop: 'leaseNumber1',
addDisplay: false,
// renderForm: ({ row }) => h('span', {}, `${row.leaseNumber}`),
},
{
hide: true,
label: '支付方式',
prop: 'payMethod',
rules: customRules({ msg: '请选择支付方式' }),
},
{
label: '租赁期限',
prop: 'term',
addDisplay: false,
},
{
hide: true,
label: '租金',
prop: 'rent',
type: 'number',
min: 1,
step: 0.01,
precision: 2,
stepStrictly: true,
suffix: '元/天/台',
rules: customRules({ msg: '请输入租赁价格' }),
},
{
label: '合同金额',
prop: 'allMoney',
addDisplay: false,
rules: customRules({ msg: '请输入合同金额' }),
},
{
hide: true,
label: '起止时间',
prop: 'startEndTime',
type: 'datetimerange',
format: 'YYYY-MM-DD HH:mm',
valueFormat: 'YYYY-MM-DD HH:mm',
startPlaceholder: '开始时间',
endPlaceholder: '终止时间',
span: 24,
rules: customRules({ msg: '请选择起止时间' }),
},
{
hide: true,
label: '机械合格证',
prop: 'certiUrl',
},
{
hide: true,
label: '租赁合同',
prop: 'contractUrl',
},
],
});
const certiAttrs = ref([]);
const contractAttrs = ref([]);
// #endregion
/* --------------- methods --------------- */
// #region
function handleDialogClose(done) {
certiAttrs.value = [];
contractAttrs.value = [];
done();
}
async function getData(resetPage) {
resetPage === 1 && (pageData.value.currentPage = 1);
_loading.value = true;
let params = Object.assign(
{
current: pageData.value.currentPage,
size: pageData.value.pageSize,
},
searchCondition.value
);
let res = await inputSuppliesApi.getLeaseSuperviseList(params);
_loading.value = false;
if (res.code == 200) {
data.value = res.data.records.map((v) => {
let d = leaseDate(v.startEndTime);
let obj = {
...v,
leaseNumber1: v.leaseNumber + '台',
term: d + '天',
allMoney: (v.rent * v.leaseNumber * d).toFixed(2) + '元',
};
return obj;
});
pageData.value.total = res.data.total;
}
}
async function handleRowSave(form, done, loading) {
let data = Object.assign({}, form);
delete data.allMoney;
if (certiAttrs.value.length) {
data.certiUrl = certiAttrs.value.map((v) => v.url).join();
}
if (contractAttrs.value.length) {
data.contractUrl = contractAttrs.value.map((v) => v.url).join();
}
data.startEndTime = data.startEndTime.join();
let res = await inputSuppliesApi.addLeaseSupervise(data);
loading();
if (res.code == 200) {
getData();
ElMessage.success('租赁信息添加成功');
// done();
}
}
function handleView(row) {
if (row.certiUrl) {
certiAttrs.value = row.certiUrl.split(',').map((v, i) => {
return {
url: v,
uid: `certi_${i}_${Date.now()}`,
};
});
}
if (row.contractUrl) {
contractAttrs.value = row.contractUrl.split(',').map((v, i) => {
return {
url: v,
uid: `contract_${i}_${Date.now()}`,
};
});
}
crudRef.value.rowView(row);
}
function leaseDate(date) {
let n = 0;
if (date) {
let arr = date.split(',');
let a1 = new Date(arr[0]).getTime();
let a2 = new Date(arr[1]).getTime();
n = Math.ceil((a2 - a1) / (1000 * 60 * 60 * 24));
}
return n;
}
// #endregion
</script>

View File

@ -38,6 +38,14 @@
</template>
</el-popconfirm>
</template>
<template #area-form="{ row, type }">
<section class="area_form_" style="">
<el-input-number v-model="landArea" :min="1" controls-position="right"></el-input-number>
<el-select v-model="unitValue">
<el-option v-for="item in unitOptions" :key="'unitOptions_' + item.value" :label="item.label" :value="item.value" />
</el-select>
</section>
</template>
<template #propertyCertificateUrl-form="{ type }">
<Attrs v-model:attrs="attrs" :type="type" />
</template>
@ -88,6 +96,13 @@ const params = ref({
const local_ = ref([102.833669, 24.88149, '昆明市']);
const local = ref(JSON.parse(JSON.stringify(local_.value)));
const landTreeDic = ref([]);
const landArea = ref(1);
const unitValue = ref('0');
const unitOptions = reactive([
{ label: '平方米', value: '0' },
{ label: '亩', value: '1' },
{ label: '公顷', value: '2' },
]);
/* --------------- data --------------- */
// #region
const loading = ref(false);
@ -150,6 +165,13 @@ const option = reactive({
addDisplay: false,
display: false,
editDisplay: false,
render: ({ row }) => {
let s = '';
if (row.area && row.landUnit) {
s = row.area + unitOptions.find((v) => v.value == row.landUnit).label;
}
return s;
},
},
{
label: '坐标',
@ -514,6 +536,8 @@ function handleCloseFrom(done) {
landOwnerAttrs.value = [];
attrs.value = [];
landAttrs.value = [];
landArea.value = 1;
unitValue.value = '0';
local.value = JSON.parse(JSON.stringify(local_.value));
done();
}
@ -533,6 +557,8 @@ async function handleRowSave(val, done, loading) {
if (landAttrs.value.length) {
landAttrs.value.forEach((item) => landUrls.push(item.url));
}
data.area = landArea.value;
data.landUnit = unitValue.value;
data.propertyCertificateUrl = urls.join();
data.landCertificateUrl = landOwnerUrls.join();
data.landUrl = landUrls.join();
@ -611,4 +637,20 @@ function newTree(arr, i) {
}
}
}
.area_form_ {
display: grid;
grid-template-columns: 75% 25%;
::v-deep() {
.el-input-number {
width: 100%;
.el-input__wrapper {
border-radius: 4px 0 0 4px;
}
}
.el-select__wrapper {
border-radius: 0 4px 4px 0 !important;
border-left: none;
}
}
}
</style>

View File

@ -15,29 +15,8 @@ export default function useLandHook() {
label: '园林',
},
]);
const landClassificationType = reactive([
{ label: '耕地', value: '0' },
{ label: '果园', value: '1' },
{ label: '茶园', value: '2' },
{ label: '其他园地', value: '3' },
{ label: '林地', value: '4' },
{ label: '草地', value: '5' },
{ label: '其他农用地', value: '6' },
{ label: '农村宅基地', value: '7' },
]);
function handleIficationType(t = 0) {
let arr = landClassificationType.filter((v) => v.value == t);
let txt = '--';
if (arr.length > 0) {
txt = arr[0].label;
}
return txt;
}
return {
landType,
landsType,
landClassificationType,
handleIficationType,
};
}

View File

@ -91,31 +91,61 @@ const state = reactive({
overHidden: true,
},
{
label: '地块名',
prop: 'p2',
width: 200,
type: 'cascader',
// hide: true,
// addDisplay: true,
// editDisplay: true,
// viewDisplay: 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 ?? [],
label: '基地分类',
prop: 'type',
type: 'select',
dicData: [
{
label: '种植基地',
value: 1,
},
{
label: '养殖基地',
value: 2,
},
],
rules: {
required: true,
message: '请选择',
message: '请输入',
trigger: 'blur',
},
overHidden: true,
},
{
label: '地块名',
prop: 'landName',
width: 200,
formslot: true,
rules: {
required: true,
message: '请输入',
trigger: 'blur',
},
},
// {
// label: '',
// prop: 'p2',
// width: 200,
// type: 'select',
// // addDisplay: true,
// // editDisplay: true,
// // viewDisplay: 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',
// },
// overHidden: true,
// },
{
label: '区域位置',
prop: 'p3',
@ -136,26 +166,6 @@ const state = reactive({
trigger: 'blur',
},
},
{
label: '基地分类',
prop: 'type',
type: 'select',
dicData: [
{
label: '种植基地',
value: 1,
},
{
label: '养殖基地',
value: 2,
},
],
rules: {
required: true,
message: '请输入',
trigger: 'blur',
},
},
{
label: '状态',
prop: 'status',
@ -273,8 +283,8 @@ const loadData = async () => {
await sleep(500);
state.data = mockData(
{
p1: '202501基地',
p2: '耿马镇1号地块',
p1: '耿马镇一号基地',
p2: '耿马镇2025001号地块',
p3: '耿马傣族佤族自治县/耿马镇',
p4: '1000',
p5: '张三',

View File

@ -3,7 +3,7 @@
* @Author: zenghua.wang
* @Date: 2022-09-18 21:24:29
* @LastEditors: zenghua.wang
* @LastEditTime: 2025-02-28 11:04:41
* @LastEditTime: 2025-03-20 14:24:31
*/
import { defineConfig, loadEnv } from 'vite';