diff --git a/src/api/owner/addOwnerMemberApi.js b/src/api/owner/addOwnerMemberApi.js new file mode 100644 index 0000000..a9f32ed --- /dev/null +++ b/src/api/owner/addOwnerMemberApi.js @@ -0,0 +1,20 @@ +import request from '@/utils/request' + +export function saveOwnerMember(data) { + return new Promise((resolve, reject) => { + request({ + url: '/owner.saveOwnerMember', + method: 'post', + data + }).then(response => { + const res = response.data + if (res.code === 0) { + resolve(res) + } else { + reject(new Error(res.msg || 'Failed to save owner member')) + } + }).catch(error => { + reject(error) + }) + }) +} \ No newline at end of file diff --git a/src/api/owner/ownerDetailAccessControlApi.js b/src/api/owner/ownerDetailAccessControlApi.js new file mode 100644 index 0000000..6f6a6f6 --- /dev/null +++ b/src/api/owner/ownerDetailAccessControlApi.js @@ -0,0 +1,20 @@ +import request from '@/utils/request' + +export function listMachineTranslates(params) { + return new Promise((resolve, reject) => { + request({ + url: '/machineTranslate.listMachineTranslates', + method: 'get', + params + }).then(response => { + const res = response.data + if (res.code === 0) { + resolve(res) + } else { + reject(new Error(res.msg || '获取门禁同步记录失败')) + } + }).catch(error => { + reject(error) + }) + }) +} \ No newline at end of file diff --git a/src/api/owner/ownerDetailAccessControlRecordApi.js b/src/api/owner/ownerDetailAccessControlRecordApi.js new file mode 100644 index 0000000..8152a4c --- /dev/null +++ b/src/api/owner/ownerDetailAccessControlRecordApi.js @@ -0,0 +1,20 @@ +import request from '@/utils/request' + +export function getOpenApi(params) { + return new Promise((resolve, reject) => { + request({ + url: '/iot.getOpenApi', + method: 'get', + params + }).then(response => { + const res = response.data + if (res.code === 0) { + resolve(res) + } else { + reject(new Error(res.msg || '获取门禁记录失败')) + } + }).catch(error => { + reject(error) + }) + }) +} \ No newline at end of file diff --git a/src/api/owner/ownerDetailAccountApi.js b/src/api/owner/ownerDetailAccountApi.js new file mode 100644 index 0000000..9f538c1 --- /dev/null +++ b/src/api/owner/ownerDetailAccountApi.js @@ -0,0 +1,20 @@ +import request from '@/utils/request' + +export function queryCommunityOwnerAccount(params) { + return new Promise((resolve, reject) => { + request({ + url: '/account.queryCommunityOwnerAccount', + method: 'get', + params + }).then(response => { + const res = response.data + if (res.code == 0) { + resolve(res) + } else { + reject(new Error(res.msg || '获取业主账户列表失败')) + } + }).catch(error => { + reject(error) + }) + }) +} \ No newline at end of file diff --git a/src/api/owner/ownerDetailAccountReceiptApi.js b/src/api/owner/ownerDetailAccountReceiptApi.js new file mode 100644 index 0000000..226e97f --- /dev/null +++ b/src/api/owner/ownerDetailAccountReceiptApi.js @@ -0,0 +1,20 @@ +import request from '@/utils/request' + +export function listAccountReceipt(params) { + return new Promise((resolve, reject) => { + request({ + url: '/receipt.listAccountReceipt', + method: 'get', + params + }).then(response => { + const res = response.data + if (res.code === 0) { + resolve(res) + } else { + reject(new Error(res.msg || '获取账户收据列表失败')) + } + }).catch(error => { + reject(error) + }) + }) +} \ No newline at end of file diff --git a/src/api/owner/ownerDetailApi.js b/src/api/owner/ownerDetailApi.js new file mode 100644 index 0000000..c5963a1 --- /dev/null +++ b/src/api/owner/ownerDetailApi.js @@ -0,0 +1,21 @@ +import request from '@/utils/request' + +// Query owner information +export function queryOwners(params) { + return new Promise((resolve, reject) => { + request({ + url: '/owner.queryOwners', + method: 'get', + params + }).then(response => { + const res = response.data + if (res.code === 0) { + resolve(res) + } else { + reject(new Error(res.msg || 'Failed to query owners')) + } + }).catch(error => { + reject(error) + }) + }) +} \ No newline at end of file diff --git a/src/api/owner/ownerDetailAppUserApi.js b/src/api/owner/ownerDetailAppUserApi.js new file mode 100644 index 0000000..461faa1 --- /dev/null +++ b/src/api/owner/ownerDetailAppUserApi.js @@ -0,0 +1,39 @@ +import request from '@/utils/request' + +export function listAuditAppUserBindingOwners(params) { + return new Promise((resolve, reject) => { + request({ + url: '/owner.listAuditAppUserBindingOwners', + method: 'get', + params + }).then(response => { + const res = response.data + if (res.code == 0) { + resolve(res) + } else { + reject(new Error(res.msg || '获取业主APP用户列表失败')) + } + }).catch(error => { + reject(error) + }) + }) +} + +export function updateAppUserBindingOwner(data) { + return new Promise((resolve, reject) => { + request({ + url: '/owner.updateAppUserBindingOwner', + method: 'post', + data + }).then(response => { + const res = response.data + if (res.code == 0) { + resolve(res) + } else { + reject(new Error(res.msg || '审核业主APP用户失败')) + } + }).catch(error => { + reject(error) + }) + }) +} \ No newline at end of file diff --git a/src/api/owner/ownerDetailCarApi.js b/src/api/owner/ownerDetailCarApi.js new file mode 100644 index 0000000..73fbadd --- /dev/null +++ b/src/api/owner/ownerDetailCarApi.js @@ -0,0 +1,20 @@ +import request from '@/utils/request' + +export function queryOwnerCars(params) { + return new Promise((resolve, reject) => { + request({ + url: '/owner.queryOwnerCars', + method: 'get', + params + }).then(response => { + const res = response.data + if (res.code === 0) { + resolve(res) + } else { + reject(new Error(res.msg || 'Failed to query owner cars')) + } + }).catch(error => { + reject(error) + }) + }) +} \ No newline at end of file diff --git a/src/api/owner/ownerDetailChargeMachineOrderApi.js b/src/api/owner/ownerDetailChargeMachineOrderApi.js new file mode 100644 index 0000000..65d81fd --- /dev/null +++ b/src/api/owner/ownerDetailChargeMachineOrderApi.js @@ -0,0 +1,20 @@ +import request from '@/utils/request' + +export function getOpenApi(params) { + return new Promise((resolve, reject) => { + request({ + url: '/iot.getOpenApi', + method: 'get', + params + }).then(response => { + const res = response.data + if (res.code === 0) { + resolve(res) + } else { + reject(new Error(res.msg || '获取充电订单失败')) + } + }).catch(error => { + reject(error) + }) + }) +} \ No newline at end of file diff --git a/src/api/owner/ownerDetailComplaintApi.js b/src/api/owner/ownerDetailComplaintApi.js new file mode 100644 index 0000000..d3a955a --- /dev/null +++ b/src/api/owner/ownerDetailComplaintApi.js @@ -0,0 +1,17 @@ +import request from '@/utils/request' + +export function listComplaints(params) { + return request({ + url: '/complaint.listComplaints', + method: 'get', + params + }) +} + +export function listRunWorkflowImage(params) { + return request({ + url: '/complaint/listRunWorkflowImage', + method: 'get', + params + }) +} \ No newline at end of file diff --git a/src/api/owner/ownerDetailContractApi.js b/src/api/owner/ownerDetailContractApi.js new file mode 100644 index 0000000..9bd0a6c --- /dev/null +++ b/src/api/owner/ownerDetailContractApi.js @@ -0,0 +1,20 @@ +import request from '@/utils/request' + +export function queryContract(params) { + return new Promise((resolve, reject) => { + request({ + url: '/contract/queryContract', + method: 'get', + params + }).then(response => { + const res = response.data + if (res.code == 0) { + resolve(res) + } else { + reject(new Error(res.msg || '获取业主合同列表失败')) + } + }).catch(error => { + reject(error) + }) + }) +} \ No newline at end of file diff --git a/src/api/owner/ownerDetailCouponApi.js b/src/api/owner/ownerDetailCouponApi.js new file mode 100644 index 0000000..3bff953 --- /dev/null +++ b/src/api/owner/ownerDetailCouponApi.js @@ -0,0 +1,9 @@ +import request from '@/utils/request' + +export function listComplaints(params) { + return request({ + url: '/complaint/listComplaints', + method: 'get', + params + }) + } \ No newline at end of file diff --git a/src/api/owner/ownerDetailHisApi.js b/src/api/owner/ownerDetailHisApi.js new file mode 100644 index 0000000..6989300 --- /dev/null +++ b/src/api/owner/ownerDetailHisApi.js @@ -0,0 +1,22 @@ +import request from '@/utils/request' + +export function queryHisOwner(params) { + return new Promise((resolve, reject) => { + request({ + url: '/owner.queryHisOwner', + method: 'get', + params + }) + .then(response => { + const res = response.data + if (res.code === 0) { + resolve(res) + } else { + reject(new Error(res.msg || '查询业主历史记录失败')) + } + }) + .catch(error => { + reject(error) + }) + }) +} \ No newline at end of file diff --git a/src/api/owner/ownerDetailHisFeeApi.js b/src/api/owner/ownerDetailHisFeeApi.js new file mode 100644 index 0000000..92b50f9 --- /dev/null +++ b/src/api/owner/ownerDetailHisFeeApi.js @@ -0,0 +1,20 @@ +import request from '@/utils/request' + +export function queryFeeDetail(params) { + return new Promise((resolve, reject) => { + request({ + url: '/fee.queryFeeDetail', + method: 'get', + params + }).then(response => { + const res = response.data + if (res.code === 0) { + resolve(res) + } else { + reject(new Error(res.msg || '获取费用明细失败')) + } + }).catch(error => { + reject(error) + }) + }) +} \ No newline at end of file diff --git a/src/api/owner/ownerDetailMemberApi.js b/src/api/owner/ownerDetailMemberApi.js new file mode 100644 index 0000000..eb0745e --- /dev/null +++ b/src/api/owner/ownerDetailMemberApi.js @@ -0,0 +1,20 @@ +import request from '@/utils/request' + +export function queryOwnerMembers(params) { + return new Promise((resolve, reject) => { + request({ + url: '/owner.queryOwnerMembers', + method: 'get', + params + }).then(response => { + const res = response.data + if (res.code == 0) { + resolve(res) + } else { + reject(new Error(res.msg || '获取业主成员列表失败')) + } + }).catch(error => { + reject(error) + }) + }) +} \ No newline at end of file diff --git a/src/api/owner/ownerDetailReceiptApi.js b/src/api/owner/ownerDetailReceiptApi.js new file mode 100644 index 0000000..3eae5ea --- /dev/null +++ b/src/api/owner/ownerDetailReceiptApi.js @@ -0,0 +1,39 @@ +import request from '@/utils/request' + +export function queryFeeReceipt(params) { + return new Promise((resolve, reject) => { + request({ + url: '/feeReceipt/queryFeeReceipt', + method: 'get', + params + }).then(response => { + const res = response.data + if (res.code === 0) { + resolve(res) + } else { + reject(new Error(res.msg || '获取收据列表失败')) + } + }).catch(error => { + reject(error) + }) + }) +} + +export function listFeePrintPage(params) { + return new Promise((resolve, reject) => { + request({ + url: '/feePrintPage.listFeePrintPage', + method: 'get', + params + }).then(response => { + const res = response.data + if (res.code === 0) { + resolve(res) + } else { + reject(new Error(res.msg || '获取打印页面配置失败')) + } + }).catch(error => { + reject(error) + }) + }) +} \ No newline at end of file diff --git a/src/api/owner/ownerDetailRepairApi.js b/src/api/owner/ownerDetailRepairApi.js new file mode 100644 index 0000000..7d6830a --- /dev/null +++ b/src/api/owner/ownerDetailRepairApi.js @@ -0,0 +1,20 @@ +import request from '@/utils/request' + +export function listOwnerRepairs(params) { + return new Promise((resolve, reject) => { + request({ + url: '/ownerRepair.listOwnerRepairs', + method: 'get', + params + }).then(response => { + const res = response.data + if (res.code == 0) { + resolve(res) + } else { + reject(new Error(res.msg || '获取业主报修列表失败')) + } + }).catch(error => { + reject(error) + }) + }) +} \ No newline at end of file diff --git a/src/api/owner/ownerDetailRoomApi.js b/src/api/owner/ownerDetailRoomApi.js new file mode 100644 index 0000000..4d3ca3a --- /dev/null +++ b/src/api/owner/ownerDetailRoomApi.js @@ -0,0 +1,20 @@ +import request from '@/utils/request' + +export function queryRoomsByOwner(params) { + return new Promise((resolve, reject) => { + request({ + url: '/room.queryRoomsByOwner', + method: 'get', + params + }).then(response => { + const res = response.data + if (res.code === 0) { + resolve(res) + } else { + reject(new Error(res.msg || 'Failed to query rooms by owner')) + } + }).catch(error => { + reject(error) + }) + }) +} \ No newline at end of file diff --git a/src/api/owner/ownerDetailRoomFeeApi.js b/src/api/owner/ownerDetailRoomFeeApi.js new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/src/api/owner/ownerDetailRoomFeeApi.js diff --git a/src/api/owner/ownerDetailVisitApi.js b/src/api/owner/ownerDetailVisitApi.js new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/src/api/owner/ownerDetailVisitApi.js diff --git a/src/components/owner/addOwnerMember.vue b/src/components/owner/addOwnerMember.vue new file mode 100644 index 0000000..a888295 --- /dev/null +++ b/src/components/owner/addOwnerMember.vue @@ -0,0 +1,390 @@ + + + + + \ No newline at end of file diff --git a/src/components/owner/addOwnerMemberLang.js b/src/components/owner/addOwnerMemberLang.js new file mode 100644 index 0000000..93d3bbd --- /dev/null +++ b/src/components/owner/addOwnerMemberLang.js @@ -0,0 +1,80 @@ +export default { + en: { + addOwnerMember: { + title: 'Add Member', + personRole: 'Person Role', + name: 'Name', + link: 'Phone', + sex: 'Gender', + concactLink: 'Alternate Phone', + address: 'Address', + idCard: 'ID Card', + remark: 'Remark', + photo: 'Photo', + uploadPhoto: 'Upload Photo', + placeholder: { + personRole: 'Required, please select person role', + name: 'Required, please enter name', + link: 'Required, please enter phone number', + sex: 'Required, please select gender', + concactLink: 'Optional, please enter alternate phone', + address: 'Optional, please enter address', + idCard: 'Optional, please enter ID card', + remark: 'Optional, please enter remark' + }, + role: { + tenant: 'Tenant', + family: 'Family Member', + staff: 'Company Staff', + other: 'Other' + }, + validate: { + nameLength: 'Name length must be between 2 and 64 characters', + phoneFormat: 'Invalid phone number format', + idCardFormat: 'Invalid ID card format', + remarkLength: 'Remark length cannot exceed 200 characters', + photoSize: 'Photo size cannot exceed 2MB' + }, + uploadFailed: 'Photo upload failed' + } + }, + zh: { + addOwnerMember: { + title: '添加成员', + personRole: '人员角色', + name: '客户名称', + link: '联系手机', + sex: '性别', + concactLink: '备用手机', + address: '地址', + idCard: '身份证', + remark: '备注', + photo: '照片', + uploadPhoto: '上传照片', + placeholder: { + personRole: '必填,请选择人员角色', + name: '必填,请填写客户名称', + link: '必填,请填写联系方式', + sex: '必填,请选择性别', + concactLink: '可选,请填写备用手机', + address: '可填,请填写地址', + idCard: '可选,请填写身份证', + remark: '可填,请填写备注' + }, + role: { + tenant: '租客', + family: '家庭成员', + staff: '公司员工', + other: '其他' + }, + validate: { + nameLength: '姓名长度必须在2位至64位', + phoneFormat: '手机号格式错误', + idCardFormat: '身份证格式不对', + remarkLength: '备注长度不能超过200位', + photoSize: '图片大小不能超过2MB' + }, + uploadFailed: '照片上传失败' + } + } +} \ No newline at end of file diff --git a/src/components/owner/editOwnerMember.vue b/src/components/owner/editOwnerMember.vue new file mode 100644 index 0000000..1a4eb6f --- /dev/null +++ b/src/components/owner/editOwnerMember.vue @@ -0,0 +1,408 @@ + + + + + \ No newline at end of file diff --git a/src/components/owner/ownerDetailAccessControl.vue b/src/components/owner/ownerDetailAccessControl.vue new file mode 100644 index 0000000..3f71fa2 --- /dev/null +++ b/src/components/owner/ownerDetailAccessControl.vue @@ -0,0 +1,103 @@ + + + \ No newline at end of file diff --git a/src/components/owner/ownerDetailAccessControlDemo.vue b/src/components/owner/ownerDetailAccessControlDemo.vue new file mode 100644 index 0000000..ab04743 --- /dev/null +++ b/src/components/owner/ownerDetailAccessControlDemo.vue @@ -0,0 +1,18 @@ + + + \ No newline at end of file diff --git a/src/components/owner/ownerDetailAccessControlRecord.vue b/src/components/owner/ownerDetailAccessControlRecord.vue new file mode 100644 index 0000000..afdcc27 --- /dev/null +++ b/src/components/owner/ownerDetailAccessControlRecord.vue @@ -0,0 +1,121 @@ + + + \ No newline at end of file diff --git a/src/components/owner/ownerDetailAccessControlRecordDemo.vue b/src/components/owner/ownerDetailAccessControlRecordDemo.vue new file mode 100644 index 0000000..e4a1781 --- /dev/null +++ b/src/components/owner/ownerDetailAccessControlRecordDemo.vue @@ -0,0 +1,18 @@ + + + \ No newline at end of file diff --git a/src/components/owner/ownerDetailAccount.vue b/src/components/owner/ownerDetailAccount.vue new file mode 100644 index 0000000..d35241e --- /dev/null +++ b/src/components/owner/ownerDetailAccount.vue @@ -0,0 +1,122 @@ + + + + + \ No newline at end of file diff --git a/src/components/owner/ownerDetailAccountDemo.vue b/src/components/owner/ownerDetailAccountDemo.vue new file mode 100644 index 0000000..14e89c5 --- /dev/null +++ b/src/components/owner/ownerDetailAccountDemo.vue @@ -0,0 +1,19 @@ + + + \ No newline at end of file diff --git a/src/components/owner/ownerDetailAccountReceipt.vue b/src/components/owner/ownerDetailAccountReceipt.vue new file mode 100644 index 0000000..e78864a --- /dev/null +++ b/src/components/owner/ownerDetailAccountReceipt.vue @@ -0,0 +1,130 @@ + + + \ No newline at end of file diff --git a/src/components/owner/ownerDetailAccountReceiptDemo.vue b/src/components/owner/ownerDetailAccountReceiptDemo.vue new file mode 100644 index 0000000..c974d98 --- /dev/null +++ b/src/components/owner/ownerDetailAccountReceiptDemo.vue @@ -0,0 +1,18 @@ + + + \ No newline at end of file diff --git a/src/components/owner/ownerDetailAppUser.vue b/src/components/owner/ownerDetailAppUser.vue new file mode 100644 index 0000000..35f463d --- /dev/null +++ b/src/components/owner/ownerDetailAppUser.vue @@ -0,0 +1,126 @@ + + + \ No newline at end of file diff --git a/src/components/owner/ownerDetailAppUserDemo.vue b/src/components/owner/ownerDetailAppUserDemo.vue new file mode 100644 index 0000000..88f43c4 --- /dev/null +++ b/src/components/owner/ownerDetailAppUserDemo.vue @@ -0,0 +1,19 @@ + + + \ No newline at end of file diff --git a/src/components/owner/ownerDetailCar.vue b/src/components/owner/ownerDetailCar.vue new file mode 100644 index 0000000..b4a0951 --- /dev/null +++ b/src/components/owner/ownerDetailCar.vue @@ -0,0 +1,196 @@ + + + + + \ No newline at end of file diff --git a/src/components/owner/ownerDetailCarDemo.vue b/src/components/owner/ownerDetailCarDemo.vue new file mode 100644 index 0000000..740638f --- /dev/null +++ b/src/components/owner/ownerDetailCarDemo.vue @@ -0,0 +1,20 @@ + + + \ No newline at end of file diff --git a/src/components/owner/ownerDetailCarLang.js b/src/components/owner/ownerDetailCarLang.js new file mode 100644 index 0000000..78252f5 --- /dev/null +++ b/src/components/owner/ownerDetailCarLang.js @@ -0,0 +1,40 @@ +export default { + en: { + ownerDetailCar: { + placeholder: { + carNum: 'Please enter license plate number' + }, + table: { + carNum: 'License Plate', + licenseType: 'License Type', + tempCar: 'Temporary Car', + carType: 'Car Type', + color: 'Color', + owner: 'Owner', + parkingSpace: 'Parking Space', + spaceReleased: 'Space released', + validity: 'Validity' + }, + addCar: 'Add Vehicle' + } + }, + zh: { + ownerDetailCar: { + placeholder: { + carNum: '请填写车牌号' + }, + table: { + carNum: '车牌号', + licenseType: '车牌类型', + tempCar: '临时车', + carType: '车辆类型', + color: '颜色', + owner: '业主', + parkingSpace: '车位', + spaceReleased: '车位已释放', + validity: '有效期' + }, + addCar: '添加车辆' + } + } +} \ No newline at end of file diff --git a/src/components/owner/ownerDetailChargeMachineOrder.vue b/src/components/owner/ownerDetailChargeMachineOrder.vue new file mode 100644 index 0000000..d6be601 --- /dev/null +++ b/src/components/owner/ownerDetailChargeMachineOrder.vue @@ -0,0 +1,128 @@ + + + + + \ No newline at end of file diff --git a/src/components/owner/ownerDetailChargeMachineOrderDemo.vue b/src/components/owner/ownerDetailChargeMachineOrderDemo.vue new file mode 100644 index 0000000..2796016 --- /dev/null +++ b/src/components/owner/ownerDetailChargeMachineOrderDemo.vue @@ -0,0 +1,18 @@ + + + \ No newline at end of file diff --git a/src/components/owner/ownerDetailComplaint.vue b/src/components/owner/ownerDetailComplaint.vue new file mode 100644 index 0000000..2e07fa1 --- /dev/null +++ b/src/components/owner/ownerDetailComplaint.vue @@ -0,0 +1,129 @@ + + + \ No newline at end of file diff --git a/src/components/owner/ownerDetailContract.vue b/src/components/owner/ownerDetailContract.vue new file mode 100644 index 0000000..764187b --- /dev/null +++ b/src/components/owner/ownerDetailContract.vue @@ -0,0 +1,75 @@ + + + \ No newline at end of file diff --git a/src/components/owner/ownerDetailContractDemo.vue b/src/components/owner/ownerDetailContractDemo.vue new file mode 100644 index 0000000..c9aa436 --- /dev/null +++ b/src/components/owner/ownerDetailContractDemo.vue @@ -0,0 +1,19 @@ + + + \ No newline at end of file diff --git a/src/components/owner/ownerDetailCoupon.vue b/src/components/owner/ownerDetailCoupon.vue new file mode 100644 index 0000000..dd54654 --- /dev/null +++ b/src/components/owner/ownerDetailCoupon.vue @@ -0,0 +1,87 @@ + + + + + \ No newline at end of file diff --git a/src/components/owner/ownerDetailHis.vue b/src/components/owner/ownerDetailHis.vue new file mode 100644 index 0000000..6cf6b33 --- /dev/null +++ b/src/components/owner/ownerDetailHis.vue @@ -0,0 +1,197 @@ + + + + + \ No newline at end of file diff --git a/src/components/owner/ownerDetailHisFee.vue b/src/components/owner/ownerDetailHisFee.vue new file mode 100644 index 0000000..d8b1d4a --- /dev/null +++ b/src/components/owner/ownerDetailHisFee.vue @@ -0,0 +1,124 @@ + + + \ No newline at end of file diff --git a/src/components/owner/ownerDetailHisFeeDemo.vue b/src/components/owner/ownerDetailHisFeeDemo.vue new file mode 100644 index 0000000..040be15 --- /dev/null +++ b/src/components/owner/ownerDetailHisFeeDemo.vue @@ -0,0 +1,18 @@ + + + \ No newline at end of file diff --git a/src/components/owner/ownerDetailMember.vue b/src/components/owner/ownerDetailMember.vue new file mode 100644 index 0000000..cfe47af --- /dev/null +++ b/src/components/owner/ownerDetailMember.vue @@ -0,0 +1,171 @@ + + + + + \ No newline at end of file diff --git a/src/components/owner/ownerDetailMemberDemo.vue b/src/components/owner/ownerDetailMemberDemo.vue new file mode 100644 index 0000000..e919807 --- /dev/null +++ b/src/components/owner/ownerDetailMemberDemo.vue @@ -0,0 +1,19 @@ + + + \ No newline at end of file diff --git a/src/components/owner/ownerDetailReceipt.vue b/src/components/owner/ownerDetailReceipt.vue new file mode 100644 index 0000000..2b9aef5 --- /dev/null +++ b/src/components/owner/ownerDetailReceipt.vue @@ -0,0 +1,169 @@ + + + \ No newline at end of file diff --git a/src/components/owner/ownerDetailReceiptDemo.vue b/src/components/owner/ownerDetailReceiptDemo.vue new file mode 100644 index 0000000..a6bebac --- /dev/null +++ b/src/components/owner/ownerDetailReceiptDemo.vue @@ -0,0 +1,18 @@ + + + \ No newline at end of file diff --git a/src/components/owner/ownerDetailRepair.vue b/src/components/owner/ownerDetailRepair.vue new file mode 100644 index 0000000..5851562 --- /dev/null +++ b/src/components/owner/ownerDetailRepair.vue @@ -0,0 +1,87 @@ + + + \ No newline at end of file diff --git a/src/components/owner/ownerDetailRepairDemo.vue b/src/components/owner/ownerDetailRepairDemo.vue new file mode 100644 index 0000000..eab77f9 --- /dev/null +++ b/src/components/owner/ownerDetailRepairDemo.vue @@ -0,0 +1,19 @@ + + + \ No newline at end of file diff --git a/src/components/owner/ownerDetailRoom.vue b/src/components/owner/ownerDetailRoom.vue new file mode 100644 index 0000000..ae52ba3 --- /dev/null +++ b/src/components/owner/ownerDetailRoom.vue @@ -0,0 +1,219 @@ + + + + + \ No newline at end of file diff --git a/src/components/owner/ownerDetailRoomDemo.vue b/src/components/owner/ownerDetailRoomDemo.vue new file mode 100644 index 0000000..9349cdf --- /dev/null +++ b/src/components/owner/ownerDetailRoomDemo.vue @@ -0,0 +1,19 @@ + + + \ No newline at end of file diff --git a/src/components/owner/ownerDetailRoomFee.vue b/src/components/owner/ownerDetailRoomFee.vue new file mode 100644 index 0000000..5ed90e2 --- /dev/null +++ b/src/components/owner/ownerDetailRoomFee.vue @@ -0,0 +1,321 @@ + + + \ No newline at end of file diff --git a/src/components/owner/ownerDetailRoomLang.js b/src/components/owner/ownerDetailRoomLang.js new file mode 100644 index 0000000..1b623b4 --- /dev/null +++ b/src/components/owner/ownerDetailRoomLang.js @@ -0,0 +1,46 @@ +export default { + en: { + ownerDetailRoom: { + placeholder: { + roomNum: 'Please enter room number', + searchRoom: 'Please enter room number like 1-1-1' + }, + table: { + roomNum: 'Room Number', + floor: 'Floor', + type: 'Type', + area: 'Built/Indoor Area', + rent: 'Rent', + validity: 'Validity', + state: 'Room Status', + oweFee: 'Room Arrears', + updateDaily: 'Update daily', + exitRoom: 'Check Out', + businessAcceptance: 'Business Acceptance', + oweSubtotal: 'Arrears Subtotal' + } + } + }, + zh: { + ownerDetailRoom: { + placeholder: { + roomNum: '请填写房屋编号', + searchRoom: '请输入房屋编号 楼栋-单元-房屋 如1-1-1' + }, + table: { + roomNum: '房屋编号', + floor: '楼层', + type: '类型', + area: '建筑/室内面积', + rent: '租金', + validity: '有效期', + state: '房屋状态', + oweFee: '房屋欠费', + updateDaily: '按天更新', + exitRoom: '退房', + businessAcceptance: '业务受理', + oweSubtotal: '欠费小计' + } + } + } +} \ No newline at end of file diff --git a/src/components/owner/ownerDetailVisit.vue b/src/components/owner/ownerDetailVisit.vue new file mode 100644 index 0000000..aa0211e --- /dev/null +++ b/src/components/owner/ownerDetailVisit.vue @@ -0,0 +1,155 @@ + + + \ No newline at end of file diff --git a/src/components/system/ownerDetailHis.vue b/src/components/system/ownerDetailHis.vue deleted file mode 100644 index c0cb078..0000000 --- a/src/components/system/ownerDetailHis.vue +++ /dev/null @@ -1,208 +0,0 @@ - - - - - \ No newline at end of file diff --git a/src/i18n/userI18n.js b/src/i18n/userI18n.js index 3bb7085..75fdf9a 100644 --- a/src/i18n/userI18n.js +++ b/src/i18n/userI18n.js @@ -8,6 +8,7 @@ import { messages as editScheduleClassesMessages } from '../views/org/editSchedu import { messages as scheduleClassesPageMessages } from '../views/org/scheduleClassesPageLang' import { messages as workflowManageMessages } from '../views/system/workflowManageLang' import { messages as workflowSettingManageMessages } from '../views/system/workflowSettingManageLang' +import { messages as ownerDetailMessages } from '../views/owner/ownerDetailLang' export const messages = { en: { @@ -21,6 +22,7 @@ export const messages = { ...scheduleClassesPageMessages.en, ...workflowManageMessages.en, ...workflowSettingManageMessages.en, + ...ownerDetailMessages.en, }, zh: { ...staffCommunityMessages.zh, @@ -33,5 +35,6 @@ export const messages = { ...scheduleClassesPageMessages.zh, ...workflowManageMessages.zh, ...workflowSettingManageMessages.zh, + ...ownerDetailMessages.zh, } } \ No newline at end of file diff --git a/src/router/userRouter.js b/src/router/userRouter.js index 92ce3ba..5f0937d 100644 --- a/src/router/userRouter.js +++ b/src/router/userRouter.js @@ -35,8 +35,13 @@ export default [ component: () => import('@/views/org/editScheduleClassesList.vue') }, { - path:'/pages/property/scheduleClassesPage', - name:'/pages/property/scheduleClassesPage', + path: '/pages/property/scheduleClassesPage', + name: '/pages/property/scheduleClassesPage', component: () => import('@/views/org/scheduleClassesPageList.vue') - }, + }, + { + path: '/views/owner/ownerDetail', + name: '/views/owner/ownerDetail', + component: () => import('@/views/owner/ownerDetail.vue') + }, ] \ No newline at end of file diff --git a/src/views/oa/complaintLang.js b/src/views/oa/complaintLang.js index e806bfd..aa7943d 100644 --- a/src/views/oa/complaintLang.js +++ b/src/views/oa/complaintLang.js @@ -28,6 +28,7 @@ export const messages = { phone: 'Phone', status: 'Status', handler: 'Handler', + handlerPhone: 'Handler Phone', createTime: 'Create Time' }, edit: { @@ -106,6 +107,7 @@ export const messages = { phone: '联系电话', status: '状态', handler: '处理人', + handlerPhone: '处理人电话', createTime: '创建时间' }, edit: { diff --git a/src/views/oa/visitManageLang.js b/src/views/oa/visitManageLang.js index 90303f3..3d9bdc4 100644 --- a/src/views/oa/visitManageLang.js +++ b/src/views/oa/visitManageLang.js @@ -18,6 +18,8 @@ export const messages = { table: { visitId: 'Visit ID', name: 'Name', + photo: 'Photo', + gender: 'Gender', phoneNumber: 'Phone Number', roomName: 'Visit Room', @@ -29,6 +31,9 @@ export const messages = { departureTime: 'Departure Time', state: 'Audit Status', msg: 'Audit Remark', + entourage: 'Entourage', + carStatus: 'Car Status', + createTime: 'Create Time' }, gender: { @@ -58,6 +63,8 @@ export const messages = { table: { visitId: '拜访ID', name: '姓名', + photo: '照片', + gender: '性别', phoneNumber: '电话号码', roomName: '拜访房屋', @@ -65,9 +72,12 @@ export const messages = { carNum: '访客车辆', visitType: '访客类型', visitCase: '拜访事由', + entourage: '随行人数', visitTime: '拜访时间', departureTime: '离开时间', state: '审核状态', + carStatus: '车辆状态', + msg: '审核备注', createTime: '创建时间' }, diff --git a/src/views/owner/listOwner.vue b/src/views/owner/listOwner.vue index 39e2b0a..ab09dc3 100644 --- a/src/views/owner/listOwner.vue +++ b/src/views/owner/listOwner.vue @@ -21,8 +21,10 @@ - - + + @@ -275,7 +277,8 @@ export default { const data = await getAttrSpecList({ page: 1, row: 100, - tableName:'building_owner_attr'}) + tableName: 'building_owner_attr' + }) this.listColumns = data .filter(item => item.specShow === 'Y') .map(item => item.specName) @@ -409,11 +412,14 @@ export default { openOwnerDetail(owner) { console.log('Owner detail:', owner) // 实际项目中跳转到详情页面 + this.$router.push(`/views/owner/ownerDetail?ownerId=${owner.ownerId}`) + }, openOwnerDetailMember(owner) { console.log('Owner detail member:', owner) // 实际项目中跳转到成员详情页面 + this.$router.push(`/views/owner/ownerDetail?ownerId=${owner.ownerId}`) } } diff --git a/src/views/owner/ownerDetail.vue b/src/views/owner/ownerDetail.vue new file mode 100644 index 0000000..472ea75 --- /dev/null +++ b/src/views/owner/ownerDetail.vue @@ -0,0 +1,328 @@ + + + + + \ No newline at end of file diff --git a/src/views/owner/ownerDetailLang.js b/src/views/owner/ownerDetailLang.js new file mode 100644 index 0000000..b7f7452 --- /dev/null +++ b/src/views/owner/ownerDetailLang.js @@ -0,0 +1,474 @@ +export const messages = { + en: { + ownerDetail: { + ownerInfo: 'Owner Information', + ownerId: 'Owner ID', + name: 'Name', + gender: 'Gender', + personType: 'Person Type', + personRole: 'Person Role', + idCard: 'ID Card', + contact: 'Contact', + backupPhone: 'Backup Phone', + contactPerson: 'Contact Person', + creator: 'Creator', + remark: 'Remark', + room: 'Room', + car: 'Car', + member: 'Member', + history: 'History', + roomFee: 'Room Fee', + paymentHistory: 'Payment History', + account: 'Account', + coupon: 'Coupon', + ownerBinding: 'Owner Binding', + complaint: 'Complaint', + repair: 'Repair', + visitor: 'Visitor', + contract: 'Contract', + receipt: 'Receipt', + depositReceipt: 'Deposit Receipt', + faceSync: 'Face Sync', + accessRecord: 'Access Record', + chargeOrder: 'Charge Order' + }, + ownerDetailMember: { + placeholder: { + name: 'Please enter member name' + }, + face: 'Face', + name: 'Name', + gender: 'Gender', + role: 'Role', + idCard: 'ID Card', + contact: 'Contact', + address: 'Address' + }, + ownerDetailAccount: { + acctId: 'Account ID', + acctName: 'Account Name', + phone: 'Phone', + acctType: 'Account Type', + amount: 'Amount', + createTime: 'Create Time', + prestore: 'Prestore', + detail: 'Account Detail' + }, + ownerDetailAppUser: { + communityName: 'Community Name', + relatedOwner: 'Related Owner', + idCard: 'ID Card', + phone: 'Phone', + status: 'Status', + applyTime: 'Apply Time', + appType: 'App Type', + unbind: 'Unbind', + resetPwd: 'Reset Password' + }, + ownerDetailRepair: { + repairId: 'Work Order ID', + location: 'Location', + repairType: 'Repair Type', + reporter: 'Reporter', + contact: 'Contact', + appointmentTime: 'Appointment Time', + status: 'Status', + taskProcess: 'Task Process' + }, + ownerDetailContract: { + contractName: 'Contract Name', + contractCode: 'Contract Code', + parentContractCode: 'Parent Contract Code', + contractType: 'Contract Type', + operator: 'Operator', + amount: 'Amount', + startTime: 'Start Time', + endTime: 'End Time', + createTime: 'Create Time', + status: 'Status' + }, + ownerDetailHisFee: { + feeItem: 'Fee Item', + chargeObject: 'Charge Object', + cycle: 'Cycle (months)', + receivableAmount: 'Receivable/Received (yuan)', + paymentMethod: 'Payment Method', + paymentPeriod: 'Payment Period', + paymentTime: 'Payment Time', + cashier: 'Cashier', + status: 'Status', + remark: 'Remark', + operation: 'Operation', + detail: 'Detail', + accountDeduction: 'Account Deduction' + }, + ownerDetailReceipt: { + print: 'Print', + printSmall: 'Print Small', + printApply: 'Print Application', + feeType: 'Fee Type', + owner: 'Owner', + feeItem: 'Fee Item', + chargePeriod: 'Charge Period', + totalAmount: 'Total Amount', + paymentTime: 'Payment Time', + receiptId: 'Receipt ID', + selectPrint: 'Please select receipts to print' + }, + ownerDetailAccountReceipt: { + print: 'Print', + printSmall: 'Print Small', + accountName: 'Account Name', + accountType: 'Account Type', + owner: 'Owner', + prestoreAmount: 'Prestore Amount', + prestoreMethod: 'Prestore Method', + totalAmount: 'Total Amount', + prestoreTime: 'Prestore Time', + receiptId: 'Receipt ID', + selectPrint: 'Please select receipts to print' + }, + ownerDetailAccessControl: { + objectType: 'Object Type', + objectName: 'Object Name', + command: 'Command', + status: 'Status', + description: 'Description', + syncTime: 'Sync Time', + operation: 'Operation', + resync: 'Resync' + }, + ownerDetailAccessControlRecord: { + face: 'Face', + id: 'ID', + deviceName: 'Device Name', + deviceCode: 'Device Code', + userName: 'User Name', + openType: 'Open Type', + phone: 'Phone', + idCard: 'ID Card', + similarity: 'Similarity', + openStatus: 'Open Status', + openTime: 'Open Time', + other: 'Other', + success: 'Success', + failed: 'Failed' + }, + ownerDetailChargeMachineOrder: { + id: 'ID', + name: 'Name', + phone: 'Phone', + charger: 'Charger', + slot: 'Slot', + chargeHours: 'Charge Hours', + byAmount: 'By Amount', + hours: 'hours', + chargeAmount: 'Charge Amount', + startTime: 'Start Time', + endTime: 'End Time', + deductionAccount: 'Deduction Account', + hourPrice: 'Hour Price', + deductionAmount: 'Deduction Amount', + detail: 'Detail', + socketStatus: 'Socket Status', + stopCharge: 'Stop Charge', + description: 'Description' + }, + ownerDetailRoom: { + pleaseEnterRoomNumber: 'Please enter room number', + roomNumber: 'Room Number', + floor: 'Floor', + type: 'Type', + area: 'Area', + rent: 'Rent', + validity: 'Validity', + roomStatus: 'Room Status', + roomArrears: 'Room Arrears', + updateDaily: 'Update daily', + checkOut: 'Check Out', + businessAcceptance: 'Business Acceptance', + arrearsSubtotal: 'Arrears Subtotal', + roomNumberPlaceholder: 'Please enter room number like 1-1-1', + deliverRoom: 'Deliver Room' + }, + ownerDetailCar: { + pleaseEnterCarNumber: 'Please enter license plate number', + addCar: 'Add Vehicle', + carNumber: 'License Plate', + licenseType: 'License Type', + temporaryCar: 'Temporary Vehicle', + carType: 'Vehicle Type', + color: 'Color', + owner: 'Owner', + parkingSpace: 'Parking Space', + parkingSpaceReleased: 'Parking Space Released', + validityPeriod: 'Validity Period' + }, + ownerDetailHis: { + action: 'Action', + operator: 'Operator', + operateTime: 'Operate Time', + name: 'Name', + gender: 'Gender', + male: 'Male', + female: 'Female', + idCard: 'ID Card', + address: 'Address', + add: 'Add', + delete: 'Delete', + modifyNew: 'Modify(New)', + modifyOld: 'Modify(Old)' + }, + ownerDetailCoupon: { + id: 'ID', + couponName: 'Coupon Name', + value: 'Value', + validity: 'Validity', + userName: 'User Name', + phone: 'Phone', + purpose: 'Purpose', + quantity: 'Quantity', + unit: 'pcs', + status: 'Status', + unused: 'Unused', + used: 'Used', + effectiveTime: 'Effective Time' + } + }, + zh: { + ownerDetail: { + ownerInfo: '业主信息', + ownerId: '业主ID', + name: '名称', + gender: '性别', + personType: '人员类型', + personRole: '人员角色', + idCard: '证件号', + contact: '联系方式', + backupPhone: '备用手机', + contactPerson: '联系人', + creator: '创建员工', + remark: '备注', + room: '房屋', + car: '车辆', + member: '成员', + history: '修改记录', + roomFee: '房屋费用', + paymentHistory: '缴费历史', + account: '账户', + coupon: '优惠券', + ownerBinding: '业主绑定', + complaint: '投诉', + repair: '报修', + visitor: '访客', + contract: '合同', + receipt: '补打收据', + depositReceipt: '预存收据', + faceSync: '人脸同步', + accessRecord: '开门记录', + chargeOrder: '充电订单' + }, + ownerDetailMember: { + placeholder: { + name: '请填写成员名称' + }, + face: '人脸', + name: '名称', + gender: '性别', + role: '人员角色', + idCard: '身份证', + contact: '联系方式', + address: '地址' + }, + ownerDetailAccount: { + acctId: '账户编号', + acctName: '账户名称', + phone: '手机号', + acctType: '账户类型', + amount: '账户金额', + createTime: '创建时间', + prestore: '预存', + detail: '账户明细' + }, + ownerDetailAppUser: { + communityName: '小区名称', + relatedOwner: '关联业主', + idCard: '身份证', + phone: '手机号', + status: '状态', + applyTime: '申请时间', + appType: '手机端类型', + unbind: '解绑', + resetPwd: '重置密码' + }, + ownerDetailRepair: { + repairId: '工单编码', + location: '位置', + repairType: '报修类型', + reporter: '报修人', + contact: '联系方式', + appointmentTime: '预约时间', + status: '状态', + taskProcess: '定时任务处理' + }, + ownerDetailContract: { + contractName: '合同名称', + contractCode: '合同编号', + parentContractCode: '父合同编号', + contractType: '合同类型', + operator: '经办人', + amount: '合同金额', + startTime: '开始时间', + endTime: '结束时间', + createTime: '起草时间', + status: '状态' + }, + ownerDetailHisFee: { + feeItem: '费用项', + chargeObject: '收费对象', + cycle: '周期(单位:月)', + receivableAmount: '应收/实收(单位:元)', + paymentMethod: '缴费方式', + paymentPeriod: '缴费起始段', + paymentTime: '缴费时间', + cashier: '收银员', + status: '状态', + remark: '备注', + operation: '操作', + detail: '详情', + accountDeduction: '账户扣款' + }, + ownerDetailReceipt: { + print: '打印', + printSmall: '打印小票', + printApply: '申请单', + feeType: '费用类型', + owner: '业主', + feeItem: '费用项目', + chargePeriod: '收费时间段', + totalAmount: '总金额', + paymentTime: '缴费时间', + receiptId: '收据ID', + selectPrint: '请选择打印收据' + }, + ownerDetailAccountReceipt: { + print: '打印', + printSmall: '打印小票', + accountName: '账户名称', + accountType: '账户类型', + owner: '业主', + prestoreAmount: '预存金额', + prestoreMethod: '预存方式', + totalAmount: '总金额', + prestoreTime: '预存时间', + receiptId: '收据ID', + selectPrint: '请选择打印收据' + }, + ownerDetailAccessControl: { + objectType: '对象类型', + objectName: '对象名称', + command: '指令', + status: '状态', + description: '说明', + syncTime: '同步时间', + operation: '操作', + resync: '重新同步' + }, + ownerDetailAccessControlRecord: { + face: '人脸', + id: '编号', + deviceName: '设备名称', + deviceCode: '设备编码', + userName: '用户名称', + openType: '开门方式', + phone: '手机号', + idCard: '用户身份证', + similarity: '相似度', + openStatus: '开门状态', + openTime: '开门时间', + other: '其他', + success: '开门成功', + failed: '开门失败' + }, + ownerDetailChargeMachineOrder: { + id: '编号', + name: '名称', + phone: '手机号', + charger: '充电桩', + slot: '插槽', + chargeHours: '充电小时', + byAmount: '按量充电', + hours: '小时', + chargeAmount: '充电量', + startTime: '开始时间', + endTime: '结束时间', + deductionAccount: '扣款账户', + hourPrice: '小时电价', + deductionAmount: '扣款金额', + detail: '明细', + socketStatus: '插座状态', + stopCharge: '停止充电', + description: '说明' + }, + ownerDetailRoom: { + pleaseEnterRoomNumber: '请填写房屋编号', + roomNumber: '房屋编号', + floor: '楼层', + type: '类型', + area: '建筑/室内面积', + rent: '租金', + validity: '有效期', + roomStatus: '房屋状态', + roomArrears: '房屋欠费', + updateDaily: '按天更新', + checkOut: '退房', + businessAcceptance: '业务受理', + arrearsSubtotal: '欠费小计', + roomNumberPlaceholder: '请输入房屋编号 楼栋-单元-房屋 如1-1-1', + deliverRoom: '交房' + }, + ownerDetailCar: { + pleaseEnterCarNumber: '请填写车牌号', + addCar: '添加车辆', + carNumber: '车牌号', + licenseType: '车牌类型', + temporaryCar: '临时车', + carType: '车辆类型', + color: '颜色', + owner: '业主', + parkingSpace: '车位', + parkingSpaceReleased: '车位已释放', + validityPeriod: '有效期' + }, + ownerDetailHis: { + action: '动作', + operator: '操作人', + operateTime: '操作时间', + name: '姓名', + gender: '性别', + male: '男', + female: '女', + idCard: '身份证', + address: '家庭住址', + add: '添加', + delete: '删除', + modifyNew: '修改(新)', + modifyOld: '修改(旧)' + }, + ownerDetailCoupon: { + id: '编号', + couponName: '优惠券名称', + value: '面值', + validity: '有效期', + userName: '用户名称', + phone: '手机号', + purpose: '用途', + quantity: '数量', + unit: '张', + status: '状态', + unused: '未使用', + used: '已使用', + effectiveTime: '生效时间' + } + } +} \ No newline at end of file diff --git a/src/views/system/operateDataLogLang.js b/src/views/system/operateDataLogLang.js index 416e74b..c61d196 100644 --- a/src/views/system/operateDataLogLang.js +++ b/src/views/system/operateDataLogLang.js @@ -53,21 +53,6 @@ export const messages = { modifyNew: 'modify(new)', modifyOld: 'modify(old)' }, - ownerDetailHis: { - operate: 'action', - userName: 'operator', - createTime: 'create time', - name: 'name', - sex: 'sex', - male: 'male', - female: 'female', - idCard: 'id card', - address: 'address', - add: 'add', - delete: 'delete', - modifyNew: 'modify(new)', - modifyOld: 'modify(old)' - }, roomDetailHis: { operate: 'action', userName: 'operator', @@ -170,21 +155,6 @@ export const messages = { modifyNew: '修改(新)', modifyOld: '修改(旧)' }, - ownerDetailHis: { - operate: '动作', - userName: '操作人', - createTime: '操作时间', - name: '姓名', - sex: '性别', - male: '男', - female: '女', - idCard: '身份证', - address: '家庭住址', - add: '添加', - delete: '删除', - modifyNew: '修改(新)', - modifyOld: '修改(旧)' - }, roomDetailHis: { operate: '动作', userName: '操作人', diff --git a/src/views/system/operateDataLogList.vue b/src/views/system/operateDataLogList.vue index f3f8af4..5b52b7e 100644 --- a/src/views/system/operateDataLogList.vue +++ b/src/views/system/operateDataLogList.vue @@ -3,43 +3,32 @@
{{ $t('operateDataLog.search.title') }} - + {{ operateDataLogInfo.moreCondition ? $t('common.hide') : $t('common.more') }}
- + - - + - - + - - + @@ -53,44 +42,39 @@ - - + - + - - + - - + - - + - - + - @@ -116,7 +100,7 @@ import { getCommunityId } from '@/api/community/communityApi' import FeeConfigDetailHis from '@/components/system/feeConfigDetailHis' import FeeDetailHis from '@/components/system/feeDetailHis' -import OwnerDetailHis from '@/components/system/ownerDetailHis' +import OwnerDetailHis from '@/components/owner/ownerDetailHis' import RoomDetailHis from '@/components/system/roomDetailHis' import CarDetailHis from '@/components/system/carDetailHis' import ContractDetailChange from '@/components/system/contractDetailChange'