This commit is contained in:
Zy
2026-04-08 14:30:29 +08:00
parent dc3080db32
commit cd292d5bf4
21 changed files with 188 additions and 62 deletions

View File

@@ -15,7 +15,10 @@ VITE_APP_MONITOR_ADMIN = '/admin/applications'
VITE_APP_SNAILJOB_ADMIN = '/snail-job' VITE_APP_SNAILJOB_ADMIN = '/snail-job'
# 生产环境 # 生产环境
VITE_APP_BASE_API = 'http://wuyeadmin.bugtc.com/' VITE_APP_BASE_API = 'http://wuyeapi.bugtc.com'
# VITE_APP_BASE_API = 'http://192.168.0.222:8080'
# 是否在打包时开启压缩,支持 gzip 和 brotli # 是否在打包时开启压缩,支持 gzip 和 brotli
VITE_BUILD_COMPRESS = gzip VITE_BUILD_COMPRESS = gzip

BIN
dist.7z Normal file

Binary file not shown.

View File

@@ -8,9 +8,11 @@
"type": "module", "type": "module",
"scripts": { "scripts": {
"dev": "vite serve --mode development", "dev": "vite serve --mode development",
"build:prod": "vite build --mode production",
"build:dev": "vite build --mode development", "build:dev": "vite build --mode development",
"build:prod": "vite build --mode production",
"preview": "vite preview", "preview": "vite preview",
"preview:dev": "vite preview --mode development",
"preview:prod": "vite preview --mode production",
"lint:eslint": "eslint", "lint:eslint": "eslint",
"lint:eslint:fix": "eslint --fix", "lint:eslint:fix": "eslint --fix",
"prettier": "prettier --write ." "prettier": "prettier --write ."

View File

@@ -16,6 +16,7 @@ export function login(data: LoginData): AxiosPromise<LoginResult> {
clientId: data.clientId || clientId, clientId: data.clientId || clientId,
grantType: data.grantType || 'password' grantType: data.grantType || 'password'
}; };
console.log(params);
return request({ return request({
url: '/auth/login', url: '/auth/login',
headers: { headers: {

View File

@@ -1,9 +1,9 @@
import request from '@/utils/request'; import request from '@/utils/request';
import { AxiosPromise } from 'axios'; import { AxiosPromise } from 'axios';
import { BuildingUnit, BuildingVo } from './type'; import { addBuildingType, BuildingUnit, BuildingVo } from './type';
// 楼栋--------------------------------------------------------------------------------------- // 楼栋---------------------------------------------------------------------------------------
// 根据 小区id 和 类型 查询楼栋信息 // 根据 小区id 和 类型 查询楼栋信息
export function getBuildinglistAPI(villageId: number, buildingUse: number): AxiosPromise<BuildingVo[]> { export function getBuildinglistAPI(villageId: number, buildingUse: number): AxiosPromise<BuildingVo[]> {
return request({ return request({
url: '/building/byVillage', url: '/building/byVillage',
@@ -15,10 +15,34 @@ export function getBuildinglistAPI(villageId: number, buildingUse: number): Axio
}); });
} }
/** 添加楼栋 */
export function addBuildingApi(data: addBuildingType) {
return request({
url: '/building',
method: 'POST',
data
});
}
// 房屋---------------------------------------------------------------------------------------------- // 房屋----------------------------------------------------------------------------------------------
// 根据 楼栋id 查询房屋信息
export function getHouselistAPI(buildingId: number): AxiosPromise<BuildingUnit[]> { export function getHouselistAPI(buildingId: number): AxiosPromise<BuildingUnit[]> {
return request({ return request({
url: `/house/groupByUnitTree/${buildingId}`, url: `/house/groupByUnitTree/${buildingId}`,
method: 'get' method: 'get'
}); });
} }
// 添加房屋
export function addHouseAPI() {
return request({
url: `/house`,
method: 'POST'
});
}
// 删除房屋
export function deleteHouseApi() {
return request({
url: `/house/{houseIds}`,
method: 'delete'
});
}

View File

@@ -63,3 +63,13 @@ export interface HouseType {
houseId: string; houseId: string;
houseNo: string; houseNo: string;
} }
export interface addBuildingType {
buildingName: string;
villageId: number;
buildStructure?: string;
buildTall?: string;
buildToward?: string;
floorCount?: number;
unitCount?: number;
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 MiB

View File

Before

Width:  |  Height:  |  Size: 15 MiB

After

Width:  |  Height:  |  Size: 15 MiB

View File

@@ -26,8 +26,9 @@ const x = ref(0);
const y = ref(0); const y = ref(0);
const menuRef = ref(); const menuRef = ref();
const openHouseId = ref(null);
// 打开菜单 // 打开菜单
const open = async (e: MouseEvent, value: any) => { const open = async (e: MouseEvent, value: string) => {
e.preventDefault(); e.preventDefault();
x.value = e.clientX; x.value = e.clientX;
y.value = e.clientY; y.value = e.clientY;
@@ -62,6 +63,7 @@ const open = async (e: MouseEvent, value: any) => {
show.value = true; show.value = true;
document.addEventListener('click', close); document.addEventListener('click', close);
document.addEventListener('contextmenu', close); document.addEventListener('contextmenu', close);
openHouseId.value = value;
}, 10); }, 10);
}; };
@@ -74,7 +76,10 @@ const close = () => {
// 点击选项 // 点击选项
const handleClick = (item) => { const handleClick = (item) => {
emit('select', item.value); emit('select', {
type: item.value,
value: openHouseId.value
});
close(); close();
}; };

View File

@@ -1,15 +1,21 @@
<template> <template>
<div class="PageHeaderBox"> <div class="PageHeaderBox">
<!-- 面包屑 --> <div class="leftbox">
<breadcrumb class="breadcrumb-container" /> <!-- 面包屑 -->
<!-- 页面标题 --> <breadcrumb class="breadcrumb-container" />
<div class="pageTitleBox flex items-center"> <!-- 页面标题 -->
<div class="line"></div> <div class="pageTitleBox flex items-center">
<div class="pagetitle">{{ props.title }}</div> <div class="line"></div>
<div class="pagetitle">{{ props.title }}</div>
</div>
<!-- solt -->
<slot name="content" v-if="showSlot"></slot>
<div class="h-20px" v-show="!showSlot"></div>
</div>
<div class="rightbox">
<!-- 操作按钮 -->
<slot name="operate" v-if="showSlot"></slot>
</div> </div>
<!-- solt -->
<slot name="content" v-if="showSlot"></slot>
<div class="h-20px" v-show="!showSlot"></div>
</div> </div>
</template> </template>
@@ -29,6 +35,7 @@ const props = defineProps({
defineSlots<{ defineSlots<{
content?: () => void; content?: () => void;
operate?: () => void;
}>(); }>();
</script> </script>
@@ -39,6 +46,12 @@ defineSlots<{
background-color: #fff; background-color: #fff;
border-radius: 2px; border-radius: 2px;
background-color: rgba(255, 255, 255, 1); background-color: rgba(255, 255, 255, 1);
display: flex;
align-items: center;
justify-content: space-between;
.leftbox {
flex: 1;
}
.pageTitleBox { .pageTitleBox {
.line { .line {
width: 5px; width: 5px;

View File

@@ -56,9 +56,9 @@ export enum HttpStatus {
*/ */
UNSUPPORTED_TYPE = 415, UNSUPPORTED_TYPE = 415,
/** /**
* 图片上传-全部失败 * 系统内部错误
*/ */
UPLOAD_IMG_ALL_ERROR = 500, SERVER_ERROR = 500,
/** /**
* 接口未实现 * 接口未实现
*/ */
@@ -84,7 +84,7 @@ export enum HttpStatus {
*/ */
DATABASE_ERROR = 522, DATABASE_ERROR = 522,
/** /**
* 图片上传-部分失败 * 系统警告消息
*/ */
UPLOAD_IMG_ERROR = 601 WARN = 601
} }

View File

@@ -91,7 +91,8 @@ const getLogoTextColor = computed(() => {
& .sidebar-title { & .sidebar-title {
display: inline-block; display: inline-block;
margin: 0; margin: 0;
color: v-bind(getLogoTextColor); // color: v-bind(getLogoTextColor);
color: white;
font-weight: 600; font-weight: 600;
line-height: 50px; line-height: 50px;
font-size: 14px; font-size: 14px;

View File

@@ -73,6 +73,12 @@ export const useHouseStore = defineStore('house', () => {
currentFloorInfoList.value = (Array.from(floorslist.value) as string[]).sort(sortNumberStr); currentFloorInfoList.value = (Array.from(floorslist.value) as string[]).sort(sortNumberStr);
}; };
// 选中房屋
const checkoutHouses = ref<string[]>([]);
const checkoutHousesFun = (data: string[]) => {
checkoutHouses.value = data;
};
// 切换住宅类型 // 切换住宅类型
const switchHouseType = (housetype: 0 | 1 | 2 | 3) => { const switchHouseType = (housetype: 0 | 1 | 2 | 3) => {
getBuildinglistAPI(currentVilageInfo.value.villageId, housetype) getBuildinglistAPI(currentVilageInfo.value.villageId, housetype)
@@ -85,14 +91,26 @@ export const useHouseStore = defineStore('house', () => {
getHouselistAPI(buildingId).then(() => ElMessage.success('切换成功')); getHouselistAPI(buildingId).then(() => ElMessage.success('切换成功'));
}; };
const deleteHouseFun = (houseId: string | string[]) => {
console.log('删除房屋');
if (typeof houseId === 'string') {
console.log('单条删除');
} else if (Array.isArray(houseId)) {
console.log('批量删除');
}
};
return { return {
currentVilageInfo, currentVilageInfo,
currentBuildingInfoList, currentBuildingInfoList,
currentBuildingInfo, currentBuildingInfo,
currentHouseInfoList, currentHouseInfoList,
currentFloorInfoList, currentFloorInfoList,
checkoutHouses,
checkoutHousesFun,
initHouse, initHouse,
switchHouseType, switchHouseType,
switchBuilding switchBuilding,
deleteHouseFun
}; };
}); });

View File

@@ -151,14 +151,14 @@ service.interceptors.response.use(
}); });
} }
return Promise.reject('无效的会话,或者会话已过期,请重新登录。'); return Promise.reject('无效的会话,或者会话已过期,请重新登录。');
// 图片上传全部失败 500 // 500
} else if (code === HttpStatus.UPLOAD_IMG_ALL_ERROR) { } else if (code === HttpStatus.SERVER_ERROR) {
ElMessage({ message: '图片全部上传失败', type: 'error' }); ElMessage({ message: msg, type: 'error' });
return Promise.reject(new Error(msg));
// 601
} else if (code === HttpStatus.WARN) {
ElMessage({ message: msg, type: 'warning' });
return Promise.reject(new Error(msg)); return Promise.reject(new Error(msg));
// 图片上传部分失败 601
} else if (code === HttpStatus.UPLOAD_IMG_ERROR) {
ElMessage({ message: '部分图片上传失败', type: 'warning' });
return Promise.reject(res.data);
} else if (code !== HttpStatus.SUCCESS) { } else if (code !== HttpStatus.SUCCESS) {
ElNotification.error({ title: msg }); ElNotification.error({ title: msg });
return Promise.reject('error'); return Promise.reject('error');

View File

@@ -9,13 +9,13 @@
</div> </div>
</div> </div>
<el-form-item prop="username"> <el-form-item prop="username">
<el-input v-model="loginForm.username" type="text" size="large" auto-complete="off" :placeholder="proxy.$t('login.username')"> <el-input v-model.trim="loginForm.username" type="text" size="large" auto-complete="off" :placeholder="proxy.$t('login.username')">
<template #prefix><svg-icon icon-class="user" class="el-input__icon input-icon" /></template> <template #prefix><svg-icon icon-class="user" class="el-input__icon input-icon" /></template>
</el-input> </el-input>
</el-form-item> </el-form-item>
<el-form-item prop="password"> <el-form-item prop="password">
<el-input <el-input
v-model="loginForm.password" v-model.trim="loginForm.password"
type="password" type="password"
size="large" size="large"
auto-complete="off" auto-complete="off"
@@ -98,6 +98,7 @@ const handleLogin = () => {
loginRef.value?.validate(async (valid: boolean, fields: any) => { loginRef.value?.validate(async (valid: boolean, fields: any) => {
if (valid) { if (valid) {
loading.value = true; loading.value = true;
console.log(loginForm.value);
// 勾选了需要记住密码设置在 localStorage 中设置记住用户名和密码 // 勾选了需要记住密码设置在 localStorage 中设置记住用户名和密码
if (loginForm.value.rememberMe) { if (loginForm.value.rememberMe) {
localStorage.setItem('tenantId', String(loginForm.value.tenantId)); localStorage.setItem('tenantId', String(loginForm.value.tenantId));
@@ -114,15 +115,12 @@ const handleLogin = () => {
// 调用action的登录方法 // 调用action的登录方法
const [err] = await to(userStore.login(loginForm.value)); const [err] = await to(userStore.login(loginForm.value));
if (!err) { if (!err) {
console.log('登录成功');
const redirectUrl = redirect.value || '/'; const redirectUrl = redirect.value || '/';
await router.push(redirectUrl); await router.push(redirectUrl);
loading.value = false; loading.value = false;
} else { } else {
loading.value = false; loading.value = false;
// 重新获取验证码
if (captchaEnabled.value) {
await getCode();
}
} }
} else { } else {
} }
@@ -200,7 +198,7 @@ onMounted(() => {
justify-content: center; justify-content: center;
align-items: center; align-items: center;
height: 100%; height: 100%;
background-image: url('../assets/images/login-background.jpg'); background-image: url('../assets/images/login-background.png');
background-size: cover; background-size: cover;
background-position: center; background-position: center;
} }

View File

@@ -6,22 +6,22 @@
<div class="addBuildingFormBody"> <div class="addBuildingFormBody">
<el-form class="formBody" ref="formRef" :model="form" :rules="rules" label-width="100px"> <el-form class="formBody" ref="formRef" :model="form" :rules="rules" label-width="100px">
<el-form-item label="楼栋名称" prop="buildingName"> <el-form-item label="楼栋名称" prop="buildingName">
<el-input v-model="form.buildingName" placeholder="请输入楼栋名称" /> <el-input v-model.trim="form.buildingName" placeholder="请输入楼栋名称" />
</el-form-item> </el-form-item>
<el-form-item label="楼栋朝向" prop="buildingCode"> <el-form-item label="楼栋朝向" prop="buildToward">
<el-input v-model="form.buildingCode" placeholder="请输入楼栋朝向" /> <el-input v-model.trim="form.buildToward" placeholder="请输入楼栋朝向" />
</el-form-item> </el-form-item>
<el-form-item label="楼高(m)" prop="buildingType"> <el-form-item label="楼高(m)" prop="buildTail">
<el-input v-model="form.buildingType" placeholder="请输入楼高(m)" /> <el-input v-model.trim="form.buildTail" placeholder="请输入楼高(m)" />
</el-form-item> </el-form-item>
<el-form-item label="楼栋结构" prop="buildingArea"> <el-form-item label="楼栋结构" prop="buildStructure">
<el-input v-model="form.buildingArea" placeholder="请输入楼栋结构" /> <el-input v-model.trim="form.buildStructure" placeholder="请输入楼栋结构" />
</el-form-item> </el-form-item>
<el-form-item label="单元数" prop="buildingAddress"> <el-form-item label="单元数" prop="unitCount">
<el-input-number :min="1" v-model="form.buildingAddress" placeholder="单元数" /> <el-input-number :min="1" v-model.trim="form.unitCount" placeholder="单元数" />
</el-form-item> </el-form-item>
<el-form-item label="楼层" prop="buildingDescription"> <el-form-item label="楼层" prop="floorCount">
<el-input-number :min="1" v-model="form.buildingDescription" placeholder="楼层数" /> <el-input-number :min="1" v-model.trim="form.floorCount" placeholder="楼层数" />
</el-form-item> </el-form-item>
<el-form-item style="margin-top: 30px"> <el-form-item style="margin-top: 30px">
<el-button type="primary" @click="submitForm">确定</el-button> <el-button type="primary" @click="submitForm">确定</el-button>
@@ -36,30 +36,52 @@
<script setup lang="ts"> <script setup lang="ts">
import { ref } from 'vue'; import { ref } from 'vue';
import PageHeader from '@/components/Pageheader/index.vue'; import PageHeader from '@/components/Pageheader/index.vue';
import { getCommunitylistAPI } from '@/api/system/community';
import { addBuildingApi } from '@/api/system/house';
const formRef = ref(); const formRef = ref();
const form = ref({ const form = ref({
buildingName: '', buildingName: '',
buildingCode: '', buildToward: '',
buildingType: '', buildTail: '',
buildingArea: '', buildStructure: '',
buildingAddress: null, unitCount: null,
buildingDescription: null floorCount: null
}); });
const rules = ref({ const rules = ref({
buildingName: [{ required: true, message: '请输入楼栋名称', trigger: 'blur' }], buildingName: [{ required: true, message: '请输入楼栋名称', trigger: 'blur' }],
buildingAddress: [{ required: true, message: '请输入单元数', trigger: 'blur' }], unitCount: [{ required: true, message: '请输入单元数', trigger: 'blur' }],
buildingDescription: [{ required: true, message: '请输入楼层', trigger: 'blur' }] floorCount: [{ required: true, message: '请输入楼层', trigger: 'blur' }]
}); });
// 获取当前小区信息
const currentVilageinfo = ref();
function getVilageFun() {
getCommunitylistAPI().then((res) => {
currentVilageinfo.value = res.rows.find((item) => item.choiceStatus === 0);
});
}
// getVilageFun();
const submitForm = () => { const submitForm = () => {
formRef.value?.validate(async (valid: boolean) => { formRef.value?.validate(async (valid: boolean) => {
if (valid) { if (valid) {
console.log(form.value); console.log(form.value);
addBuildingApi({
...form.value,
villageId: currentVilageinfo.value.id
})
.then((res) => {
console.log(res);
ElMessage.success('添加成功');
})
.catch((err) => {
console.log(err);
ElMessage.error('添加失败');
});
} }
}); });
}; };
const cancelForm = () => { const cancelForm = () => {
console.log('取消'); formRef.value?.resetFields();
}; };
</script> </script>

View File

@@ -15,7 +15,7 @@
:key="index" :key="index"
@click="switchBuilding(item.id)" @click="switchBuilding(item.id)"
> >
<div class="buildingname">{{ item.villageName ?? '未知' }}</div> <div class="buildingname">{{ item.buildingName ?? '测试数据' }}</div>
<div class="buildactions flex align-center justify-around"> <div class="buildactions flex align-center justify-around">
<el-icon class="pointer hover-color-blue"><Setting /></el-icon> <el-icon class="pointer hover-color-blue"><Setting /></el-icon>
<el-icon class="pointer hover-color-red"><Delete /></el-icon> <el-icon class="pointer hover-color-red"><Delete /></el-icon>
@@ -26,13 +26,12 @@
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { ref } from 'vue';
import { useHouseStore } from '@/store/modules/house'; import { useHouseStore } from '@/store/modules/house';
const houseStore = useHouseStore(); const houseStore = useHouseStore();
const { switchBuilding } = houseStore; // 方法 const { switchBuilding } = houseStore; // 方法
const { currentBuildingInfoList, currentBuildingInfo } = storeToRefs(houseStore); // 数据 const { currentBuildingInfoList, currentBuildingInfo } = storeToRefs(houseStore); // 数据
const router = useRouter(); const router = useRouter();
console.log(currentBuildingInfoList);
const handleAddBuilding = () => { const handleAddBuilding = () => {
router.push({ router.push({
path: '/house/addbuilding' path: '/house/addbuilding'

View File

@@ -25,8 +25,8 @@ const checked = ref<string[]>([]);
// 菜单ref // 菜单ref
const contextMenu = ref(); const contextMenu = ref();
// 点击事件 // 点击事件
const handleSelect = (val: string) => { const handleSelect = (data: { type: string; value: string }) => {
emit('contextmenufun', val); emit('contextmenufun', data);
}; };
function handleClick(house: HouseType) { function handleClick(house: HouseType) {
checked.value = checked.value.includes(house.houseId) checked.value = checked.value.includes(house.houseId)
@@ -37,7 +37,7 @@ function handleClick(house: HouseType) {
const emit = defineEmits<{ const emit = defineEmits<{
change: [value: string[]]; change: [value: string[]];
contextmenufun: [value: string]; contextmenufun: [value: { type: string; value: string }];
}>(); }>();
</script> </script>

View File

@@ -15,7 +15,13 @@
:key="index" :key="index"
> >
<template #default="{ row }"> <template #default="{ row }">
<houseItem :menu-list="menutlist" :unit="units.floors_Json" :f-idx="row"></houseItem> <houseItem
@contextmenufun="contextMenuFun"
@change="handleChange"
:menu-list="menutlist"
:unit="units.floors_Json"
:f-idx="row"
></houseItem>
</template> </template>
</el-table-column> </el-table-column>
</el-table> </el-table>
@@ -33,6 +39,26 @@ const menutlist = [
{ label: '详情', value: 'main' }, { label: '详情', value: 'main' },
{ label: '删除', value: 'delete' } { label: '删除', value: 'delete' }
]; ];
function contextMenuFun(val: { type: string; value: string }) {
switch (val.type) {
case 'edit':
console.log('你选择了:', val);
break;
case 'money':
console.log('你选择了:', val);
break;
case 'main':
console.log('你选择了:', val);
break;
case 'delete':
console.log('你选择了:', val);
houseStore.deleteHouseFun(val.value);
break;
}
}
function handleChange(data: string[]) {
houseStore.checkoutHousesFun(data);
}
</script> </script>
<style scoped lang="scss"> <style scoped lang="scss">

View File

@@ -31,6 +31,10 @@ export default defineConfig(({ mode, command }) => {
} }
} }
}, },
build: {
outDir: 'dist',
cleanOutDir: true
},
css: { css: {
preprocessorOptions: { preprocessorOptions: {
scss: { scss: {

View File

@@ -13,7 +13,7 @@ import path from 'path';
export default (viteEnv: any, isBuild = false): [] => { export default (viteEnv: any, isBuild = false): [] => {
const vitePlugins: any = []; const vitePlugins: any = [];
vitePlugins.push(vue()); vitePlugins.push(vue());
vitePlugins.push(vueDevTools()); // vitePlugins.push(vueDevTools());
vitePlugins.push(createUnoCss()); vitePlugins.push(createUnoCss());
vitePlugins.push(createAutoImport(path)); vitePlugins.push(createAutoImport(path));
vitePlugins.push(createComponents(path)); vitePlugins.push(createComponents(path));