Merge branch 'dev' into report

# Conflicts:
#	src/views/system/Repair/addRepairlist.vue
#	src/views/system/resident/addResident.vue
#	src/views/system/statistics/Personnel/index.vue
#	src/views/system/user/addUser.vue
This commit is contained in:
Zy
2026-08-20 17:06:42 +08:00
24 changed files with 444 additions and 117 deletions

View File

@@ -9,9 +9,9 @@ VITE_APP_ENV='development'
# 开发环境
VITE_APP_BASE_API='/dev-api'
# # 开发环境 接口代理地址
VITE_APP_PROXY_API='http://192.168.1.222:8080'
#VITE_APP_PROXY_API='http://192.168.1.222:8080'
# 开发环境 接口代理地址
#VITE_APP_PROXY_API='http://192.168.1.6:8080'
VITE_APP_PROXY_API='http://192.168.1.6:8080'
# 图片基础地址
VITE_IMG_URL='http://192.168.1.222:8080'

View File

@@ -20,7 +20,7 @@ export const listComplaint = (query?: ComplaintQuery): AxiosPromise<ComplaintVO[
* 查询投诉管理详细
* @param id
*/
export const getComplaint = (id: string | number): AxiosPromise<ComplaintVO> => {
export const getComplaint = (id: string): AxiosPromise<ComplaintVO> => {
return request({
url: '/complaint/' + id,
method: 'get'

View File

@@ -30,7 +30,7 @@ export interface ComplaintVO {
problemIamgeUrl: string;
/**
* 投诉状态 0待处理 1处理中 2已处理
* 投诉状态 0 待处理 1 已处理
*/
status: string;

View File

@@ -20,9 +20,13 @@ export interface BillVO {
* 收费范围 0全体业主 1部分业主
*/
chargeScope: string;
/**
* 按季度收费时,指定季度起始年月列表,格式 "yyyy-MM",如 ["2026-01", "2026-04", "2026-07"]
*/
periodCalcType: string;
/**
* 收费周期 0年 1月 2日
* 收费周期 0年 1月 2日 3 季度 4永久为空时取账单配置
*/
chargePeriod: string;

View File

@@ -63,8 +63,7 @@ export const billEdit = (data: { 'detailsId': string[]; 'payType': string; 'payS
return request({
url: '/cash/billEdit',
method: 'post',
data: data,
data: data
});
};
@@ -76,6 +75,25 @@ export const billPrint = (data: { 'detailsIds': string[]; 'residentId': string }
data: data
});
};
// 查询所有账单总金额
export const getAllAccount = (
data = {}
): AxiosPromise<{
/** 总金额 */
'receivableAmount': string;
/** 总实收金额 */
'receivedAmount': string;
/** 总优惠金额 */
'discountAmount': string;
/** 未收金额 */
'unpaidAmount': string;
}> => {
return request({
url: '/cash/billAmountSummary',
method: 'post',
data: data
});
};
// 删除账单
export const billDelete = (ids: string | string[]) => {

View File

@@ -117,6 +117,8 @@ export interface HouseRentalForm extends BaseEntity {
villageId?: string;
}
export interface HouseRentalSigningVO {
rentAmount: string | number;
depositAmount: string | number;
'id': string;
'rentalId': string;
'contractNo': string;

View File

@@ -0,0 +1,126 @@
<template>
<div class="quarter-select">
<!-- 输入框点击弹出popover -->
<el-popover v-model:visible="popoverVisible" placement="bottom-start" trigger="manual" width="240">
<div class="quarter-panel">
<!-- 年份切换 -->
<div class="year-header">
<el-button icon="ArrowLeft" size="small" circle @click="prevYear" />
<span class="current-year">{{ currentYear }}</span>
<el-button icon="ArrowRight" size="small" circle @click="nextYear" />
</div>
<!-- 四个季度按钮 -->
<div class="quarter-buttons">
<el-button
v-for="q in 4"
:key="q"
style="margin: 0"
:type="isSelected(currentYear, q) ? 'primary' : ''"
:disabled="isDisabledQuarter(currentYear, q)"
@click="handleSelect(currentYear, q)"
>
{{ q }}季度
</el-button>
</div>
</div>
<!-- 触发源 -->
<template #reference>
<el-input
:model-value="displayText"
placeholder="请选择季度"
readonly
suffix-icon="Calendar"
@click="popoverVisible = true"
clearable
@clear="handleClear"
/>
</template>
</el-popover>
</div>
</template>
<script setup lang="ts">
import { ref, computed } from 'vue';
// 外部vmodel绑定
const props = defineProps({
modelValue: {
type: String,
default: '' // "20261"
}
});
const emit = defineEmits(['update:modelValue', 'change']);
// popover弹窗
const popoverVisible = ref(false);
// 解析回显的季度值 20261
const parseQuarter = (str) => {
if (!str) return { year: new Date().getFullYear(), quarter: null };
const [y, q] = str.split('-').map(Number);
return { year: y, quarter: q };
};
const { year: initYear } = parseQuarter(props.modelValue);
const currentYear = ref(initYear);
console.log(currentYear.value, typeof currentYear.value);
// 输入框展示文本
const displayText = computed(() => {
if (!props.modelValue) return '';
console.log(props.modelValue, props.modelValue.trim().split('-'));
const [y, q] = props.modelValue.split('-').map(Number);
return `${y}${q}季度`;
});
// 是否选中该季度
const isSelected = (y, q) => {
return props.modelValue === `${y}-${q}`;
};
// --------------------------
// 【这里写你的禁用逻辑】仿照 disableddate
// return true 禁用该季度
// --------------------------
const isDisabledQuarter = () => {
return false;
};
// 切换年份
const prevYear = () => currentYear.value--;
const nextYear = () => currentYear.value++;
// 选中季度
const handleSelect = (y, q) => {
const val = `${y}-${q}`;
emit('update:modelValue', val);
emit('change', val);
popoverVisible.value = false;
};
// 清空
const handleClear = () => {
emit('update:modelValue', '');
emit('change', '');
};
</script>
<style scoped>
.quarter-panel {
padding: 12px;
}
.year-header {
display: flex;
align-items: center;
justify-content: space-between;
margin-bottom: 12px;
}
.current-year {
font-weight: 500;
}
.quarter-buttons {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 8px;
}
</style>

View File

@@ -125,7 +125,10 @@ const formInfo = ref({
'complaintName': '',
'phone': '',
'problemImageUrl': '',
'status': '1', // 投诉状态 0 待处理 1 已处理
/**
* 投诉状态 0 待处理 1 已处理╬╬╬╬╬╬
*/
'status': '1',
'handleId': '',
'handleName': '',
'handleContent': '',

View File

@@ -137,6 +137,7 @@ import { listDecoration, delDecoration, updateDecoration } from '@/api/system/De
import { DecorationVO, DecorationQuery, DecorationForm } from '@/api/system/Decoration/type';
import { checkPermi } from '@/utils/permission';
import { validator } from '@/utils/Reg';
import '@/types/axios.d.ts';
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
const { com_decoration_status } = toRefs<any>(proxy?.useDict('com_decoration_status'));
@@ -217,10 +218,14 @@ const { queryParams, form, rules } = toRefs(data);
/** 查询装修管理列表 */
const getList = async () => {
loading.value = true;
const res = await listDecoration(queryParams.value);
decorationList.value = res.rows;
total.value = res.total;
loading.value = false;
listDecoration(queryParams.value)
.then((res) => {
decorationList.value = res.rows;
total.value = res.total;
})
.finally(() => {
loading.value = false;
});
};
/** 取消按钮 */
@@ -248,6 +253,8 @@ const handleClear = () => {
/** 重置按钮操作 */
const resetQuery = () => {
queryFormRef.value?.resetFields();
queryParams.value.inspectionResult = undefined;
queryParams.value.applyName = undefined;
handleQuery();
};

View File

@@ -204,13 +204,18 @@ const dialogVisible = ref(false);
const handleRemove: UploadProps['onRemove'] = (uploadFile, uploadFiles) => {
console.log(uploadFile, uploadFiles);
};
const blockedExts = ['.exe', '.bat', '.cmd', '.msi'];
const blockedExits = ['.exe', '.bat', '.cmd', '.msi'];
const allUploadExits = ['.jpg', '.jpeg', '.png', '.gif', '.bmp'];
const handleChangeFile: UploadProps['beforeUpload'] = (rawFile: UploadRawFile) => {
const ext = rawFile.name.toLowerCase().slice(rawFile.name.lastIndexOf('.'));
if (blockedExts.includes(ext)) {
if (blockedExits.includes(ext)) {
ElMessage.warning(`禁止上传 ${ext} 文件`);
return false;
}
if (!allUploadExits.includes(ext)) {
ElMessage.warning(`请上传 图片格式 文件`);
return false;
}
return true;
};

View File

@@ -95,7 +95,7 @@ function handleChange(val: string) {
form.value.projectType = find.projectType;
}
}
// != ==========================================
// != ==========================================8
async function init() {
form.value = {

View File

@@ -43,8 +43,8 @@
<el-option v-for="(item, index) in com_charge_item_unit" :key="index" :value="item.value" :label="item.label"></el-option>
</el-select>
</el-form-item>
<el-form-item label="费用单价" prop="fixedPrice">
<el-input maxlength="10" v-model.trim="form.fixedPrice" :placeholder="placeHolderFun(form.typeId)" />
<el-form-item label="费用单价">
<el-input maxlength="10" v-model.trim.number="form.fixedPrice" :placeholder="placeHolderFun(form.typeId)" />
</el-form-item>
<el-form-item label="计算精度" prop="accuracy">
<el-select v-model="form.accuracy">

View File

@@ -48,8 +48,7 @@
</el-table-column>
<el-table-column label="单价" width="100" align="center" prop="fixedPrice">
<template #default="scope">
{{ scope.row.price }}
<dict-tag :options="com_charge_item_unit" :value="scope.row.fixedPrice"></dict-tag>
{{ scope.row.fixedPrice ?? '---' }}
</template>
</el-table-column>
<el-table-column label="计量单位" width="100" align="center" prop="unit">

View File

@@ -78,10 +78,46 @@
</div>
</el-form-item>
<el-form-item label="费用周期" prop="chargePeriod">
<el-select v-model="form.chargePeriod">
<el-select @change="handleChangePeriod" v-model="form.chargePeriod">
<el-option v-for="(item, index) in com_bill_charge_period" :key="index" :value="item.value" :label="item.label"></el-option>
</el-select>
</el-form-item>
<el-form-item v-if="form.chargePeriod !== '2'" label="周期计算维度" prop="periodCalcType">
<div class="w-full flex flex-row flex-items-center">
<el-select v-model="form.periodCalcType">
<el-option v-for="(item, index) in PeriodicCalculationDimensionList" :key="index" :value="item.value" :label="item.label"></el-option>
</el-select>
<el-tooltip class="box-item" effect="light" placement="top">
<el-icon style="margin-left: 10px" color="#909399"><QuestionFilled /></el-icon>
<template #content>
<div class="items">
<div class="label">自然年</div>
<div class="content">公历固定日历年1 1 12 31 </div>
</div>
<div class="items">
<div class="label">滚动年</div>
<div class="content">以某个实际发生的起始日期向后完整推算 12 个月不绑定 1 1 </div>
</div>
<div class="items">
<div class="label">自然月</div>
<div class="content">按公历日历整月计算每月 1 日到当月最后一天</div>
</div>
<div class="items">
<div class="label">滚动月</div>
<div class="content">以实际发生的某一天作为起点往后推算一个月不强制从 1 号开始</div>
</div>
<div class="items">
<div class="label">自然季度(日历季度)</div>
<div class="content">跟随公历日历固定划分属于日历周期</div>
</div>
<div class="items">
<div class="label">滚动季度(连续3个月)</div>
<div class="content">属于滚动周期以某个自定义起始日向后连续推 3 个自然月</div>
</div>
</template>
</el-tooltip>
</div>
</el-form-item>
<el-form-item label="起止日期" prop="startDate">
<el-date-picker
v-model="StartEndDate"
@@ -89,6 +125,7 @@
@update:model-value="handleDate"
@clear="handleClear"
:value-format="datepicker[2].format"
:disabled-date="handleDisableDate"
:format="datepicker[2].format"
:type="datepicker[2].type"
range-separator=""
@@ -96,18 +133,6 @@
end-placeholder="结束"
/>
</el-form-item>
<!-- <el-form-item label="结束日期" prop="price">
<el-date-picker
v-model="StartEndDate"
@update:model-value="handleDate"
:value-format="datepicker[2].format"
:format="datepicker[2].format"
:type="datepicker[2].type"
range-separator=""
start-placeholder="开始"
end-placeholder="结束"
/>
</el-form-item> -->
<el-form-item label="备注" prop="remark">
<el-input type="textarea" maxlength="200" show-word-limit :rows="5" v-model.trim="form.remark" placeholder="请输入" />
</el-form-item>
@@ -134,11 +159,12 @@ import { listChargeItem } from '@/api/system/SdbChargeItem';
import { getBill, updateBill, addBill } from '@/api/system/SdbBill';
import type { DatePickerType } from 'element-plus';
import { formatDate2 } from '@/utils';
import { QuestionFilled } from '@element-plus/icons-vue';
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
const { com_questionnaire_scope } = toRefs<any>(proxy?.useDict('com_questionnaire_scope'));
const { com_bill_charge_scope_house } = toRefs<any>(proxy?.useDict('com_bill_charge_scope_house'));
const { com_bill_charge_period } = toRefs<any>(proxy?.useDict('com_bill_charge_period'));
const { com_bill_charge_scope_house, com_questionnaire_scope, com_bill_charge_period } = toRefs<any>(
proxy?.useDict('com_bill_charge_scope_house', 'com_questionnaire_scope', 'com_bill_charge_period')
);
type PickerConfig = {
type: DatePickerType;
@@ -163,6 +189,7 @@ const form = ref({
residentIds: [], // 部分业主
parkingIds: [],
chargeTypeId: '', // typeid
periodCalcType: '0', // 周期计算维度
'startDate': '', // 开始
'endDate': '', // 结束
'remark': ''
@@ -172,12 +199,30 @@ const rules = ref({
chargeItemId: [{ required: true, message: '请选择 收费项目', trigger: 'blur' }],
chargePeriod: [{ required: true, message: '请选择 费用周期', trigger: 'blur' }],
startDate: [{ required: true, message: '请选择 起止日期', trigger: 'blur' }],
periodCalcType: [{ required: true, message: '请选择 周期计算维度', trigger: 'blur' }],
endDate: [{ required: true, message: '请选择 起止日期', trigger: 'blur' }]
});
const userid = ref(null);
// 开始结束日期
const StartEndDate = ref([]);
function handleDisableDate(date: Date) {
// 月 - 自然月/滚动月
if (form.value.periodCalcType === '0') {
// 自然月
const year = date.getFullYear();
const month = date.getMonth() + 1;
const firstDay = new Date(year, month - 1, 1);
const lastDay = new Date(year, month, 0);
if (date.getTime() == lastDay.getTime() || date.getTime() == firstDay.getTime()) {
return false;
}
return true;
} else if (form.value.periodCalcType === '1') {
// 滚动月
return false;
}
}
function handleDate(val: string[]) {
if (val === null || val.length === 0) {
form.value.startDate = '';
@@ -201,7 +246,6 @@ const chargeItemList = ref([]);
async function init() {
listChargeItem({}).then((res) => {
chargeItemList.value = res.rows;
// const res = await listBillHouse({ pageNum: 1, pageSize: 999999 });
// houselist.value = res.rows;
// const res2 = await queryResidentList_holder({ pageNum: 1, pageSize: 999999 });
@@ -215,15 +259,12 @@ async function init() {
...form.value,
...res.data
};
// TODO 没有住户参数
form.value.houseIds = res.data.houseIds || [];
form.value.residentIds = res.data.residentIds || [];
form.value.parkingIds = res.data.parkingIds || [];
form.value.startDate = formatDate2(form.value.startDate);
form.value.endDate = formatDate2(form.value.endDate);
StartEndDate.value = [form.value.startDate, form.value.endDate];
// TODO houseid 有默认值, 需要处理
// TODO residentids 添加,
checkoutHouses.value = [];
checkoutUser.value = [];
checkoutParking.value = [];
@@ -231,6 +272,7 @@ async function init() {
checkoutUser.value = form.value.residentIds.filter((item) => item);
checkoutParking.value = form.value.parkingIds.filter((item) => item);
handleChange(form.value.chargeItemId);
handleChangePeriod(form.value.chargePeriod);
});
}
});
@@ -315,10 +357,27 @@ function OpenUseTablesFun(val: string) {
}
}
// !== 业主 =============================================================================
const PeriodicCalculationDimensionList = ref([]);
function handleChangePeriod(val: string) {
const find = com_bill_charge_period.value.find((item: { value: string; label: string }) => item.value === val);
if (find) {
// 不是日,才显示自然和滚动周期
if (find.value === '2') return;
PeriodicCalculationDimensionList.value = [
{
label: find.value === '3' ? `自然${find.label}(日历季度)` : `自然${find.label}`,
value: '0'
},
{
label: find.value === '3' ? `滚动${find.label}(连续3个月)` : `滚动${find.label}`,
value: '1'
}
];
}
}
// !== 提交 =============================================================================
const submitForm = () => {
console.log(form.value);
formRef.value?.validate(async (valid: boolean) => {
if (valid) {
if (userid.value) {
@@ -342,6 +401,13 @@ const cancelForm = () => {
</script>
<style scoped lang="scss">
.items {
.label {
font-weight: bold;
width: 150px;
}
}
.AddBuildingBox {
padding: 15px;
height: 100%;
@@ -365,7 +431,7 @@ const cancelForm = () => {
}
.formBody {
width: 950px;
width: 650px;
margin: 0 auto;
.residentBox {

View File

@@ -77,15 +77,30 @@
placeholder="选择账单生成年份"
style="width: 100%"
/>
<!-- 滚动月份 -->
<el-date-picker
format="YYYY-MM"
value-format="YYYY-MM"
v-else
v-else-if="BillForm.chargePeriod === '1'"
v-model="BillForm.yearMonths"
:disabled-date="handleDisableMonth"
type="months"
placeholder="选择账单生成月份"
style="width: 100%"
/>
<!-- 滚动季度 -->
<el-date-picker
format="YYYY-MM"
value-format="YYYY-MM"
v-else-if="BillForm.chargePeriod === '3'"
v-model="BillForm.yearQuarters"
type="months"
placeholder="选择账单生成季度"
:disabled-date="handleDisableMonth"
style="width: 100%"
/>
<!-- 季度账单-滚动季度 -->
<!-- <QuarterSelect v-if="BillForm.chargePeriod === '3' && BillForm.periodCalcType === '1'" v-model="myQuarter" @change="onQuarterChange" />-->
</el-form-item>
<!-- <el-form-item label="选择生成账单的房屋">-->
<!-- <div class="flex flex-col">-->
@@ -239,16 +254,24 @@ const BillVisible = ref(false);
const BillForm = ref<{
title: string;
billId: string;
/**
* 收费周期 0年 1月 2日 3 季度 4永久为空时取账单配置
*/
chargePeriod: string;
chargeScope: string;
yearMonths?: string[];
periodCalcType: string;
houseId: string[];
yearQuarters?: string[];
year?: string[];
startDate?: string;
endDate?: string;
}>({
title: '',
billId: '',
chargePeriod: '1', // 账单类型
chargeScope: '0',
periodCalcType: '0',
houseId: []
});
// const HolderRef = ref<InstanceType<typeof House>>();
@@ -266,9 +289,14 @@ function handleChange(row: BillVO) {
BillForm.value.title = row.billName;
BillForm.value.chargePeriod = row.chargePeriod;
BillForm.value.billId = row.id;
BillForm.value.periodCalcType = row.periodCalcType;
BillForm.value.startDate = row.startDate;
BillForm.value.endDate = row.endDate;
if (BillForm.value.chargePeriod === '1') {
BillForm.value['yearMonths'] = [];
} else {
} else if (BillForm.value.chargePeriod === '3') {
BillForm.value['yearQuarters'] = [];
} else if (BillForm.value.chargePeriod === '0') {
BillForm.value['year'] = [];
}
}
@@ -281,6 +309,7 @@ function handleChangeApi() {
}
function clearChangeBillForm() {
BillForm.value = {
periodCalcType: undefined,
title: '',
billId: '',
chargePeriod: '1',
@@ -289,6 +318,17 @@ function clearChangeBillForm() {
};
}
function handleDisableMonth(date: Date) {
if (!BillForm.value.startDate || !BillForm.value.endDate) return false;
return date.getTime() < new Date(BillForm.value.startDate).getTime() || date.getTime() > new Date(BillForm.value.endDate).getTime();
}
const myQuarter = ref('2026-2');
function onQuarterChange(val: string) {
console.log(val);
}
onMounted(() => {
getList();
});

View File

@@ -441,7 +441,7 @@ import pagination from '@/components/Pagination/index.vue';
import DictTag from '@/components/DictTag/index.vue';
import { getBuildinglistAPI, getHouselistAPI } from '@/api/system/house';
import { getCommunitylistAPI } from '@/api/system/community';
import { billDelete, billEdit, billlistType, billPrint, BillPrintType, billQuery } from '@/api/system/SdbCashier';
import { billDelete, billEdit, billlistType, billPrint, BillPrintType, billQuery, getAllAccount } from '@/api/system/SdbCashier';
import { listChargeItem } from '@/api/system/SdbChargeItem';
import { ref } from 'vue';
import { add, div, eq, eqMoney, gtMoney, ltMoney, minMoney, moneyAdd, mul, sub, sum, toBig } from '@/utils/money';
@@ -574,6 +574,7 @@ function handleChangeBuilding(val: string): void {
// 选择 单元
function handleChangeUnit(val: string) {
const find = unitList.value.find((item) => item.unitNoId === val);
queryParams.value.houseId = undefined;
houseList.value = [];
if (find) {
houseList.value = find.floors;
@@ -606,7 +607,21 @@ function getList() {
.finally(() => {
loading.value = false;
});
getAllBillAmount();
}
function getAllBillAmount() {
getAllAccount(queryParams.value).then((res) => {
console.log(res);
totalAll.value = {
totalDiscountAmount: res.data.discountAmount, // 总优惠金额
TotalPaymentAmount: res.data.receivedAmount, // 总实收金额
totalAccount: res.data.receivableAmount, // 总金额
TotalUnPaymentAmount: res.data.unpaidAmount // 未收金额
};
});
}
/** 搜索按钮操作 */
const handleQuery = () => {
queryParams.value.pageNum = 1;
@@ -687,12 +702,6 @@ function initInComeFrom() {
discount: '0', // 优惠金额
residentName: '' // 缴费人
};
totalAll.value = {
totalDiscountAmount: 0, // 总优惠金额
TotalPaymentAmount: 0, // 总实收金额
totalAccount: 0, // 总金额
TotalUnPaymentAmount: 0 // 未收金额
};
payList.value = [
{
payType: '',
@@ -1076,18 +1085,13 @@ onMounted(() => {
// 总 表单
const totalAll = ref({
totalDiscountAmount: 0, // 总优惠金额
TotalPaymentAmount: 0, // 总实收金额
totalAccount: 0, // 总金额
TotalUnPaymentAmount: 0 // 未收金额
totalDiscountAmount: '0', // 总优惠金额
TotalPaymentAmount: '0', // 总实收金额
totalAccount: '0', // 总金额
TotalUnPaymentAmount: '0' // 未收金额
});
// 多选时 统计总金额,优惠总金额,实付总金额
function handleSelectBill(val: billlistType[]) {
totalAll.value.totalAccount = sum(val.map((item) => item.amount ?? 0));
totalAll.value.TotalPaymentAmount = sum(val.map((item) => item.actualAccount ?? 0));
totalAll.value.totalDiscountAmount = sum(val.map((item) => item.singleDiscountAmount ?? 0));
totalAll.value.TotalUnPaymentAmount = sum(val.map((item) => item.needPayAmount ?? 0));
}
function handleSelectBill() {}
function handleChangePayTypeId(val: string, index: number) {
// 【可选兜底校验】防止异常数据出现重复
@@ -1245,6 +1249,7 @@ function checkMoney(value: string) {
}
.footerBox {
min-height: 72px;
display: flex;
align-items: center;
justify-content: space-between;

View File

@@ -236,7 +236,7 @@ const rules = ref({
if (val === '' || val === null || val === undefined) {
return callback(new Error('请输入名称'));
}
return validator(val, 'ChineseName') ? callback() : callback(new Error('请输入中文字符'));
return validator(val, 'Character') ? callback() : callback(new Error('请输入正确的名称'));
}
}
],
@@ -358,13 +358,12 @@ getHouseUseType();
function handleChange(val: CascaderValue) {
userHousePath.value = val;
form.value.houseId = val[2];
form.value.rentalName = '';
if (val[2]) {
getHouseOwnUser(val[2]).then((res) => {
if (res.msg.trim()) {
if (res.msg && res.msg.trim()) {
form.value.rentalName = res.msg.trim();
} else {
form.value.rentalName = '';
form.value.rentalName = undefined;
}
});
}
@@ -382,7 +381,7 @@ const handleAvatarSuccess: UploadProps['onSuccess'] = (response) => {
};
const blockedExits = ['.exe', '.bat', '.cmd', '.msi'];
const allowExits = ['.bmp", ".gif", ".jpg", ".jpeg", ".png'];
const allowExits = ['.bmp', '.gif', '.jpg', '.jpeg', '.png'];
const handleChangeFile = (uploadFile: UploadFile, uploadFiles: UploadFiles) => {
const ext = uploadFile.name.toLowerCase().slice(uploadFile.name.lastIndexOf('.'));
if (blockedExits.includes(ext)) {

View File

@@ -99,10 +99,14 @@
<el-input disabled maxlength="20" show-word-limit v-model.trim="form.houseArea" placeholder="请输入面积" />
</el-form-item>
<el-form-item label="收费模式" prop="chargeMode">
<el-input v-model.trim="form.chargeMode" show-word-limit placeholder="请输入收费模式" maxlength="200" />
<el-select v-model.trim="form.chargeMode" placeholder="请选择收费模式">
<el-option v-for="(item, index) in com_house_rental_pricing_model" :key="index" :label="item.label" :value="item.value"></el-option>
</el-select>
</el-form-item>
<el-form-item label="收费标准" prop="chargeStandard">
<el-input v-model.trim="form.chargeStandard" show-word-limit placeholder="请输入收费标准" maxlength="200" />
<el-select v-model.trim="form.chargeStandard" placeholder="请选择收费标准">
<el-option v-for="(item, index) in com_house_rental_pricing" :key="index" :label="item.label" :value="item.value"></el-option>
</el-select>
</el-form-item>
<el-form-item label="合同编号" prop="contractNo">
<el-input maxlength="20" show-word-limit v-model.trim="form.contractNo" placeholder="请输入合同编号" />
@@ -130,6 +134,20 @@
placeholder="请选择租赁终止日"
/>
</el-form-item>
<el-form-item label="租金" prop="rentAmount">
<el-input maxlength="8" v-model.trim.number="form.rentAmount" placeholder="请输入租金">
<template #append>
<span>/</span>
</template>
</el-input>
</el-form-item>
<el-form-item label="押金" prop="depositAmount">
<el-input maxlength="8" v-model.trim.number="form.depositAmount" placeholder="请输入押金">
<template #append>
<span></span>
</template>
</el-input>
</el-form-item>
<el-form-item label="合同附件">
<el-upload
accept=".png,.jpg,.jpeg, .pdf"
@@ -145,6 +163,7 @@
:on-preview="handlePreview"
:auto-upload="false"
drag
style="width: 100%"
:action="uploadApi"
>
<el-icon class="el-icon--upload"><upload-filled /></el-icon>
@@ -176,7 +195,9 @@ import { UploadFilled } from '@element-plus/icons-vue';
import { ElMessage, UploadUserFile } from 'element-plus';
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
const { com_rental_status, com_rental_method } = toRefs<any>(proxy?.useDict('com_rental_status', 'com_rental_method'));
const { com_rental_status, com_rental_method, com_house_rental_pricing_model, com_house_rental_pricing } = toRefs<any>(
proxy?.useDict('com_rental_status', 'com_rental_method', 'com_house_rental_pricing_model', 'com_house_rental_pricing')
);
const uploadApi = '/houseRental/uploadImages';
const router = useRouter();
@@ -207,6 +228,8 @@ type HouseRentalFormType = HouseRentalSigningVO & {
const initFormData: HouseRentalFormType = {
contractName: '',
rentAmount: undefined,
depositAmount: undefined,
'createTime': undefined,
'id': undefined,
'rentalId': undefined,
@@ -275,7 +298,9 @@ const data = reactive<PageData<HouseRentalFormType, HouseRentalQuery>>({
leaseEndDate: [{ required: true, message: '请选择租赁终止日', trigger: 'change' }],
houseId: [{ required: true, message: '请选择房屋', trigger: 'change' }],
villageId: [{ required: true, message: '请选择小区', trigger: 'change' }],
houseArea: [{ required: true, message: '请输入房屋面积', trigger: 'blur' }]
houseArea: [{ required: true, message: '请输入房屋面积', trigger: 'blur' }],
rentAmount: [{ required: true, message: '请输入租金', trigger: 'blur' }],
depositAmount: [{ required: true, message: '请输入押金', trigger: 'blur' }]
}
});
@@ -388,20 +413,26 @@ function sign(row: HouseRentalVO) {
form.value.villageName = info.villageName;
form.value.houseName = row.name;
form.value.houseArea = row.houseArea;
form.value.tenantPhone = row.phone;
form.value.tenantPhone = '';
form.value.houseId = row.houseId;
form.value.villageId = info.villageId;
form.value.rentalId = row.id;
if (row.signingList && row.signingList.length > 0) {
const names = row.signingList[0].contractName ? row.signingList[0].contractName.split(',') : [];
showImgList.value = row.signingList[0].contractUrl.split(',').map((item, index) => {
return {
uid: index,
name: names[index] || item.split('.com/')[1].split('/')[3],
url: item,
isLink: true
};
});
const list = row.signingList[0].contractUrl ? row.signingList[0].contractUrl.split(',') : [];
console.log(list);
if (list.length > 0) {
showImgList.value = list.map((item, index) => {
return {
uid: index,
name: names[index] || item ? item.split('.com/')[1].split('/')[3] : '',
url: item,
isLink: true
};
});
} else {
showImgList.value = [];
}
} else {
showImgList.value = [];
}
@@ -459,6 +490,8 @@ function submitForm() {
const arr = await uploadAllCarousel();
// 拼接最终图片字符串
form.value.contractUrl = arr.join(',');
form.value.rentAmount = String(form.value.rentAmount) || 0;
form.value.depositAmount = String(form.value.depositAmount) || 0;
HouseRedientSign(form.value).then(() => {
proxy?.$modal.msgSuccess('操作成功');
getList();

View File

@@ -42,18 +42,25 @@
</div>
</div>
<div class="carInfo_item">
<div class="label">添加时间</div>
<div class="main">{{ parkingReviewInfo.parking.createTime }}</div>
</div>
<div class="carInfo_item">
<div class="label">业主持有人</div>
<div class="label">持有人</div>
<div class="main">
<span>
{{ parkingReviewInfo.parking.residentName }}
</span>
<el-button @click="getUserInfo" type="primary" link style="font-size: smaller; margin-left: 15px">详情</el-button>
<el-button
v-if="parkingReviewInfo.parking.residentId"
@click="getUserInfo"
type="primary"
link
style="font-size: smaller; margin-left: 15px"
>详情</el-button
>
</div>
</div>
<div class="carInfo_item">
<div class="label">添加时间</div>
<div class="main">{{ parkingReviewInfo.parking.createTime }}</div>
</div>
</div>
<div class="CarInfoBox" style="margin-top: 20px">
<div class="carInfo_item" v-if="parkingReviewInfo.parking.contactName">
@@ -243,17 +250,17 @@ type parkingReviewType = {
villageId: string;
villageName: string;
parkingCode: string;
parkingArea: any;
parkingArea: string;
parkingStatus: string;
type: string;
residentId: any;
residentName: any;
residentId: string;
residentName: string;
parkingFloor: string;
createName: string;
checkStatus: string;
remark: string;
createTime: string;
delFlag: any;
delFlag: string;
};
car: {
'id': string;

View File

@@ -170,7 +170,7 @@ const rules = ref({
if (val === '' || val === null || val === undefined) {
return callback(new Error('请输入名称'));
}
return validator(val, 'ChineseName') ? callback() : callback(new Error('请输入中文名称1-10位字符'));
return validator(val, 'Character') ? callback() : callback(new Error('请输入正确的名称'));
}
}
],
@@ -291,8 +291,6 @@ const handleBeforeUpload = (uploadFile: UploadRawFile) => {
}
return true;
};
// !==╬╬&╬╬╬ ╬╬ 2╬╬&提交 =============================================================================
// 提交
const submitForm = () => {
formRef.value?.validate(async (valid: boolean) => {

View File

@@ -372,7 +372,7 @@ const dayX = ref([]);
const inData = ref([]);
const outData = ref([]);
/** 近十天人员流入流出 - 平滑折线图*/
/** 近十天人员流入流出 - 平滑折线图 */
const flowLineOption = ref<EChartsOption>({
title: {
text: '近七日人员流动趋势',

View File

@@ -177,7 +177,10 @@ function getStoreRoomInfo(id: string) {
getStoreroom(id).then((res) => {
form.value = {
...form.value,
...res.data
...res.data,
houseArea: res.data.houseArea === 0 ? null : res.data.houseArea,
shareArea: res.data.shareArea === 0 ? null : res.data.shareArea,
internalArea: res.data.internalArea === 0 ? null : res.data.internalArea
};
if (form.value.buildingId) {
handleChangeBuild(form.value.buildingId, () => {

View File

@@ -31,7 +31,7 @@
</el-select>
</el-form-item>
<el-form-item label="管理小区" prop="villageIds">
<el-select v-model="checkvillage" multiple @change="handleChangeVillage">
<el-select v-model="checkVillage" multiple @change="handleChangeVillage">
<el-option v-for="(item, index) in villageList" :key="index" :value="item.villageId" :label="item.villageName"></el-option>
</el-select>
</el-form-item>
@@ -125,7 +125,7 @@ const rules = ref({
]
});
// 选择小区
const checkvillage = ref([]);
const checkVillage = ref([]);
// 角色列表
const roleOptions = ref([]);
@@ -148,7 +148,7 @@ async function init() {
};
roleOptions.value = [];
roleOptions.value = Array.from(new Map([...res.data.roles, ...res.data.user.roles].map((role) => [role.roleId, role])).values());
checkvillage.value = res.data.user.villageIds.split(',').filter((item) => item);
checkVillage.value = res.data.user.villageIds.split(',').filter((item) => item);
});
} else {
const { data } = await api.getUser();
@@ -159,13 +159,13 @@ async function init() {
// 小区列表
const villageList = ref([]);
/** 查询小区列表 */
const getViliageList = async () => {
const getVillageList = async () => {
const res = await getCommunitylistAPI();
villageList.value = res.rows;
console.log(villageList.value);
};
onMounted(() => {
getViliageList();
getVillageList();
init();
});

View File

@@ -208,14 +208,13 @@
import api from '@/api/system/user';
import { UserForm, UserQuery, UserVO } from '@/api/system/user/types';
import { RoleVO } from '@/api/system/role/types';
import { PostVO } from '@/api/system/post/types';
// import { PostVO } from '@/api/system/post/types';
import { globalHeaders } from '@/utils/request';
import { to } from 'await-to-js';
import { checkPermi } from '@/utils/permission';
import { useUserStore } from '@/store/modules/user';
import { getCommunitylistAPI } from '@/api/system/community';
import { communitylist_rows_type } from '@/api/system/community/type';
import { UploadRawFile } from 'element-plus';
const router = useRouter();
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
@@ -231,7 +230,7 @@ const total = ref(0);
const dateRange = ref<[DateModelType, DateModelType]>(['', '']);
const vilageList = ref<communitylist_rows_type[]>([]);
const initPassword = ref<string>('');
const postOptions = ref<PostVO[]>([]);
// const postOptions = ref<PostVO[]>([]);
const roleOptions = ref<RoleVO[]>([]);
/*** 员工导入参数 */
@@ -346,6 +345,8 @@ const { queryParams, form, rules } = toRefs<PageData<UserForm, UserQuery>>(data)
/** 查询员工列表 */
const getList = async () => {
loading.value = true;
const obj = JSON.stringify(queryParams.value);
sessionStorage.setItem('queryParams', obj);
const res = await api.listUser(proxy?.addDateRange(queryParams.value, dateRange.value));
loading.value = false;
userList.value = res.rows;
@@ -432,21 +433,21 @@ const handleSelectionChange = (selection: UserVO[]) => {
multiple.value = !selection.length;
};
/** 导入按钮操作 */
const handleImport = () => {
upload.title = '员工导入';
upload.open = true;
};
/** 导出按钮操作 */
const handleExport = () => {
proxy?.download(
'system/user/export',
{
...queryParams.value
},
`user_${new Date().getTime()}.xlsx`
);
};
// /** 导入按钮操作 */
// const handleImport = () => {
// upload.title = '员工导入';
// upload.open = true;
// };
// /** 导出按钮操作 */
// const handleExport = () => {
// proxy?.download(
// 'system/user/export',
// {
// ...queryParams.value
// },
// `user_${new Date().getTime()}.xlsx`
// );
// };
/** 下载模板操作 */
const importTemplate = () => {
proxy?.download('system/user/importTemplate', {}, `user_template_${new Date().getTime()}.xlsx`);
@@ -552,8 +553,19 @@ const resetForm = () => {
form.value.status = '1';
};
onMounted(() => {
queryParams.value = {
pageNum: 1,
pageSize: 10,
userName: '',
villageIds: '',
phonenumber: '',
status: '',
deptId: '',
roleId: '',
...JSON.parse(sessionStorage.getItem('queryParams') || '{}')
};
getViliageList(); // 初始化部门数据
getList(); // 初始化列表数据
getList(); // 初始化列表数据╬«>
proxy?.getConfigKey('sys.user.initPassword').then((response) => {
initPassword.value = response.data;
});