Merge branch 'master' of http://47.109.37.87:3000/by2025/admin-vben5
Some checks failed
/ Explore-Gitea-Actions (push) Failing after 5m51s

This commit is contained in:
fyy
2025-08-22 13:03:57 +08:00
62 changed files with 1547 additions and 173 deletions

View File

@@ -10,28 +10,39 @@ jobs:
- name: 拉取代码仓库
uses: http://git.missmoc.top/mocheng/checkout@v4
- name: Set up Node.js ${{ matrix.node-version }}
- name: Set up Node.js
uses: http://git.missmoc.top/mocheng/setup-node@v3
with:
node-version: 20.x
- name: pnpm
- name: 安装pnpm
run: npm i pnpm -g
- name: node
run: |
pnpm config set registry https://registry.npmmirror.com
pnpm install
- name: Build
- name: 安装依赖
run: pnpm install
continue-on-error: false # 依赖安装失败则终止工作流
- name: 构建项目
run: pnpm build:antd
- name: copy file via ssh password
continue-on-error: false # 构建失败则终止工作流
- name: 检查构建结果
run: |
if [ ! -d "./apps/web-antd/dist" ]; then
echo "构建目录不存在,构建失败"
exit 1
fi
if [ -z "$(ls -A ./apps/web-antd/dist)" ]; then
echo "构建目录为空,构建失败"
exit 1
fi
- name: 通过SSH复制文件
uses: http://git.missmoc.top/mocheng/scp-action@v0.1.7
with:
host: 127.0.0.1
username: ${ { SERVER_NAME } }
password: ${{ SERVER_PWD}}
username: ${{ secrets.SERVER_NAME }} # 使用secrets存储
password: ${{ secrets.SERVER_PWD }} # 使用secrets存储
port: 11001
source: "./apps/web-antd/dist"
target: "/www/wwwroot/183.230.235.66_11010/property"

View File

@@ -0,0 +1,61 @@
import type { ActivitiesVO, ActivitiesForm, ActivitiesQuery } from './model';
import type { ID, IDS } from '#/api/common';
import type { PageResult } from '#/api/common';
import { commonExport } from '#/api/helper';
import { requestClient } from '#/api/request';
/**
* 查询热门活动列表
* @param params
* @returns 热门活动列表
*/
export function activitiesList(params?: ActivitiesQuery) {
return requestClient.get<PageResult<ActivitiesVO>>('/property/activities/list', { params });
}
/**
* 导出热门活动列表
* @param params
* @returns 热门活动列表
*/
export function activitiesExport(params?: ActivitiesQuery) {
return commonExport('/property/activities/export', params ?? {});
}
/**
* 查询热门活动详情
* @param id id
* @returns 热门活动详情
*/
export function activitiesInfo(id: ID) {
return requestClient.get<ActivitiesVO>(`/property/activities/${id}`);
}
/**
* 新增热门活动
* @param data
* @returns void
*/
export function activitiesAdd(data: ActivitiesForm) {
return requestClient.postWithMsg<void>('/property/activities', data);
}
/**
* 更新热门活动
* @param data
* @returns void
*/
export function activitiesUpdate(data: ActivitiesForm) {
return requestClient.putWithMsg<void>('/property/activities', data);
}
/**
* 删除热门活动
* @param id id
* @returns void
*/
export function activitiesRemove(id: ID | IDS) {
return requestClient.deleteWithMsg<void>(`/property/activities/${id}`);
}

View File

@@ -0,0 +1,129 @@
import type { PageQuery, BaseEntity } from '#/api/common';
export interface ActivitiesVO {
/**
* 主键
*/
id: string | number;
/**
* 标题
*/
title: string;
/**
* 头部照片
*/
headImgUrl: string;
/**
* 开始时间
*/
startTime: string;
/**
* 结束时间
*/
endTime: string;
/**
* 活动内容
*/
activeContent: string;
/**
* 状态1.未开始 2.进行中 3.已结束)
*/
status: string;
/**
* 搜索值
*/
searchValue: string;
}
export interface ActivitiesForm extends BaseEntity {
/**
* 主键
*/
id?: string | number;
/**
* 标题
*/
title?: string;
/**
* 头部照片
*/
headImgUrl?: string;
/**
* 开始时间
*/
startTime?: string;
/**
* 结束时间
*/
endTime?: string;
/**
* 活动内容
*/
activeContent?: string;
/**
* 状态1.未开始 2.进行中 3.已结束)
*/
status?: string;
/**
* 搜索值
*/
searchValue?: string;
}
export interface ActivitiesQuery extends PageQuery {
/**
* 标题
*/
title?: string;
/**
* 头部照片
*/
headImgUrl?: string;
/**
* 开始时间
*/
startTime?: string;
/**
* 结束时间
*/
endTime?: string;
/**
* 活动内容
*/
activeContent?: string;
/**
* 状态1.未开始 2.进行中 3.已结束)
*/
status?: string;
/**
* 搜索值
*/
searchValue?: string;
/**
* 日期范围参数
*/
params?: any;
}

View File

@@ -10,6 +10,7 @@ export interface FeedbacksVO {
* 反馈类型(0保修1保洁2会议)
*/
feedbackType: string;
feedbackTypeName: string;
/**
* 反馈人
@@ -21,6 +22,11 @@ export interface FeedbacksVO {
*/
feedbackPersionPhone: string;
/**
* 反馈人名称
*/
feedbackPersionName: string;
/**
* 反馈内容
*/
@@ -50,6 +56,10 @@ export interface FeedbacksVO {
* 客服电话
*/
serviceName: string;
/**
* 工单id
*/
orderId: string;
}

View File

@@ -0,0 +1,79 @@
import type { LightInfoVO, LightInfoForm, LightInfoQuery } from './model';
import type { ID, IDS } from '#/api/common';
import type { PageResult } from '#/api/common';
import { commonExport } from '#/api/helper';
import { requestClient } from '#/api/request';
/**
* 查询灯控开关信息列表
* @param params
* @returns 灯控开关信息列表
*/
export function lightInfoList(params?: LightInfoQuery) {
return requestClient.get<PageResult<LightInfoVO>>('/property/lightInfo/list', { params });
}
/**
* 导出灯控开关信息列表
* @param params
* @returns 灯控开关信息列表
*/
export function lightInfoExport(params?: LightInfoQuery) {
return commonExport('/property/lightInfo/export', params ?? {});
}
/**
* 查询灯控开关信息详情
* @param id id
* @returns 灯控开关信息详情
*/
export function lightInfoInfo(id: ID) {
return requestClient.get<LightInfoVO>(`/property/lightInfo/${id}`);
}
/**
* 新增灯控开关信息
* @param data
* @returns void
*/
export function lightInfoAdd(data: LightInfoForm) {
return requestClient.postWithMsg<void>('/property/lightInfo', data);
}
/**
* 更新灯控开关信息
* @param data
* @returns void
*/
export function lightInfoUpdate(data: LightInfoForm) {
return requestClient.putWithMsg<void>('/property/lightInfo', data);
}
/**
* 删除灯控开关信息
* @param id id
* @returns void
*/
export function lightInfoRemove(id: ID | IDS) {
return requestClient.deleteWithMsg<void>(`/property/lightInfo/${id}`);
}
/**
* 更新灯控开关状态
* @param data
* @returns void
*/
export function switchSingleLight(data: LightInfoForm) {
return requestClient.postWithMsg<void>('/property/lightInfo/switch', data);
}
/**
* 批量更新灯控开关状态
* @param data
* @returns void
*/
export function switchBatchLight(data: LightInfoForm) {
return requestClient.postWithMsg<void>('/property/lightInfo/switch', data);
}

View File

@@ -0,0 +1,134 @@
import type { PageQuery, BaseEntity } from '#/api/common';
export interface LightInfoVO {
/**
* 主键id
*/
id: string | number;
/**
* 位置描述
*/
locationRemark: string;
/**
* 开关状态01
*/
isOn: boolean;
/**
* 灯控模块编码
*/
code: number;
/**
* 园区编码
*/
communityId: string | number;
/**
* 建筑名称
*/
buildingId: string | number;
/**
* 单元编码
*/
unitId: string | number;
/**
* 所属楼层ID
*/
floorId: string | number;
/**
* 楼层
*/
floorName: string;
}
export interface LightInfoForm extends BaseEntity {
/**
* 主键id
*/
id?: string | number;
/**
* 位置描述
*/
locationRemark?: string;
/**
* 开关状态01
*/
isOn: boolean;
/**
* 灯控模块编码
*/
code?: number;
/**
* 园区编码
*/
communityId?: string | number;
/**
* 建筑名称
*/
buildingId?: string | number;
/**
* 单元编码
*/
unitId?: string | number;
/**
* 所属楼层ID
*/
floorId?: string | number;
}
export interface LightInfoQuery extends PageQuery {
/**
* 位置描述
*/
locationRemark?: string;
/**
* 开关状态01
*/
isOn?: number;
/**
* 灯控模块编码
*/
code?: number;
/**
* 园区编码
*/
communityId?: string | number;
/**
* 建筑名称
*/
buildingId?: string | number;
/**
* 单元编码
*/
unitId?: string | number;
/**
* 所属楼层ID
*/
floorId?: string | number;
/**
* 日期范围参数
*/
params?: any;
}

View File

@@ -61,5 +61,5 @@ export function meetRemove(id: ID | IDS) {
}
export function notlist(params?: MeetBo) {
return requestClient.get<PageResult<MeetVO>>('/property/meet/notlist', { params });
return requestClient.get<MeetVO[]>('/property/meet/notlist', { params });
}

View File

@@ -67,6 +67,14 @@ export interface MeetVO {
* 图片
*/
picture: string;
/**
* 开放时段开始时间
*/
openStartHours: string;
/**
* 开放时段结束时间
*/
openEndHours: string;
}
export interface MeetForm extends BaseEntity {
@@ -153,6 +161,15 @@ export interface MeetForm extends BaseEntity {
*/
picture: string;
/**
* 开放时段开始时间
*/
openStartHours: string;
/**
* 开放时段结束时间
*/
openEndHours: string;
}
export interface MeetQuery extends PageQuery {
@@ -240,7 +257,7 @@ export interface MeetQuery extends PageQuery {
picture: string;
}
export interface conferenceSettingsDetail extends BaseEntity {
export interface ConferenceSettingsDetail{
/**
* 主键
*/
@@ -329,6 +346,16 @@ export interface conferenceSettingsDetail extends BaseEntity {
* 图片
*/
picture: string;
/**
* 开放时段开始时间
*/
openStartHours: string;
/**
* 开放时段结束时间
*/
openEndHours: string;
}
export interface MeetBo{

View File

@@ -164,7 +164,7 @@ const { hasAccessByCodes } = useAccess();
<template #action="{ row }">
<Space>
<ghost-button
v-access:code="['property:depot:info']"
v-access:code="['property:depot:query']"
@click.stop="handleInfo(row)"
>
{{ $t('pages.common.info') }}

View File

@@ -39,10 +39,11 @@ export const querySchema: FormSchemaGetter = () => [
{
component: 'Select',
componentProps: {},
componentProps: {
options: getDictOptions('wy_zccgfs'),
},
fieldName: 'buyType',
label: '采购方式',
options: getDictOptions('wy_zccgfs'),
},
{
component: 'Select',

View File

@@ -179,7 +179,7 @@ function handleDownloadExcel() {
<template #action="{ row }">
<Space>
<ghost-button
v-access:code="['domain:procurementApplication:audit']"
v-access:code="['domain:procurementApplication:edit']"
:disabled="row.state === '1' || row.state === '2'"
type="primary"
@click.stop="handleAudit(row)"
@@ -187,7 +187,7 @@ function handleDownloadExcel() {
审核
</ghost-button>
<ghost-button
v-access:code="['domain:procurementApplication:detail']"
v-access:code="['domain:procurementApplication:query']"
@click.stop="handleDetail(row)"
>
详情

View File

@@ -155,14 +155,14 @@ const { hasAccessByCodes } = useAccess();
:unCheckedValue="0"
v-model:value="row.state"
:api="() => suppliersUpdate(row)"
:disabled="!hasAccessByCodes(['property:suppliers:update'])"
:disabled="!hasAccessByCodes(['property:suppliers:edit'])"
@reload="() => tableApi.query()"
/>
</template>
<template #action="{ row }">
<Space>
<ghost-button
v-access:code="['property:suppliers:info']"
v-access:code="['property:suppliers:query']"
@click.stop="handleInfo(row)"
>
{{ $t('pages.common.info') }}

View File

@@ -154,7 +154,7 @@ function handleDownloadExcel() {
<template #action="{ row }">
<Space>
<ghost-button
v-access:code="['Property:group:info']"
v-access:code="['Property:group:query']"
@click.stop="handleInfo(row)"
>
{{ $t('pages.common.info') }}
@@ -187,7 +187,7 @@ function handleDownloadExcel() {
:unCheckedValue="0"
v-model:value="row.status"
:api="() => groupUpdate(row)"
:disabled="!hasAccessByCodes(['property:depot:edit'])"
:disabled="!hasAccessByCodes(['Property:group:edit'])"
@reload="() => tableApi.query()"
/>
</template>

View File

@@ -75,7 +75,7 @@ function handleInfo(row:any) {
<template #action="{ row }">
<Space>
<ghost-button
v-access:code="['property:workOrders:info']"
v-access:code="['property:workOrders:query']"
@click.stop="handleInfo(row)"
>
{{ $t('pages.common.info') }}

View File

@@ -75,7 +75,7 @@ function handleInfo(row:any) {
<template #action="{ row }">
<Space>
<ghost-button
v-access:code="['property:workOrders:info']"
v-access:code="['property:workOrders:query']"
@click.stop="handleInfo(row)"
>
{{ $t('pages.common.info') }}

View File

@@ -30,7 +30,7 @@ export const querySchema: FormSchemaGetter = () => [
options: getDictOptions('pro_processing_weight'),
},
fieldName: 'processingWeight',
label: '处理权重',
label: '处理优先级',
},
];
@@ -82,7 +82,7 @@ export const columns: VxeGridProps['columns'] = [
width: 100,
},
{
title: '处理权重',
title: '处理优先级',
field: 'processingWeight',
slots: {
default: ({row}) => {
@@ -166,7 +166,7 @@ export const modalSchema: FormSchemaGetter = () => [
rules: 'selectRequired',
},
{
label: '处理权重',
label: '处理优先级',
fieldName: 'processingWeight',
component: 'Select',
componentProps: {

View File

@@ -196,7 +196,7 @@ onMounted(async () => {
{{ '抢单' }}
</ghost-button>
<ghost-button
v-access:code="['property:workOrders:info']"
v-access:code="['property:workOrders:query']"
@click.stop="handleInfo(row)"
>
{{ $t('pages.common.info') }}

View File

@@ -57,7 +57,7 @@ async function handleOpenChange(open: boolean) {
:is="renderDict(orderDetail.reportingType,'wy_gdsblx')"
/>
</DescriptionsItem>
<DescriptionsItem label="处理权重">
<DescriptionsItem label="处理优先级">
<component
:is="renderDict(orderDetail.processingWeight,'pro_processing_weight')"
/>

View File

@@ -140,6 +140,7 @@ function handleMultiDelete() {
<Space>
<ghost-button
@click.stop="handleInfo(row)"
v-access:code="['property:workOrdersType:query']"
>
{{ $t('pages.common.info') }}
</ghost-button>

View File

@@ -152,7 +152,7 @@ function handleDownloadExcel() {
<template #action="{ row }">
<Space>
<ghost-button
v-access:code="['property:carCharge:info']"
v-access:code="['property:carCharge:query']"
@click.stop="handleInfo(row)"
>
{{ $t('pages.common.info') }}

View File

@@ -140,7 +140,7 @@ const { hasAccessByCodes } = useAccess();
unCheckedValue="0"
v-model:value="row.state"
:api="() => costItemSettingUpdate(row)"
:disabled=" !hasAccessByCodes(['property:unit:edit'])"
:disabled=" !hasAccessByCodes(['property:costItemSetting:edit'])"
@reload="() => tableApi.query()"
/>
</template>

View File

@@ -164,7 +164,7 @@ function handleDownloadExcel() {
<template #action="{ row }">
<Space>
<ghost-button
v-access:code="['property:houseCharge:info']"
v-access:code="['property:houseCharge:query']"
@click.stop="handleInfo(row)"
>
{{ $t('pages.common.info') }}

View File

@@ -85,12 +85,14 @@ async function handleEdit(row: Required<PaymentReviewForm>) {
<Space>
<ghost-button
@click.stop="handleInfo(row)"
v-access:code="['property:payFeeAudit:query']"
>
{{ $t('pages.common.info') }}
</ghost-button>
<ghost-button
:disabled="row.state!=='0'"
@click.stop="handleEdit(row)"
v-access:code="['property:payFeeAudit:query']"
>
{{ '审核' }}
</ghost-button>

View File

@@ -158,7 +158,7 @@ function handleDownloadExcel() {
审核
</ghost-button>
<ghost-button
v-access:code="['property:returnPayFee:info']"
v-access:code="['property:returnPayFee:query']"
@click.stop="handleInfo(row)"
>
{{ $t('pages.common.info') }}

View File

@@ -0,0 +1,106 @@
<script setup lang="ts">
import { computed, ref } from 'vue';
import { useVbenModal } from '@vben/common-ui';
import { $t } from '@vben/locales';
import { cloneDeep } from '@vben/utils';
import { useVbenForm } from '#/adapter/form';
import { activitiesAdd, activitiesInfo, activitiesUpdate } from '#/api/property/customerService/activities';
import { defaultFormValueGetter, useBeforeCloseDiff } from '#/utils/popup';
import { modalSchema } from './data';
import dayjs from "dayjs";
const emit = defineEmits<{ reload: [] }>();
const isUpdate = ref(false);
const title = computed(() => {
return isUpdate.value ? $t('pages.common.edit') : $t('pages.common.add');
});
const [BasicForm, formApi] = useVbenForm({
commonConfig: {
// 默认占满两列
formItemClass: 'col-span-1',
// 默认label宽度 px
labelWidth: 80,
// 通用配置项 会影响到所有表单项
componentProps: {
class: 'w-full',
}
},
schema: modalSchema(),
showDefaultActions: false,
wrapperClass: 'grid-cols-2',
});
const { onBeforeClose, markInitialized, resetInitialized } = useBeforeCloseDiff(
{
initializedGetter: defaultFormValueGetter(formApi),
currentGetter: defaultFormValueGetter(formApi),
},
);
const [BasicModal, modalApi] = useVbenModal({
// 在这里更改宽度
class: 'w-[60%]',
fullscreenButton: false,
onBeforeClose,
onClosed: handleClosed,
onConfirm: handleConfirm,
onOpenChange: async (isOpen) => {
if (!isOpen) {
return null;
}
modalApi.modalLoading(true);
const { id } = modalApi.getData() as { id?: number | string };
isUpdate.value = !!id;
if (isUpdate.value && id) {
const record = await activitiesInfo(id);
dayjs(record.startTime, 'YYYY-MM-DD HH:mm:ss')
dayjs(record.endTime, 'YYYY-MM-DD HH:mm:ss')
await formApi.setValues(record);
}
await markInitialized();
modalApi.modalLoading(false);
},
});
async function handleConfirm() {
try {
modalApi.lock(true);
const { valid } = await formApi.validate();
if (!valid) {
return;
}
// getValues获取为一个readonly的对象 需要修改必须先深拷贝一次
const data = cloneDeep(await formApi.getValues());
data.startTime = dayjs(data.startTime).format('YYYY-MM-DD HH:mm:ss');
data.endTime = dayjs(data.endTime).format('YYYY-MM-DD HH:mm:ss');
await (isUpdate.value ? activitiesUpdate(data) : activitiesAdd(data));
resetInitialized();
emit('reload');
modalApi.close();
} catch (error) {
console.error(error);
} finally {
modalApi.lock(false);
}
}
async function handleClosed() {
await formApi.resetForm();
resetInitialized();
}
</script>
<template>
<BasicModal :title="title">
<BasicForm />
</BasicModal>
</template>

View File

@@ -0,0 +1,128 @@
import type { FormSchemaGetter } from '#/adapter/form';
import type { VxeGridProps } from '#/adapter/vxe-table';
import { getDictOptions } from '#/utils/dict';
import { renderDict } from '#/utils/render';
export const querySchema: FormSchemaGetter = () => [
{
component: 'Input',
fieldName: 'title',
label: '标题',
},
{
component: 'Select',
componentProps: {
options: getDictOptions('pro_activity_status'),
},
fieldName: 'status',
label: '状态',
},
];
export const columns: VxeGridProps['columns'] = [
{ type: 'checkbox', width: 60 },
{
title: '序号',
field: 'id',
slots: {
default: ({ rowIndex }) => {
return (rowIndex + 1).toString();
},
},
},
{
title: '标题',
field: 'title',
},
{
title: '创建人',
field: 'createName',
},
{
title: '开始时间',
field: 'startTime',
},
{
title: '结束时间',
field: 'endTime',
},
{
title: '状态',
field: 'status',
slots: {
default: ({ row }) => {
// 可选从DictEnum中获取 DictEnum.PRO_ACTIVITY_STATUS 便于维护
return renderDict(row.status, 'pro_activity_status');
},
},
},
{
field: 'action',
fixed: 'right',
slots: { default: 'action' },
title: '操作',
width: 180,
},
];
export const modalSchema: FormSchemaGetter = () => [
{
label: '主键',
fieldName: 'id',
component: 'Input',
dependencies: {
show: () => false,
triggerFields: [''],
},
},
{
label: '标题',
fieldName: 'title',
component: 'Input',
rules: 'required',
},
{
label: '头部照片',
fieldName: 'headImgUrl',
component: 'ImageUpload',
componentProps: {
maxCount: 1,
},
formItemClass: 'col-span-2',
// rules: 'required',
},
{
label: '开始时间',
fieldName: 'startTime',
component: 'DatePicker',
componentProps: {
showTime: true,
format: 'YYYY-MM-DD HH:mm:ss',
valueFormat: 'YYYY-MM-DD HH:mm:ss',
},
rules: 'required',
},
{
label: '结束时间',
fieldName: 'endTime',
component: 'DatePicker',
componentProps: {
showTime: true,
format: 'YYYY-MM-DD HH:mm:ss',
valueFormat: 'YYYY-MM-DD HH:mm:ss',
},
rules: 'required',
},
{
label: '活动内容',
fieldName: 'activeContent',
component: 'RichTextarea',
formItemClass: 'col-span-2',
componentProps: {
// disabled: false, // 是否只读
// height: 400 // 高度 默认400
},
rules: 'required',
},
];

View File

@@ -0,0 +1,182 @@
<script setup lang="ts">
import type { Recordable } from '@vben/types';
import { ref } from 'vue';
import { Page, useVbenModal, type VbenFormProps } from '@vben/common-ui';
import { getVxePopupContainer } from '@vben/utils';
import { Modal, Popconfirm, Space } from 'ant-design-vue';
import dayjs from 'dayjs';
import {
useVbenVxeGrid,
vxeCheckboxChecked,
type VxeGridProps
} from '#/adapter/vxe-table';
import {
activitiesExport,
activitiesList,
activitiesRemove,
} from '#/api/property/customerService/activities';
import type { ActivitiesForm } from '#/api/property/customerService/activities/model';
import { commonDownloadExcel } from '#/utils/file/download';
import activitiesModal from './activities-modal.vue';
import { columns, querySchema } from './data';
const formOptions: VbenFormProps = {
commonConfig: {
labelWidth: 80,
componentProps: {
allowClear: true,
},
},
schema: querySchema(),
wrapperClass: 'grid-cols-1 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4',
// 处理区间选择器RangePicker时间格式 将一个字段映射为两个字段 搜索/导出会用到
// 不需要直接删除
// fieldMappingTime: [
// [
// 'createTime',
// ['params[beginTime]', 'params[endTime]'],
// ['YYYY-MM-DD 00:00:00', 'YYYY-MM-DD 23:59:59'],
// ],
// ],
};
const gridOptions: VxeGridProps = {
checkboxConfig: {
// 高亮
highlight: true,
// 翻页时保留选中状态
reserve: true,
// 点击行选中
// trigger: 'row',
},
// 需要使用i18n注意这里要改成getter形式 否则切换语言不会刷新
// columns: columns(),
columns,
height: 'auto',
keepSource: true,
pagerConfig: {},
proxyConfig: {
ajax: {
query: async ({ page }, formValues = {}) => {
return await activitiesList({
pageNum: page.currentPage,
pageSize: page.pageSize,
...formValues,
});
},
},
},
rowConfig: {
keyField: 'id',
},
// 表格全局唯一表示 保存列配置需要用到
id: 'property-activities-index'
};
const [BasicTable, tableApi] = useVbenVxeGrid({
formOptions,
gridOptions,
});
const [ActivitiesModal, modalApi] = useVbenModal({
connectedComponent: activitiesModal,
});
function handleAdd() {
modalApi.setData({});
modalApi.open();
}
async function handleEdit(row: Required<ActivitiesForm>) {
modalApi.setData({ id: row.id });
modalApi.open();
}
async function handleDelete(row: Required<ActivitiesForm>) {
await activitiesRemove(row.id);
await tableApi.query();
}
function handleMultiDelete() {
const rows = tableApi.grid.getCheckboxRecords();
const ids = rows.map((row: Required<ActivitiesForm>) => row.id);
Modal.confirm({
title: '提示',
okType: 'danger',
content: `确认删除选中的${ids.length}条记录吗?`,
onOk: async () => {
await activitiesRemove(ids);
await tableApi.query();
},
});
}
function handleDownloadExcel() {
commonDownloadExcel(activitiesExport, '热门活动数据', tableApi.formApi.form.values, {
fieldMappingTime: formOptions.fieldMappingTime,
});
}
</script>
<template>
<Page :auto-content-height="true">
<BasicTable table-title="热门活动列表">
<template #toolbar-tools>
<Space>
<a-button
v-access:code="['property:activities:export']"
@click="handleDownloadExcel"
>
{{ $t('pages.common.export') }}
</a-button>
<a-button
:disabled="!vxeCheckboxChecked(tableApi)"
danger
type="primary"
v-access:code="['property:activities:remove']"
@click="handleMultiDelete">
{{ $t('pages.common.delete') }}
</a-button>
<a-button
type="primary"
v-access:code="['property:activities:add']"
@click="handleAdd"
>
{{ $t('pages.common.add') }}
</a-button>
</Space>
</template>
<template #action="{ row }">
<Space>
<ghost-button
v-access:code="['property:activities:edit']"
@click.stop="handleEdit(row)"
>
{{ $t('pages.common.edit') }}
</ghost-button>
<Popconfirm
:get-popup-container="getVxePopupContainer"
placement="left"
title="确认删除?"
@confirm="handleDelete(row)"
>
<ghost-button
danger
v-access:code="['property:activities:remove']"
@click.stop=""
>
{{ $t('pages.common.delete') }}
</ghost-button>
</Popconfirm>
</Space>
</template>
</BasicTable>
<ActivitiesModal @reload="tableApi.query()" />
</Page>
</template>

View File

@@ -90,7 +90,7 @@ export const modalSchema: FormSchemaGetter = () => [
{
label: '反馈类型',
fieldName: 'feedbackType',
component: 'Select',
component: 'TreeSelect',
rules: 'selectRequired',
},
{
@@ -160,7 +160,15 @@ export const modalSchema: FormSchemaGetter = () => [
},
rules:'selectRequired'
},
{
label: '工单id',
fieldName: 'orderId',
component: 'Input',
dependencies: {
show: () => false,
triggerFields: [''],
},
},
{
label: '转至工单',//转至工单
fieldName: 'isWorkOrder',
@@ -170,7 +178,11 @@ export const modalSchema: FormSchemaGetter = () => [
options: getDictOptions('wy_sf'),
optionType: 'button',
},
defaultValue:'0',
rules:'selectRequired'
defaultValue:'1',
rules:'selectRequired',
dependencies: {
show: (formValue) => !formValue.orderId,
triggerFields: ['orderId'],
},
},
];

View File

@@ -37,10 +37,12 @@ async function handleOpenChange(open: boolean) {
<Descriptions v-if="feedbacksDetail" size="small" :column="2" bordered
:labelStyle="{width:'120px'}">
<DescriptionsItem label="反馈类型">
{{ feedbacksDetail.feedbackType }}
{{ feedbacksDetail.feedbackTypeName }}
</DescriptionsItem>
<DescriptionsItem label="反馈人">
{{ feedbacksDetail.feedbackPersion+'-'+feedbacksDetail.feedbackPersionPhone }}
<span>
{{ feedbacksDetail.feedbackPersionName||''+'-'+feedbacksDetail.feedbackPersionPhone }}
</span>
</DescriptionsItem>
<DescriptionsItem label="反馈内容" :span="2">
{{ feedbacksDetail.feedbackContent }}

View File

@@ -15,7 +15,9 @@ import {defaultFormValueGetter, useBeforeCloseDiff} from '#/utils/popup';
import {modalSchema} from './data';
import type {FeedbacksVO} from "#/api/property/customerService/feedbacks/model";
import {workOrdersTypeList} from "#/api/property/businessManagement/workOrdersType";
import {
workOrdersTypeTree
} from "#/api/property/businessManagement/workOrdersType";
const emit = defineEmits<{ reload: [] }>();
@@ -101,28 +103,38 @@ async function handleClosed() {
}
async function initWorkOrderTypeOption() {
let params = {
pageSize: 1000,
pageNum: 1
}
const res = await workOrdersTypeList(params)
formApi.updateSchema([{
componentProps: () => ({
options: res.rows,
showSearch: true,
optionFilterProp: 'orderTypeName',
fieldNames: {label: 'orderTypeName', value: 'id'},
}),
fieldName: 'feedbackType',
}])
const options = await workOrdersTypeTree()
formApi.updateSchema([
{
componentProps: () => ({
class: 'w-full',
fieldNames: {
key: 'id',
label: 'orderTypeName',
value: 'id',
children: 'children',
},
placeholder: '请选择反馈类型',
showSearch: true,
treeData: options,
treeDefaultExpandAll: true,
treeLine: { showLeafIcon: false },
treeNodeFilterProp: 'orderTypeName',
treeNodeLabelProp: 'orderTypeName',
}),
fieldName: 'feedbackType',
},
]);
}
</script>
<template>
<BasicModal :title="title">
<BasicForm>
<template #person>
<span v-if="detail">{{ detail.feedbackPersion + '-' + detail.feedbackPersionPhone }}</span>
<span v-if="detail">
{{ detail.feedbackPersionName||'' + '-' + detail.feedbackPersionPhone }}</span>
</template>
</BasicForm>
</BasicModal>

View File

@@ -122,7 +122,7 @@ function handleDownloadExcel() {
<template #action="{ row }">
<Space>
<ghost-button
v-access:code="['system:feedbacks:info']"
v-access:code="['system:feedbacks:query']"
@click.stop="handleInfo(row)"
>
{{ $t('pages.common.info') }}
@@ -134,7 +134,7 @@ function handleDownloadExcel() {
{{ $t('pages.common.edit') }}
</ghost-button>
<ghost-button
v-access:code="['system:feedbacks:info']"
v-access:code="['system:feedbacks:query']"
@click.stop="handleOrderInfo(row)"
:disabled="row.isWorkOrder=='1'"
>

View File

@@ -12,6 +12,7 @@ import { defaultFormValueGetter, useBeforeCloseDiff } from '#/utils/popup';
import { modalSchema } from './data';
import {personList} from "#/api/property/resident/person";
import {renderDictValue} from "#/utils/render";
import {userList} from "#/api/system/user";
const emit = defineEmits<{ reload: [] }>();
@@ -104,11 +105,11 @@ async function queryPersonData() {
pageSize: 1000,
pageNum: 1,
}
const res = await personList(params);
const res = await userList(params);
const options = res.rows.map((user) => ({
label: user.userName + '-' + renderDictValue(user.gender, 'sys_user_sex')
+ '-' + user.phone + '-' + user.unitName,
value: user.id,
label: user.nickName + '-' + renderDictValue(user.sex, 'sys_user_sex')
+ '-' + user.phonenumber,
value: user.userId.toString(),
}));
formApi.updateSchema([{
componentProps: () => ({

View File

@@ -147,7 +147,7 @@ async function handleDelete(row: Required<QuestionnaireForm>) {
<template #action="{ row }">
<Space>
<ghost-button
v-access:code="['property:questionnaire:info']"
v-access:code="['property:questionnaire:query']"
@click.stop="handleInfo(row)"
>
预览问卷
@@ -175,7 +175,7 @@ async function handleDelete(row: Required<QuestionnaireForm>) {
</ghost-button>
</Popconfirm>
<ghost-button
v-access:code="['property:questionnaire:info']"
v-access:code="['property:questionnaire:statistics']"
@click.stop="handleEdit(row)"
>
统计分析

View File

@@ -1,5 +1,5 @@
<script setup lang="ts">
import {reactive, shallowRef} from 'vue';
import {reactive, ref} from 'vue';
import {useVbenModal} from '@vben/common-ui';
import {questionnaireInfo} from "#/api/property/customerService/questionnaire/questionnaire";
import type {
@@ -33,7 +33,7 @@ const [BasicModal, modalApi] = useVbenModal({
},
});
const questionnaireDetail = shallowRef<null | QuestionnaireVO>(null);
const questionnaireDetail = ref<null | QuestionnaireVO>(null);
async function handleOpenChange(open: boolean) {
if (!open) {
@@ -44,7 +44,6 @@ async function handleOpenChange(open: boolean) {
questionnaireDetail.value = await questionnaireInfo(id);
if (questionnaireDetail.value.questionnaireQuestionVos) {
questionnaireDetail.value.questionnaireQuestionVos.forEach(item => {
item.answer = ''
if (item.questionnaireQuestionItemVos) {
item.options = item.questionnaireQuestionItemVos.map(item => item.itemContent)
}

View File

@@ -35,10 +35,10 @@ async function loadTree() {
showTreeSkeleton.value = false;
}
async function handleReload() {
await loadTree();
emit('reload');
}
// async function handleReload() {
// await loadTree();
// emit('reload');
// }
onMounted(loadTree);
</script>
@@ -87,13 +87,6 @@ onMounted(loadTree);
</template>
<style scoped lang="scss">
:deep(html),
:deep(body),
:deep(#app) {
height: 100%;
margin: 0;
padding: 0;
}
.bg-background{
background-color: white;
:deep(.ant-tree){

View File

@@ -370,6 +370,7 @@ onBeforeUnmount(() => {
.left-content {
flex: 1;
height: 95vh;
}
.right-content {
@@ -468,14 +469,14 @@ onBeforeUnmount(() => {
}
.chart-placeholder {
height: 310px;
height: 36vh;
display: flex;
align-items: center;
justify-content: center;
border-radius: 4px;
}
.power-chart{
height: 47vh;
height: 38vh;
display: flex;
align-items: center;
justify-content: center;

View File

@@ -173,7 +173,7 @@ function handleDownloadExcel() {
<template #action="{ row }">
<Space>
<ghost-button
v-access:code="['property:machine:info']"
v-access:code="['property:machine:query']"
@click.stop="handleInfo(row)"
>
{{ $t('pages.common.info') }}

View File

@@ -153,7 +153,7 @@ function handleDownloadExcel() {
<template #action="{ row }">
<Space>
<ghost-button
v-access:code="['property:maintainPlan:info']"
v-access:code="['property:maintainPlan:query']"
@click.stop="handleInfo(row)"
>
{{ $t('pages.common.info') }}

View File

@@ -30,7 +30,7 @@ async function queryUser(value: string, callback: any) {
const options = res.rows.map((user) => ({
label: user.userName,
value: user.userName,
userId: user.userId,
userId: user.id,
userName: user.userName,
}));
callback(options);
@@ -55,7 +55,7 @@ async function getUserInfo(val:number|string) {
const user = await personInfo(val)
if (user) {
data.value = [{
userId: user.userId,
userId: user.id,
userName: user.userName,
}]
emit('update:userInfo', data.value[0]);

View File

@@ -110,13 +110,13 @@ function handleMultiDelete() {
:disabled="!vxeCheckboxChecked(tableApi)"
danger
type="primary"
v-access:code="['property:property:remove']"
v-access:code="['property:plantsProduct:remove']"
@click="handleMultiDelete">
{{ $t('pages.common.delete') }}
</a-button>
<a-button
type="primary"
v-access:code="['property:property:add']"
v-access:code="['property:plantsProduct:add']"
@click="handleAdd"
>
{{ $t('pages.common.add') }}
@@ -126,12 +126,13 @@ function handleMultiDelete() {
<template #action="{ row }">
<Space>
<ghost-button
v-access:code="['property:plantsProduct:query']"
@click.stop="handleInfo(row)"
>
{{ $t('pages.common.info') }}
</ghost-button>
<ghost-button
v-access:code="['property:property:edit']"
v-access:code="['property:plantsProduct:edit']"
@click.stop="handleEdit(row)"
>
{{ $t('pages.common.edit') }}
@@ -144,7 +145,7 @@ function handleMultiDelete() {
>
<ghost-button
danger
v-access:code="['property:property:remove']"
v-access:code="['property:plantsProduct:remove']"
@click.stop=""
>
{{ $t('pages.common.delete') }}

View File

@@ -105,7 +105,7 @@ function handleDownloadExcel() {
<template #action="{ row }">
<Space>
<ghost-button
v-access:code="['property:inspectionTask:info']"
v-access:code="['property:inspectionTask:query']"
@click.stop="handInfo(row)"
>
{{ $t('pages.common.info') }}

View File

@@ -149,7 +149,7 @@ const { hasAccessByCodes } = useAccess();
<template #action="{ row }">
<Space>
<ghost-button
v-access:code="['property:inspectionPlan:info']"
v-access:code="['property:inspectionPlan:query']"
@click.stop="handleInfo(row)"
>
{{ $t('pages.common.info') }}

View File

@@ -155,7 +155,7 @@ async function handleDownload(row){
<template #action="{ row }">
<Space>
<ghost-button
v-access:code="['property:inspectionPoint:info']"
v-access:code="['property:inspectionPoint:query']"
@click.stop="handleInfo(row)"
>
{{ $t('pages.common.info') }}

View File

@@ -10,7 +10,6 @@ import { inspectionPointAdd, inspectionPointInfo, inspectionPointUpdate } from '
import { defaultFormValueGetter, useBeforeCloseDiff } from '#/utils/popup';
import { modalSchema } from './data';
import {workOrdersTypeList} from "#/api/property/businessManagement/workOrdersType";
const emit = defineEmits<{ reload: [] }>();
@@ -54,7 +53,6 @@ const [BasicModal, modalApi] = useVbenModal({
return null;
}
modalApi.modalLoading(true);
await queryWorkOrdersType()
const { id } = modalApi.getData() as { id?: number | string };
isUpdate.value = !!id;
@@ -92,31 +90,6 @@ async function handleClosed() {
await formApi.resetForm();
resetInitialized();
}
async function queryWorkOrdersType() {
let params = {
pageSize: 1000,
pageNum: 1
}
const res = await workOrdersTypeList(params)
const options = res.rows.map((item) => ({
label: item.orderTypeName,
value: item.id,
}));
formApi.updateSchema([{
componentProps: () => ({
options: options,
filterOption: filterOption,
showSearch:true,
}),
fieldName: 'type',
}])
}
const filterOption = (input: string, option: any) => {
return option.label.toLowerCase().indexOf(input.toLowerCase()) >= 0;
};
</script>
<template>

View File

@@ -143,5 +143,6 @@ export const modalSchema: FormSchemaGetter = () => [
label: '描述',
fieldName: 'depict',
component: 'Textarea',
rules: 'required',
},
];

View File

@@ -147,7 +147,7 @@ function handleDownloadExcel() {
<template #action="{ row }">
<Space>
<ghost-button
v-access:code="['domain:knowledge:info']"
v-access:code="['domain:knowledge:query']"
@click.stop="handleInfo(row)"
>
{{ $t('pages.common.info') }}

View File

@@ -0,0 +1,83 @@
import type { FormSchemaGetter } from '#/adapter/form'
import type { VxeGridProps } from '#/adapter/vxe-table'
export const querySchema: FormSchemaGetter = () => [
{
component: 'Input',
fieldName: 'locationRemark',
label: '位置描述',
},
]
// 需要使用i18n注意这里要改成getter形式 否则切换语言不会刷新
// export const columns: () => VxeGridProps['columns'] = () => [
export const columns: VxeGridProps['columns'] = [
{ type: 'checkbox', width: 60 },
// {
// title: '主键id',
// field: 'id',
// },
{
title: '位置描述',
field: 'locationRemark',
},
{
title: '楼 层',
field: 'floorName',
},
{
title: '开关状态',
field: 'isOn',
slots: { default: 'isOn' },
},
{
field: 'action',
fixed: 'right',
slots: { default: 'action' },
title: '操作',
width: 180,
},
]
export const drawerSchema: FormSchemaGetter = () => [
{
label: '主键id',
fieldName: 'id',
component: 'Input',
dependencies: {
show: () => false,
triggerFields: [''],
},
},
{
label: '楼层',
fieldName: 'floorId',
component: 'TreeSelect',
defaultValue: undefined,
rules: 'required',
},
{
label: '位置描述',
fieldName: 'locationRemark',
component: 'Input',
rules: 'required',
},
{
label: '开关状态',
fieldName: 'isOn',
component: 'Switch',
rules: 'required',
defaultValue: false,
componentProps: {
class: 'w-auto',
},
},
{
label: '灯控模块编码',
fieldName: 'code',
component: 'Input',
rules: 'required',
},
]

View File

@@ -0,0 +1,81 @@
<script setup lang="ts">
import type { PropType } from 'vue'
import { onMounted, ref } from 'vue'
import { handleNode } from '@vben/utils'
import { Empty, Skeleton, Tree } from 'ant-design-vue'
import { communityTree } from "#/api/property/community"
import type { CommunityVO } from "#/api/property/community/model"
defineOptions({ inheritAttrs: false })
withDefaults(defineProps<{ showSearch?: boolean }>(), { showSearch: true })
const emit = defineEmits<{
/**
* 点击刷新按钮的事件
*/
reload: []
/**
* 点击节点的事件
*/
select: []
}>()
const selectFloorId = defineModel('selectFloorId', {
type: Array as PropType<string[]>,
})
const searchValue = defineModel('searchValue', {
type: String,
default: '',
})
type TreeArray = CommunityVO[]
const treeArray = ref<TreeArray>([])
/** 骨架屏加载 */
const showTreeSkeleton = ref<boolean>(true)
async function loadTree() {
showTreeSkeleton.value = true
searchValue.value = ''
selectFloorId.value = []
const ret = await communityTree(3)
const splitStr = '/'
handleNode(ret, 'label', splitStr, function (node: any) {
if (node.level != 3) {
node.disabled = true
}
})
treeArray.value = ret
showTreeSkeleton.value = false
}
onMounted(loadTree);
</script>
<template>
<div :class="$attrs.class">
<Skeleton :loading="showTreeSkeleton" :paragraph="{ rows: 8 }" active class="p-[8px] flex-1 min-h-0">
<div class="bg-background flex h-full flex-col overflow-y-auto rounded-lg">
<div class="h-full overflow-x-hidden px-[8px]">
<Tree v-bind="$attrs" v-if="treeArray.length > 0" v-model:selected-keys="selectFloorId"
:field-names="{ title: 'label', key: 'id' }" :show-line="{ showLeafIcon: false }" :tree-data="treeArray"
:virtual="false" default-expand-all @select="$emit('select')">
<template #title="{ label }">
<span v-if="label.indexOf(searchValue) > -1">
{{ label.substring(0, label.indexOf(searchValue)) }}
<span style="color: #f50">{{ searchValue }}</span>
{{ label.substring(label.indexOf(searchValue) + searchValue.length) }}
</span>
<span v-else>{{ label }}</span>
</template>
</Tree>
<div v-else class="mt-5">
<Empty :image="Empty.PRESENTED_IMAGE_SIMPLE" description="暂无数据" />
</div>
</div>
</div>
</Skeleton>
</div>
</template>

View File

@@ -0,0 +1,173 @@
<script setup lang="ts">
import { TableSwitch } from "#/components/table"
import { Page, useVbenDrawer, type VbenFormProps } from '@vben/common-ui'
import { getVxePopupContainer } from '@vben/utils';
import { ref } from 'vue'
import { columns, querySchema } from './data'
import { Modal, Popconfirm, Space } from 'ant-design-vue'
import FloorTree from "./floor-tree.vue"
import lightInfoDrawer from './lightInfo-drawer.vue'
import {
useVbenVxeGrid,
vxeCheckboxChecked,
type VxeGridProps
} from '#/adapter/vxe-table'
import {
lightInfoList,
lightInfoRemove,
switchSingleLight,
} from '#/api/property/meter/lightInfo'
import type { LightInfoForm } from '#/api/property/meter/lightInfo/model'
// 左边楼层用
const selectFloorId = ref<string[]>([])
const formOptions: VbenFormProps = {
commonConfig: {
labelWidth: 80,
componentProps: {
allowClear: true,
},
},
schema: querySchema(),
wrapperClass: 'grid-cols-1 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4',
handleReset: async () => {
selectFloorId.value = []
const { formApi, reload } = tableApi
await formApi.resetForm()
const formValues = formApi.form.values
formApi.setLatestSubmissionValues(formValues)
await reload(formValues)
},
}
const gridOptions: VxeGridProps = {
checkboxConfig: {
// 高亮
highlight: true,
// 翻页时保留选中状态
reserve: true,
// 点击行选中
// trigger: 'row',
},
// 需要使用i18n注意这里要改成getter形式 否则切换语言不会刷新
// columns: columns(),
columns,
height: 'auto',
keepSource: true,
pagerConfig: {},
proxyConfig: {
ajax: {
query: async ({ page }, formValues = {}) => {
// 部门树选择处理
if (selectFloorId.value.length === 1) {
formValues.floorId = selectFloorId.value[0]
} else {
Reflect.deleteProperty(formValues, 'deptId')
}
return await lightInfoList({
pageNum: page.currentPage,
pageSize: page.pageSize,
...formValues,
})
},
},
},
rowConfig: {
keyField: 'id',
},
// 表格全局唯一表示 保存列配置需要用到
id: 'property-lightInfo-index'
}
const [BasicTable, tableApi] = useVbenVxeGrid({
formOptions,
gridOptions,
})
const [LightInfoDrawer, drawerApi] = useVbenDrawer({
connectedComponent: lightInfoDrawer,
})
function handleAdd() {
drawerApi.setData({})
drawerApi.open()
}
async function handleEdit(row: Required<LightInfoForm>) {
drawerApi.setData({ id: row.id })
drawerApi.open()
}
async function handleDelete(row: Required<LightInfoForm>) {
await lightInfoRemove(row.id)
await tableApi.query()
}
function handleMultiDelete() {
const rows = tableApi.grid.getCheckboxRecords()
const ids = rows.map((row: Required<LightInfoForm>) => row.id)
Modal.confirm({
title: '提示',
okType: 'danger',
content: `确认删除选中的${ids.length}条记录吗?`,
onOk: async () => {
await lightInfoRemove(ids)
await tableApi.query()
},
})
}
</script>
<template>
<Page :auto-content-height="true">
<div class="flex h-full gap-[8px]">
<FloorTree class="w-[260px]" @reload="() => tableApi.reload()" @select="() => tableApi.reload()"
v-model:select-floor-id="selectFloorId"></FloorTree>
<BasicTable class="flex-1 overflow-hidden" table-title="灯控开关信息列表">
<template #toolbar-tools>
<Space>
<a-button type="primary" v-access:code="['property:lightInfo:add']" @click="handleAdd">
{{ $t('pages.common.add') }}
</a-button>
<a-button :disabled="!vxeCheckboxChecked(tableApi)" danger type="primary"
v-access:code="['property:lightInfo:remove']" @click="handleMultiDelete">
{{ $t('pages.common.delete') }}
</a-button>
<a-button :disabled="!vxeCheckboxChecked(tableApi)" danger type="primary">
关灯
</a-button>
<a-button :disabled="!vxeCheckboxChecked(tableApi)" success type="primary">
开灯
</a-button>
</Space>
</template>
<template #action="{ row }">
<Space>
<ghost-button v-access:code="['property:lightInfo:edit']" @click.stop="handleEdit(row)">
{{ $t('pages.common.edit') }}
</ghost-button>
<Popconfirm :get-popup-container="getVxePopupContainer" placement="left" title="确认删除?"
@confirm="handleDelete(row)">
<ghost-button danger v-access:code="['property:lightInfo:remove']" @click.stop="">
{{ $t('pages.common.delete') }}
</ghost-button>
</Popconfirm>
</Space>
</template>
<template #isOn="{ row }">
<TableSwitch :checkedValue=true :unCheckedValue=false v-model:value="row.isOn" checked-children=""
un-checked-children="" :api="() => switchSingleLight({'id':row.id, 'isOn':row.isOn})"
@reload="() => tableApi.query()" />
</template>
</BasicTable>
</div>
<LightInfoDrawer @reload="tableApi.query()" />
</Page>
</template>

View File

@@ -0,0 +1,140 @@
<script setup lang="ts">
import { computed, ref } from 'vue'
import { useVbenDrawer } from '@vben/common-ui'
import { $t } from '@vben/locales'
import { cloneDeep, getPopupContainer, handleNode } from '@vben/utils'
import { useVbenForm } from '#/adapter/form'
import { communityTree } from '#/api/property/community'
import { lightInfoAdd, lightInfoInfo, lightInfoUpdate } from '#/api/property/meter/lightInfo'
import { defaultFormValueGetter, useBeforeCloseDiff } from '#/utils/popup'
import { drawerSchema } from './data';
const emit = defineEmits<{ reload: [] }>()
const isUpdate = ref(false)
const title = computed(() => {
return isUpdate.value ? $t('pages.common.edit') : $t('pages.common.add')
})
const [BasicForm, formApi] = useVbenForm({
commonConfig: {
// 默认占满两列
formItemClass: 'col-span-2',
// 默认label宽度 px
labelWidth: 100,
// 通用配置项 会影响到所有表单项
componentProps: {
class: 'w-full',
}
},
schema: drawerSchema(),
showDefaultActions: false,
wrapperClass: 'grid-cols-2',
})
const { onBeforeClose, markInitialized, resetInitialized } = useBeforeCloseDiff(
{
initializedGetter: defaultFormValueGetter(formApi),
currentGetter: defaultFormValueGetter(formApi),
},
)
const [BasicModal, modalApi] = useVbenDrawer({
// 在这里更改宽度
class: 'w-[550px]',
fullscreenButton: false,
onBeforeClose,
onClosed: handleClosed,
onConfirm: handleConfirm,
onOpenChange: async (isOpen) => {
if (!isOpen) {
return null
}
modalApi.drawerLoading(true)
const { id } = modalApi.getData() as { id?: number | string }
isUpdate.value = !!id
setupCommunitySelect()
if (isUpdate.value && id) {
const record = await lightInfoInfo(id)
await formApi.setValues(record)
}
await markInitialized()
modalApi.drawerLoading(false)
},
})
async function handleConfirm() {
try {
modalApi.lock(true)
const { valid } = await formApi.validate()
if (!valid) {
return
}
// getValues获取为一个readonly的对象 需要修改必须先深拷贝一次
const data = cloneDeep(await formApi.getValues())
await (isUpdate.value ? lightInfoUpdate(data) : lightInfoAdd(data))
resetInitialized()
emit('reload')
modalApi.close()
} catch (error) {
console.error(error)
} finally {
modalApi.lock(false)
}
}
/**
* 初始化城市
*/
async function setupCommunitySelect() {
const areaList = await communityTree(3)
// 选中后显示在输入框的值 即父节点 / 子节点
// addFullName(areaList, 'areaName', ' / ');
const splitStr = '/'
handleNode(areaList, 'label', splitStr, function (node: any) {
if (node.level != 3) {
node.disabled = true
}
})
formApi.updateSchema([
{
componentProps: () => ({
fieldNames: {
key: 'id',
label: 'label',
value: 'code',
children: 'children',
},
getPopupContainer,
placeholder: '请选择建筑',
showSearch: true,
treeData: areaList,
treeDefaultExpandAll: true,
treeLine: { showLeafIcon: false },
// 筛选的字段
treeNodeFilterProp: 'label',
// 选中后显示在输入框的值
treeNodeLabelProp: 'fullName',
}),
fieldName: 'floorId',
},
])
}
async function handleClosed() {
await formApi.resetForm()
resetInitialized()
}
</script>
<template>
<BasicModal :title="title">
<BasicForm />
</BasicModal>
</template>

View File

@@ -6,7 +6,7 @@ import {attachListAll} from '#/api/property/roomBooking/conferenceAddServices';
import {meetInfo} from '#/api/property/roomBooking/conferenceSettings';
import {defaultFormValueGetter, useBeforeCloseDiff} from '#/utils/popup';
import {modalSchema} from './data';
import type {conferenceSettingsDetail} from "#/api/property/roomBooking/conferenceSettings/model";
import type {ConferenceSettingsDetail} from "#/api/property/roomBooking/conferenceSettings/model";
import type {AttachVO} from "#/api/property/roomBooking/conferenceAddServices/model";
import {addServiceColumns} from "./data";
import {Table, InputNumber, TimeRangePicker} from "ant-design-vue";
@@ -17,7 +17,7 @@ import {reservationAdd} from "#/api/property/roomBooking/conferenceReservations"
import {ref} from "vue";
const emit = defineEmits<{ reload: [] }>();
const conferenceSettingDetail = ref<conferenceSettingsDetail>()
const conferenceSettingDetail = ref<ConferenceSettingsDetail>()
const addServiceList = ref<AttachVO[]>([])
const totalAmount = ref<number>(0)
const [BasicForm, formApi] = useVbenForm({
@@ -188,7 +188,7 @@ async function changeProjectNum() {
conferenceSettingDetail.expenseType == '2' ? conferenceSettingDetail.basePrice + '元' :
renderDictValue(conferenceSettingDetail.expenseType, 'wy_fyms')
}}</span>
<span>开放时段{{ conferenceSettingDetail.openHours }}</span>
<span>开放时段{{ conferenceSettingDetail.openStartHours+'-'+conferenceSettingDetail.openEndHours }}</span>
</div>
</div>
<BasicForm>

View File

@@ -53,7 +53,7 @@
item.expenseType == '2' ? (item.basePrice+"元") : renderDictValue(item.expenseType, 'wy_fyms')
}}
</div>
<div>开放时段: {{ item.openHours }}</div>
<div>开放时段: {{ item.openStartHours+'-'+item.openEndHours }}</div>
<div>配套设备: {{ item.baseService }}</div>
</div>
</div>
@@ -102,14 +102,18 @@ const simpleImage = Empty.PRESENTED_IMAGE_SIMPLE;
const meetingList = ref<MeetVO[]>([])
async function handleSearch() {
let hours = '';
let openStartHours = '';
let openEndHours = '';
if (formState.openHours && formState.openHours.length) {
hours = formState.openHours[0]?.format("HH:mm") + '-' + formState.openHours[1]?.format("HH:mm");
openStartHours=formState.openHours[0]?.format("HH:mm");
openEndHours=formState.openHours[1]?.format("HH:mm");
}
const obj = {
openHours: hours??undefined,
personNumber: formState.personNumber,
appointmentTime:formState.appointmentTime?formState.appointmentTime.format('YYYY-MM-DD'):undefined
openStartHours: openStartHours??undefined,
openEndHours:openEndHours??undefined,
appointmentTime:formState.appointmentTime?formState.appointmentTime.format('YYYY-MM-DD'):undefined,
meetingRoomType:formState.meetingRoomType
}
meetingList.value =await notlist(obj);
}

View File

@@ -1,5 +1,7 @@
<script setup lang="ts">
import type {conferenceSettingsDetail} from '#/api/property/roomBooking/conferenceSettings/model';
import type {
ConferenceSettingsDetail,
} from '#/api/property/roomBooking/conferenceSettings/model';
import {shallowRef} from 'vue';
import {useVbenModal} from '@vben/common-ui';
import {Descriptions, DescriptionsItem} from 'ant-design-vue';
@@ -19,7 +21,7 @@ const [BasicModal, modalApi] = useVbenModal({
},
});
const conferenceSettingsDetail = shallowRef<null | conferenceSettingsDetail>(null);
const conferenceSettingsDetail = shallowRef<null | ConferenceSettingsDetail>(null);
async function handleOpenChange(open: boolean) {
if (!open) {
@@ -73,7 +75,7 @@ async function handleOpenChange(open: boolean) {
/>
</DescriptionsItem>
<DescriptionsItem label="开放时段" :span="2">
{{ conferenceSettingsDetail.openHours }}
{{ conferenceSettingsDetail.openStartHours+'-'+ conferenceSettingsDetail.openEndHours}}
</DescriptionsItem>
<DescriptionsItem label="会议室描述" :span="2">
{{ conferenceSettingsDetail.descs }}

View File

@@ -16,9 +16,10 @@ import { defaultFormValueGetter, useBeforeCloseDiff } from '#/utils/popup';
import { modalSchema } from './data';
import { TimeRangePicker } from 'ant-design-vue';
import { renderDictValue } from '#/utils/render';
import { personList } from '#/api/property/resident/person';
import { communityTree } from '#/api/property/community';
import dayjs from 'dayjs';
import {userList} from "#/api/system/user";
import {getDictOptions} from "#/utils/dict";
const emit = defineEmits<{ reload: [] }>();
const isUpdate = ref(false);
@@ -67,15 +68,15 @@ const [BasicModal, modalApi] = useVbenModal({
});
const { id } = modalApi.getData() as { id?: number | string };
isUpdate.value = !!id;
getDictOptions('sys_user_sex')
await queryPerson();
await initLocationOptions();
if (isUpdate.value && id) {
const record = await meetInfo(id);
record.expenseType = record.expenseType.toString();
record.isCheck = record.isCheck.toString();
let hour = record.openHours.split('-');
if (hour.length > 1) {
record.openHours = [dayjs(hour[0], 'HH:mm'), dayjs(hour[1], 'HH:mm')];
if (record.openStartHours&&record.openEndHours) {
record.openHours = [dayjs(record.openStartHours, 'HH:mm'), dayjs(record.openEndHours, 'HH:mm')];
}
await formApi.setValues(record);
}
@@ -95,10 +96,8 @@ async function handleConfirm() {
// getValues获取为一个readonly的对象 需要修改必须先深拷贝一次
const data = cloneDeep(await formApi.getValues());
if (data.openHours) {
data.openHours =
data.openHours[0]?.format('HH:mm') +
'-' +
data.openHours[1]?.format('HH:mm');
data.openStartHours=data.openHours[0]?.format('HH:mm');
data.openEndHours=data.openHours[1]?.format('HH:mm');
}
await (isUpdate.value ? meetUpdate(data) : meetAdd(data));
resetInitialized();
@@ -117,19 +116,18 @@ async function handleClosed() {
}
async function queryPerson() {
let params = {
pageSize: 1000,
const res = await userList({
pageNum: 1,
};
const res = await personList(params);
pageSize: 1000,
});
const options = res.rows.map((user) => ({
label:
user.userName +
user.nickName +
'-' +
renderDictValue(user.gender, 'sys_user_sex') +
renderDictValue(user.sex, 'sys_user_sex') +
'-' +
user.phone,
value: user.id,
user.phonenumber,
value: user.userId,
}));
formApi.updateSchema([
{
@@ -143,6 +141,7 @@ async function queryPerson() {
]);
}
const filterOption = (input: string, option: any) => {
return option.label.toLowerCase().indexOf(input.toLowerCase()) >= 0;
};

View File

@@ -76,6 +76,11 @@ export const columns: VxeGridProps['columns'] = [
title: '开放时段',
field: 'openHours',
width:100,
slots: {
default: ({row}) => {
return row.openStartHours+'-'+row.openEndHours;
},
},
},
{
title: '状态',

View File

@@ -2,6 +2,7 @@ import type { FormSchemaGetter } from '#/adapter/form';
import type { VxeGridProps } from '#/adapter/vxe-table';
import {getDictOptions} from "#/utils/dict";
import {renderDict} from "#/utils/render";
import {personList} from '#/api/property/resident/person'
export const querySchema: FormSchemaGetter = () => [
{
@@ -148,10 +149,23 @@ export const modalSchema: FormSchemaGetter = () => [
component: 'Input',
rules: 'required',
},
// {
// label: '邀约单位',
// fieldName: 'interviewedUnit',
// component: 'Input',
// rules: 'required',
// },
{
label: '邀约单位',
fieldName: 'interviewedUnit',
component: 'Input',
component: 'ApiSelect',
componentProps: {
api: personList,
resultField: 'rows',
labelField: 'unitName',
valueField: 'unitName',
placeholder: '请选择邀约单位',
},
rules: 'required',
},
{
@@ -206,13 +220,14 @@ export const modalSchema: FormSchemaGetter = () => [
// triggerFields: ['bookingParkingSpace'],
// },
// },
// {
// label: '人脸图片',
// fieldName: 'facePictures',
// component: 'ImageUpload',
// componentProps: {
// maxCount: 1,
// },
// formItemClass: 'col-span-2',
// },
{
label: '人脸图片',
fieldName: 'facePictures',
component: 'ImageUpload',
componentProps: {
maxCount: 1,
},
formItemClass: 'col-span-2',
rules: 'required',
},
];

View File

@@ -39,6 +39,7 @@ const gridOptions: VxeGridProps = {
return await visitorManagementList({
pageNum: page.currentPage,
pageSize: page.pageSize,
type:1,
...formValues,
// visitingBeginTime: new Date(formValues.visitingTimeRange[0]).getTime(),
// visitingEndTime: new Date(formValues.visitingTimeRange[1]).getTime(),
@@ -98,6 +99,7 @@ function handleAdd() {
<Space>
<ghost-button
@click.stop="handleInfo(row)"
v-access:code="['property:visitorManagement:query']"
>
{{ $t('pages.common.info') }}
</ghost-button>

View File

@@ -76,10 +76,10 @@ async function handleConfirm() {
// 自定义深拷贝
const data = {
...cloneDeep(formValues),
facePictures: 1,
visitingBeginTime: formValues.visitingTimeRange?.[0],
visitingEndTime: formValues.visitingTimeRange?.[1],
visitingTimeRange: undefined
visitingTimeRange: undefined,
type:1
};
// getValues获取为一个readonly的对象 需要修改必须先深拷贝一次
// const data = cloneDeep(await formApi.getValues());

View File

@@ -45,6 +45,7 @@ const gridOptions: VxeGridProps = {
pageNum: page.currentPage,
pageSize: page.pageSize,
...formValues,
type:0,
visitingBeginTime: formValues.visitingTimeRange?.[0],
visitingEndTime: formValues.visitingTimeRange?.[1],
visitingTimeRange: undefined
@@ -76,10 +77,10 @@ const [VisitorTodoModal, modalApi] = useVbenModal({
connectedComponent: visitorTodoModal,
});
async function handleEdit(row: Required<VisitorManagementForm>) {
modalApi.setData({ id: row.id });
modalApi.open();
}
// async function handleEdit(row: Required<VisitorManagementForm>) {
// modalApi.setData({ id: row.id });
// modalApi.open();
// }
</script>
<template>
@@ -89,15 +90,16 @@ async function handleEdit(row: Required<VisitorManagementForm>) {
<Space>
<ghost-button
@click.stop="handleInfo(row)"
v-access:code="['property:visitorManagement:query']"
>
{{ $t('pages.common.info') }}
</ghost-button>
<ghost-button
@click.stop="handleEdit(row)"
v-if="row.serveStatus === 0"
>
{{ '审核' }}
</ghost-button>
<!-- <ghost-button-->
<!-- @click.stop="handleEdit(row)"-->
<!-- v-if="row.serveStatus === 0"-->
<!-- >-->
<!-- {{ '审核' }}-->
<!-- </ghost-button>-->
</Space>
</template>
</BasicTable>

View File

@@ -301,6 +301,7 @@ onBeforeUnmount(() => {
.left-content {
flex: 1;
height: 95vh;
}
.right-content {
@@ -386,11 +387,11 @@ onBeforeUnmount(() => {
}
.power-chart{
height: 55vh;
height: 45vh;
}
.energy-chart{
height: 240px;
height: 30vh;
}
</style>

View File

@@ -137,6 +137,7 @@ const handleAccountLogin = async () => {
type="password"
placeholder="请输入您的密码"
v-model="password"
@keyup.enter="handleAccountLogin"
/>
</div>

View File

@@ -187,7 +187,7 @@ catalog:
vue-tippy: ^6.7.0
vue-tsc: 2.2.10
vxe-pc-ui: ^4.5.35
vxe-table: ^4.13.16
vxe-table: 4.13.53
watermark-js-plus: ^1.6.0
zod: ^3.24.3
zod-defaults: ^0.1.3