This commit is contained in:
2024-01-31 14:56:48 +08:00
parent 14cbb87311
commit 494e3ee248
97 changed files with 11579 additions and 3858 deletions

View File

@@ -4,7 +4,7 @@ root = true
[*]
charset = utf-8
indent_style = space
indent_size = 2
indent_size = 4
end_of_line = lf
insert_final_newline = true
trim_trailing_whitespace = true

View File

@@ -11,33 +11,33 @@
</template>
<script lang="ts" setup>
import { unref, computed } from 'vue';
import { storeToRefs } from 'pinia';
import { useThemeStore } from '@/store/modules/theme';
import {
MAP_KEY,
MAP_CODE,
LICENSE_CODE,
TAB_KEEP_ALIVE
} from '@/config/setting';
import { useSetDocumentTitle } from '@/utils/document-title-util';
import { useLocale } from '@/i18n/use-locale';
import { unref, computed } from "vue";
import { storeToRefs } from "pinia";
import { useThemeStore } from "@/store/modules/theme";
import {
MAP_KEY,
MAP_CODE,
LICENSE_CODE,
TAB_KEEP_ALIVE
} from "@/config/setting";
import { useSetDocumentTitle } from "@/utils/document-title-util";
import { useLocale } from "@/i18n/use-locale";
const themeStore = useThemeStore();
const { showTabs } = storeToRefs(themeStore);
const themeStore = useThemeStore();
const { showTabs } = storeToRefs(themeStore);
// 恢复主题
themeStore.recoverTheme();
// 恢复主题
themeStore.recoverTheme();
// 切换路由自动更新浏览器页签标题
useSetDocumentTitle();
// 切换路由自动更新浏览器页签标题
useSetDocumentTitle();
// 国际化配置
const { antLocale } = useLocale();
// 国际化配置
const { antLocale } = useLocale();
// 用于内链 iframe 组件获取 KeepAlive
const keepAlive = computed(() => TAB_KEEP_ALIVE && unref(showTabs));
window._AMapSecurityConfig = {
securityJsCode: MAP_CODE
};
// 用于内链 iframe 组件获取 KeepAlive
const keepAlive = computed(() => TAB_KEEP_ALIVE && unref(showTabs));
window._AMapSecurityConfig = {
securityJsCode: MAP_CODE
};
</script>

View File

@@ -75,6 +75,20 @@ export async function updateCustomer(data: Customer) {
return Promise.reject(new Error(res.data.message));
}
/**
* 批量添加客户
*/
export async function addBatchCustomer(data: Customer[]) {
const res = await request.post<ApiResult<unknown>>(
'/tower/tower-customer/batch',
data
);
if (res.data.code === 0) {
return res.data.message;
}
return Promise.reject(new Error(res.data.message));
}
/**
* 批量修改客户
*/

View File

@@ -1,7 +1,7 @@
import type { PageParam } from '@/api';
import type { Role } from '../../role/model';
import type { Menu } from '../../menu/model';
import { Company } from '@/api/system/company/model';
import type { PageParam } from "@/api";
import type { Role } from "../../role/model";
import type { Menu } from "../../menu/model";
import { Company } from "@/api/system/company/model";
/**
* 用户
@@ -37,6 +37,8 @@ export interface User {
introduction?: string;
// 机构id
organizationId?: number;
// 用户等级
userLevel?: number;
// 状态, 0正常, 1冻结
status?: number;
// 性别名称
@@ -98,3 +100,5 @@ export interface UserParam extends PageParam {
roleId?: string;
isStaff?: boolean;
}
export const USER_LEVEL_LIST = ["无权限", "场地主管", "资料员", "经营人员", "生产主管", "审核人", "资产员", "车辆调度员", "维保人员", "财务"];

View File

@@ -1,40 +1,43 @@
import type { PageParam } from '@/api';
import type { PageParam } from "@/api";
import { Dayjs } from "dayjs";
export interface Accessory {
accessoryId?: undefined;
accessoryName?: string;
accessoryNo?: string;
accessoryCategory?: object;
accessoryModel?: string;
accessoryModelMultiple?: string[];
accessorySpecs?: string;
accessoryPrice?: number;
accessoryUnit?: string;
accessoryStock?: string;
companyNo?: string;
companyName?: string;
manufactor?: string;
manufactorNo?: string;
accessoryWeight?: string;
lifeYear?: number;
factoryDate?: string;
scrapDate?: string;
status?: number;
comments?: string;
sortNumber?: number;
userId?: number;
deleted?: number;
tenantId?: number;
createTime?: string;
updateTime?: string;
accessoryId?: undefined;
accessoryName?: string;
accessoryNo?: string;
accessoryCategory?: object;
accessoryModel?: string;
accessoryModelMultiple?: string[];
accessorySpecs?: string;
accessoryPrice?: number;
accessoryNum?: number;
accessoryUnit?: string;
accessoryStock?: string;
companyNo?: string;
companyName?: string;
manufactor?: string;
manufactorNo?: string;
accessoryWeight?: string;
lifeYear?: number;
factoryDate?: string;
scrapDate?: string;
status?: number;
comments?: string;
sortNumber?: number;
userId?: number;
deleted?: number;
tenantId?: number;
createTime?: string;
updateTime?: string;
buyDate?: string | Dayjs;
}
/**
* 搜索条件
*/
export interface AccessoryParam extends PageParam {
accessoryId?: number;
accessoryName?: string;
status?: number;
keywords?: string;
accessoryId?: number;
accessoryName?: string;
status?: number;
keywords?: string;
}

View File

@@ -17,11 +17,11 @@ export interface Contract {
// 合同编号
contactNumber?: string;
// 签订日期
signDate?: string;
signDate?: any;
// 开始日期
startDate?: string;
startDate?: any;
// 截止日期
endDate?: string;
endDate?: any;
// 合同金额
contractAmount?: number;
// 合同约定金额
@@ -31,13 +31,20 @@ export interface Contract {
// 是否自动结算
autoSettle?: number;
// 结算方式
settleMethod?: number;
settleMethod?: any;
// 跨月结算日期
extendMonthDate?: number;
userId?: any;
projectName?: any;
customerName?: any;
companyName?: any;
totalInvoicingAmount?: any;
totalIncomeAmount?: any;
totalReceivableAmount?: any;
totalSettleAmount?: any;
payRate?: any;
remark?: string;
fileList?: string;
}
@@ -46,6 +53,7 @@ export interface Contract {
*/
export interface ContractParam extends PageParam {
contactNumber?: string;
projectName?: string;
createTimeStart?: string;
createTimeEnd?: string;
betweenTime?: any;

View File

@@ -8,9 +8,15 @@ export interface ContractEquipment {
// 合同id
contractId: any;
// 设备名
equipmentId: any;
equipmentName: string;
name?: string;
model?: string;
// 规格
equipmentModel: string;
equipmentModel?: string;
factoryNo?: string;
equipmentNo?: string;
filingNo?: string;
// 数量
num: any;
// 租期
@@ -35,5 +41,5 @@ export interface ContractEquipment {
* 合同搜索条件
*/
export interface ContractEquipmentParam extends PageParam {
contactId?: string;
contractId?: string;
}

View File

@@ -20,5 +20,5 @@ export interface ContractFile {
* 合同搜索条件
*/
export interface ContractFileParam extends PageParam {
contactId?: string;
contractId?: string;
}

View File

@@ -5,6 +5,7 @@ import type { PageParam } from '@/api';
*/
export interface ContractSettleEquipment {
contractSettleId?: any;
equipmentId: any;
// 合同id
contractId: any;
// 设备名
@@ -13,6 +14,8 @@ export interface ContractSettleEquipment {
equipmentModel: string;
// 进场编号
factoryNo: any;
// 备案号
filingNo: any;
// 自编号
equipmentNo: any;
// 租期
@@ -25,10 +28,15 @@ export interface ContractSettleEquipment {
workerAmount: any;
// 其他费用
otherAmount: any;
// 其他费用计算模式
otherAmountCalMode: any;
// 预埋费
preBuryAmount: any;
// 备注
remark?: any;
userId?: any;
}
/**

View File

@@ -4,6 +4,19 @@ import type {
TowerEquipment,
TowerEquipmentParam
} from '@/api/tower/equipment/model';
/**
* 设备数据
*/
export async function towerEquipmentData() {
const res = await request.get(
'/tower/tower-equipment/data'
);
if (res.data.code === 0) {
return res.data.data;
}
return Promise.reject(new Error(res.data.message));
}
/**
* 分页查询设备
*/
@@ -134,3 +147,16 @@ export async function removeBatchTowerEquipment(data: (number | undefined)[]) {
}
return Promise.reject(new Error(res.data.message));
}
export async function towerEquipmentQr(params: TowerEquipmentParam) {
const res = await request.get<ApiResult<unknown>>(
'/tower/tower-equipment/qr',
{
params
}
);
if (res.data.code === 0) {
return res.data.message;
}
return Promise.reject(new Error(res.data.message));
}

View File

@@ -1,55 +1,61 @@
import type { PageParam } from '@/api';
import type { PageParam } from "@/api";
import { Project } from "@/api/tower/project/model";
export interface TowerEquipment {
equipmentId?: number;
name?: string;
model?: string;
equipmentNo?: string;
factoryNo?: string;
factoryDate?: string;
manufactor?: string;
lifeYear?: number;
surplusYear?: number;
scrapDate?: string;
beianNo?: string;
licenceNo?: string;
company?: string;
organization?: string;
warehouse?: string;
source?: string;
filingNo?: string;
machineNo?: string;
maxLiftingHeight?: string;
armLength?: string;
isOutOrg?: boolean;
buyDate?: string;
currentLocation?: string;
designHeight?: number;
height?: number;
ratedLoad?: string;
files?: string;
file1?: string;
file2?: string;
file3?: string;
file4?: string;
file5?: string;
file6?: string;
file7?: string;
users?: string;
status?: number;
comments?: string;
userId?: number;
deleted?: number;
tenantId?: number;
createTime?: number;
maxRatedLoad?: string;
equipmentId?: number;
name?: string;
model?: string;
equipmentNo?: string;
factoryNo?: string;
factoryDate?: string;
manufactor?: string;
lifeYear?: any;
surplusYear?: number;
scrapDate?: string;
beianNo?: string;
licenceNo?: string;
company?: string;
organization?: string;
warehouse?: string;
source?: string;
filingNo?: string;
machineNo?: string;
maxLiftingHeight?: string;
armLength?: string;
isOutOrg?: boolean;
buyDate?: string;
currentLocation?: string;
designHeight?: number;
height?: number;
ratedLoad?: string;
files?: string;
file1?: string;
file2?: string;
file3?: string;
file4?: string;
file5?: string;
file6?: string;
file7?: string;
users?: string;
status?: number;
comments?: string;
userId?: number;
deleted?: number;
tenantId?: number;
createTime?: number;
maxRatedLoad?: string;
securityStatus?: string;
projectName?: string;
competentDepartment?: string;
projectList?: Project[];
}
/**
* 搜索条件
*/
export interface TowerEquipmentParam extends PageParam {
equipmentId?: number;
name?: string;
status?: number;
equipmentId?: number;
name?: string;
status?: number;
yearFilter?: number;
}

View File

@@ -9,6 +9,8 @@ export interface TowerFall {
factory?: string;
factoryDate?: string;
discardDate?: string;
checkDate?: string;
file1?: string;
file2?: string;
file3?: string;

View File

@@ -0,0 +1,129 @@
import request from '@/utils/request';
import type {ApiResult, PageResult} from '@/api';
import type {FinalSettle, FinalSettleParam} from './model';
/**
* 分页查询结算
*/
export async function pageFinalSettle(params: FinalSettleParam) {
const res = await request.get<ApiResult<PageResult<FinalSettle>>>(
'/tower/tower-contract-final-settle/page',
{
params
}
);
if (res.data.code === 0) {
return res.data.data;
}
return Promise.reject(new Error(res.data.message));
}
/**
* 查询合同列表
*/
export async function listFinalSettle(params?: FinalSettleParam) {
const res = await request.get<ApiResult<FinalSettle[]>>(
'/tower/tower-contract-final-settle',
{
params
}
);
if (res.data.code === 0 && res.data.data) {
return res.data.data;
}
return Promise.reject(new Error(res.data.message));
}
/**
* 根据id查询合同
*/
export async function getFinalSettle(id: number) {
const res = await request.get<ApiResult<FinalSettle>>(
'/tower/tower-contract-final-settle/' + id
);
if (res.data.code === 0 && res.data.data) {
return res.data.data;
}
return Promise.reject(new Error(res.data.message));
}
/**
* 添加合同
*/
export async function addFinalSettle(data: FinalSettle) {
const res = await request.post<ApiResult<unknown>>(
'/tower/tower-contract-final-settle',
data
);
if (res.data.code === 0) {
return res.data;
}
return Promise.reject(new Error(res.data.message));
}
/**
* 修改合同
*/
export async function updateFinalSettle(data: FinalSettle) {
const res = await request.put<ApiResult<unknown>>(
'/tower/tower-contract-final-settle',
data
);
if (res.data.code === 0) {
return res.data;
}
return Promise.reject(new Error(res.data.message));
}
/**
* 批量修改合同
*/
export async function updateBatchFinalSettle(data: FinalSettle[]) {
const res = await request.put<ApiResult<unknown>>(
'/tower/tower-contract-final-settle/batch',
data
);
if (res.data.code === 0) {
return res.data.message;
}
return Promise.reject(new Error(res.data.message));
}
export async function addBatchFinalSettle(data: FinalSettle[]) {
const res = await request.post<ApiResult<unknown>>(
'/tower/tower-contract-final-settle/batch',
data
);
if (res.data.code === 0) {
return res.data.message;
}
return Promise.reject(new Error(res.data.message));
}
/**
* 删除合同
*/
export async function removeFinalSettle(id?: number) {
const res = await request.delete<ApiResult<unknown>>(
'/tower/tower-contract-final-settle/' + id
);
if (res.data.code === 0) {
return res.data.message;
}
return Promise.reject(new Error(res.data.message));
}
/**
* 批量删除合同
*/
export async function removeBatchFinalSettle(data: (number | undefined)[]) {
const res = await request.delete<ApiResult<unknown>>(
'/tower/tower-contract-final-settle/batch',
{
data
}
);
if (res.data.code === 0) {
return res.data.message;
}
return Promise.reject(new Error(res.data.message));
}

View File

@@ -0,0 +1,31 @@
import type { PageParam } from '@/api';
/**
* 合同
*/
export interface FinalSettle {
contractFinalSettleId?: any;
contractId?: any;
settleCompanyId?: any;
fileList?: any;
signName?: any;
signDate?: any;
remark?: any;
userId?: any;
settleCompanyName?: any;
contractNumber?: any;
companyName?: any;
customerName?: any;
projectName?: any;
totalSettleAmount?: any;
totalInvoicingAmount?: any;
totalIncomeAmount?: any;
}
/**
* 合同搜索条件
*/
export interface FinalSettleParam extends PageParam {
projectName?: string;
contractNo?: string;
}

View File

@@ -0,0 +1,129 @@
import request from '@/utils/request';
import type {ApiResult, PageResult} from '@/api';
import type {FinalSettleLost, FinalSettleLostParam} from './model';
/**
* 分页查询结算
*/
export async function pageFinalSettleLost(params: FinalSettleLostParam) {
const res = await request.get<ApiResult<PageResult<FinalSettleLost>>>(
'/tower/tower-contract-final-settle-lost/page',
{
params
}
);
if (res.data.code === 0) {
return res.data.data;
}
return Promise.reject(new Error(res.data.message));
}
/**
* 查询合同列表
*/
export async function listFinalSettleLost(params?: FinalSettleLostParam) {
const res = await request.get<ApiResult<FinalSettleLost[]>>(
'/tower/tower-contract-final-settle-lost',
{
params
}
);
if (res.data.code === 0 && res.data.data) {
return res.data.data;
}
return Promise.reject(new Error(res.data.message));
}
/**
* 根据id查询合同
*/
export async function getFinalSettleLost(id: number) {
const res = await request.get<ApiResult<FinalSettleLost>>(
'/tower/tower-contract-final-settle-lost/' + id
);
if (res.data.code === 0 && res.data.data) {
return res.data.data;
}
return Promise.reject(new Error(res.data.message));
}
/**
* 添加合同
*/
export async function addFinalSettleLost(data: FinalSettleLost) {
const res = await request.post<ApiResult<unknown>>(
'/tower/tower-contract-final-settle-lost',
data
);
if (res.data.code === 0) {
return res.data;
}
return Promise.reject(new Error(res.data.message));
}
/**
* 修改合同
*/
export async function updateFinalSettleLost(data: FinalSettleLost) {
const res = await request.put<ApiResult<unknown>>(
'/tower/tower-contract-final-settle-lost',
data
);
if (res.data.code === 0) {
return res.data;
}
return Promise.reject(new Error(res.data.message));
}
/**
* 批量修改合同
*/
export async function updateBatchFinalSettleLost(data: FinalSettleLost[]) {
const res = await request.put<ApiResult<unknown>>(
'/tower/tower-contract-final-settle-lost/batch',
data
);
if (res.data.code === 0) {
return res.data.message;
}
return Promise.reject(new Error(res.data.message));
}
export async function addBatchFinalSettleLost(data: FinalSettleLost[]) {
const res = await request.post<ApiResult<unknown>>(
'/tower/tower-contract-final-settle-lost/batch',
data
);
if (res.data.code === 0) {
return res.data.message;
}
return Promise.reject(new Error(res.data.message));
}
/**
* 删除合同
*/
export async function removeFinalSettleLost(id?: number) {
const res = await request.delete<ApiResult<unknown>>(
'/tower/tower-contract-final-settle-lost/' + id
);
if (res.data.code === 0) {
return res.data.message;
}
return Promise.reject(new Error(res.data.message));
}
/**
* 批量删除合同
*/
export async function removeBatchFinalSettleLost(data: (number | undefined)[]) {
const res = await request.delete<ApiResult<unknown>>(
'/tower/tower-contract-final-settle-lost/batch',
{
data
}
);
if (res.data.code === 0) {
return res.data.message;
}
return Promise.reject(new Error(res.data.message));
}

View File

@@ -0,0 +1,22 @@
import type { PageParam } from '@/api';
/**
* 合同
*/
export interface FinalSettleLost {
finalSettleLostId?: any;
finalSettleId?: any;
itemId?: any;
itemName?: any;
amount?: any;
num?: any;
total?: any;
userId?: any;
}
/**
* 合同搜索条件
*/
export interface FinalSettleLostParam extends PageParam {
finalSettleId?: string;
}

View File

@@ -0,0 +1,129 @@
import request from '@/utils/request';
import type {ApiResult, PageResult} from '@/api';
import type {Income, IncomeParam} from './model';
/**
* 分页查询结算
*/
export async function pageIncome(params: IncomeParam) {
const res = await request.get<ApiResult<PageResult<Income>>>(
'/tower/tower-income/page',
{
params
}
);
if (res.data.code === 0) {
return res.data.data;
}
return Promise.reject(new Error(res.data.message));
}
/**
* 查询合同列表
*/
export async function listIncome(params?: IncomeParam) {
const res = await request.get<ApiResult<Income[]>>(
'/tower/tower-income',
{
params
}
);
if (res.data.code === 0 && res.data.data) {
return res.data.data;
}
return Promise.reject(new Error(res.data.message));
}
/**
* 根据id查询合同
*/
export async function getIncome(id: number) {
const res = await request.get<ApiResult<Income>>(
'/tower/tower-income/' + id
);
if (res.data.code === 0 && res.data.data) {
return res.data.data;
}
return Promise.reject(new Error(res.data.message));
}
/**
* 添加合同
*/
export async function addIncome(data: Income) {
const res = await request.post<ApiResult<unknown>>(
'/tower/tower-income',
data
);
if (res.data.code === 0) {
return res.data;
}
return Promise.reject(new Error(res.data.message));
}
/**
* 修改合同
*/
export async function updateIncome(data: Income) {
const res = await request.put<ApiResult<unknown>>(
'/tower/tower-income',
data
);
if (res.data.code === 0) {
return res.data;
}
return Promise.reject(new Error(res.data.message));
}
/**
* 批量修改合同
*/
export async function updateBatchIncome(data: Income[]) {
const res = await request.put<ApiResult<unknown>>(
'/tower/tower-income/batch',
data
);
if (res.data.code === 0) {
return res.data.message;
}
return Promise.reject(new Error(res.data.message));
}
export async function addBatchIncome(data: Income[]) {
const res = await request.post<ApiResult<unknown>>(
'/tower/tower-income/batch',
data
);
if (res.data.code === 0) {
return res.data.message;
}
return Promise.reject(new Error(res.data.message));
}
/**
* 删除合同
*/
export async function removeIncome(id?: number) {
const res = await request.delete<ApiResult<unknown>>(
'/tower/tower-income/' + id
);
if (res.data.code === 0) {
return res.data.message;
}
return Promise.reject(new Error(res.data.message));
}
/**
* 批量删除合同
*/
export async function removeBatchIncome(data: (number | undefined)[]) {
const res = await request.delete<ApiResult<unknown>>(
'/tower/tower-income/batch',
{
data
}
);
if (res.data.code === 0) {
return res.data.message;
}
return Promise.reject(new Error(res.data.message));
}

View File

@@ -0,0 +1,43 @@
import type { PageParam } from '@/api';
/**
* 合同
*/
export interface Income {
incomeId?: any;
contractId?: any;
incomeNo?: any;
incomeDate?: any;
incomeCompanyId?: any;
payCompanyId?: any;
payCompanyName?: any;
amount?: any;
companyName?: any;
totalIncomeAmount?: any;
totalInvoicingAmount?: any;
incomeType?: any;
expectIncomeDate?: any;
expectIncomeAmount?: any;
incomeMethod?: any;
invoicingNo?: any;
fileList?: any;
remark?: any;
status?: any;
userId?: any;
signName?: any;
signDate?: any;
contractNumber?: any;
projectName?: any;
incomeCompanyName?: any;
customerName?: any;
}
/**
* 合同搜索条件
*/
export interface IncomeParam extends PageParam {
projectName?: string;
contractNo?: string;
}
export const INCOME_STATUS_LIST = ['已收款', '已作废']

View File

@@ -0,0 +1,129 @@
import request from '@/utils/request';
import type {ApiResult, PageResult} from '@/api';
import type {IncomeEquipment, IncomeEquipmentParam} from './model';
/**
* 分页查询结算
*/
export async function pageIncomeEquipment(params: IncomeEquipmentParam) {
const res = await request.get<ApiResult<PageResult<IncomeEquipment>>>(
'/tower/tower-income-equipment/page',
{
params
}
);
if (res.data.code === 0) {
return res.data.data;
}
return Promise.reject(new Error(res.data.message));
}
/**
* 查询合同列表
*/
export async function listIncomeEquipment(params?: IncomeEquipmentParam) {
const res = await request.get<ApiResult<IncomeEquipment[]>>(
'/tower/tower-income-equipment',
{
params
}
);
if (res.data.code === 0 && res.data.data) {
return res.data.data;
}
return Promise.reject(new Error(res.data.message));
}
/**
* 根据id查询合同
*/
export async function getIncomeEquipment(id: number) {
const res = await request.get<ApiResult<IncomeEquipment>>(
'/tower/tower-income-equipment/' + id
);
if (res.data.code === 0 && res.data.data) {
return res.data.data;
}
return Promise.reject(new Error(res.data.message));
}
/**
* 添加合同
*/
export async function addIncomeEquipment(data: IncomeEquipment) {
const res = await request.post<ApiResult<unknown>>(
'/tower/tower-income-equipment',
data
);
if (res.data.code === 0) {
return res.data;
}
return Promise.reject(new Error(res.data.message));
}
/**
* 修改合同
*/
export async function updateIncomeEquipment(data: IncomeEquipment) {
const res = await request.put<ApiResult<unknown>>(
'/tower/tower-income-equipment',
data
);
if (res.data.code === 0) {
return res.data;
}
return Promise.reject(new Error(res.data.message));
}
/**
* 批量修改合同
*/
export async function updateBatchIncomeEquipment(data: IncomeEquipment[]) {
const res = await request.put<ApiResult<unknown>>(
'/tower/tower-income-equipment/batch',
data
);
if (res.data.code === 0) {
return res.data.message;
}
return Promise.reject(new Error(res.data.message));
}
export async function addBatchIncomeEquipment(data: IncomeEquipment[]) {
const res = await request.post<ApiResult<unknown>>(
'/tower/tower-income-equipment/batch',
data
);
if (res.data.code === 0) {
return res.data.message;
}
return Promise.reject(new Error(res.data.message));
}
/**
* 删除合同
*/
export async function removeIncomeEquipment(id?: number) {
const res = await request.delete<ApiResult<unknown>>(
'/tower/tower-income-equipment/' + id
);
if (res.data.code === 0) {
return res.data.message;
}
return Promise.reject(new Error(res.data.message));
}
/**
* 批量删除合同
*/
export async function removeBatchIncomeEquipment(data: (number | undefined)[]) {
const res = await request.delete<ApiResult<unknown>>(
'/tower/tower-income-equipment/batch',
{
data
}
);
if (res.data.code === 0) {
return res.data.message;
}
return Promise.reject(new Error(res.data.message));
}

View File

@@ -0,0 +1,30 @@
import type { PageParam } from '@/api';
/**
* 合同
*/
export interface IncomeEquipment {
incomeEquipmentId?: any;
incomeId?: any;
equipmentId?: any;
equipmentName?: any;
equipmentModel?: any;
// 进场编号
factoryNo?: any;
// 自编号
equipmentNo?: any;
filingNo?: string;
rentAmount?: string;
shareAmount?: any;
userId?: any;
}
/**
* 合同搜索条件
*/
export interface IncomeEquipmentParam extends PageParam {
projectName?: string;
contractNo?: string;
incomeId?: string;
}

View File

@@ -0,0 +1,129 @@
import request from '@/utils/request';
import type {ApiResult, PageResult} from '@/api';
import type {Invoicing, InvoicingParam} from './model';
/**
* 分页查询结算
*/
export async function pageInvoicing(params: InvoicingParam) {
const res = await request.get<ApiResult<PageResult<Invoicing>>>(
'/tower/tower-invoicing/page',
{
params
}
);
if (res.data.code === 0) {
return res.data.data;
}
return Promise.reject(new Error(res.data.message));
}
/**
* 查询合同列表
*/
export async function listInvoicing(params?: InvoicingParam) {
const res = await request.get<ApiResult<Invoicing[]>>(
'/tower/tower-invoicing',
{
params
}
);
if (res.data.code === 0 && res.data.data) {
return res.data.data;
}
return Promise.reject(new Error(res.data.message));
}
/**
* 根据id查询合同
*/
export async function getInvoicing(id: number) {
const res = await request.get<ApiResult<Invoicing>>(
'/tower/tower-invoicing/' + id
);
if (res.data.code === 0 && res.data.data) {
return res.data.data;
}
return Promise.reject(new Error(res.data.message));
}
/**
* 添加合同
*/
export async function addInvoicing(data: Invoicing) {
const res = await request.post<ApiResult<unknown>>(
'/tower/tower-invoicing',
data
);
if (res.data.code === 0) {
return res.data;
}
return Promise.reject(new Error(res.data.message));
}
/**
* 修改合同
*/
export async function updateInvoicing(data: Invoicing) {
const res = await request.put<ApiResult<unknown>>(
'/tower/tower-invoicing',
data
);
if (res.data.code === 0) {
return res.data;
}
return Promise.reject(new Error(res.data.message));
}
/**
* 批量修改合同
*/
export async function updateBatchInvoicing(data: Invoicing[]) {
const res = await request.put<ApiResult<unknown>>(
'/tower/tower-invoicing/batch',
data
);
if (res.data.code === 0) {
return res.data.message;
}
return Promise.reject(new Error(res.data.message));
}
export async function addBatchInvoicing(data: Invoicing[]) {
const res = await request.post<ApiResult<unknown>>(
'/tower/tower-invoicing/batch',
data
);
if (res.data.code === 0) {
return res.data.message;
}
return Promise.reject(new Error(res.data.message));
}
/**
* 删除合同
*/
export async function removeInvoicing(id?: number) {
const res = await request.delete<ApiResult<unknown>>(
'/tower/tower-invoicing/' + id
);
if (res.data.code === 0) {
return res.data.message;
}
return Promise.reject(new Error(res.data.message));
}
/**
* 批量删除合同
*/
export async function removeBatchInvoicing(data: (number | undefined)[]) {
const res = await request.delete<ApiResult<unknown>>(
'/tower/tower-invoicing/batch',
{
data
}
);
if (res.data.code === 0) {
return res.data.message;
}
return Promise.reject(new Error(res.data.message));
}

View File

@@ -0,0 +1,35 @@
import type { PageParam } from '@/api';
/**
* 合同
*/
export interface Invoicing {
invoicingId?: any;
contractId?: any;
invoicingDate?: any;
invoicingCompany?: any;
requestName?: any;
signName?: any;
invoicingAmount?: any;
invoicingNo?: any;
fileList?: any;
remark?: any;
status?: any;
userId?: any;
contractNumber?: any;
projectName?: any;
signDate?: any;
companyName?: any;
customerName?: any;
totalInvoicingAmount?: any;
}
/**
* 合同搜索条件
*/
export interface InvoicingParam extends PageParam {
projectName?: string;
contractNo?: string;
}
export const INVOICING_STATUS_LIST = ['已开票', '已作废']

View File

@@ -0,0 +1,129 @@
import request from '@/utils/request';
import type {ApiResult, PageResult} from '@/api';
import type {InvoicingSettle, InvoicingSettleParam} from './model';
/**
* 分页查询结算
*/
export async function pageInvoicingSettle(params: InvoicingSettleParam) {
const res = await request.get<ApiResult<PageResult<InvoicingSettle>>>(
'/tower/tower-invoicing-settle/page',
{
params
}
);
if (res.data.code === 0) {
return res.data.data;
}
return Promise.reject(new Error(res.data.message));
}
/**
* 查询合同列表
*/
export async function listInvoicingSettle(params?: InvoicingSettleParam) {
const res = await request.get<ApiResult<InvoicingSettle[]>>(
'/tower/tower-invoicing-settle',
{
params
}
);
if (res.data.code === 0 && res.data.data) {
return res.data.data;
}
return Promise.reject(new Error(res.data.message));
}
/**
* 根据id查询合同
*/
export async function getInvoicingSettle(id: number) {
const res = await request.get<ApiResult<InvoicingSettle>>(
'/tower/tower-invoicing-settle/' + id
);
if (res.data.code === 0 && res.data.data) {
return res.data.data;
}
return Promise.reject(new Error(res.data.message));
}
/**
* 添加合同
*/
export async function addInvoicingSettle(data: InvoicingSettle) {
const res = await request.post<ApiResult<unknown>>(
'/tower/tower-invoicing-settle',
data
);
if (res.data.code === 0) {
return res.data;
}
return Promise.reject(new Error(res.data.message));
}
/**
* 修改合同
*/
export async function updateInvoicingSettle(data: InvoicingSettle) {
const res = await request.put<ApiResult<unknown>>(
'/tower/tower-invoicing-settle',
data
);
if (res.data.code === 0) {
return res.data;
}
return Promise.reject(new Error(res.data.message));
}
/**
* 批量修改合同
*/
export async function updateBatchInvoicingSettle(data: InvoicingSettle[]) {
const res = await request.put<ApiResult<unknown>>(
'/tower/tower-invoicing-settle/batch',
data
);
if (res.data.code === 0) {
return res.data.message;
}
return Promise.reject(new Error(res.data.message));
}
export async function addBatchInvoicingSettle(data: InvoicingSettle[]) {
const res = await request.post<ApiResult<unknown>>(
'/tower/tower-invoicing-settle/batch',
data
);
if (res.data.code === 0) {
return res.data.message;
}
return Promise.reject(new Error(res.data.message));
}
/**
* 删除合同
*/
export async function removeInvoicingSettle(id?: number) {
const res = await request.delete<ApiResult<unknown>>(
'/tower/tower-InvoicingSettle/' + id
);
if (res.data.code === 0) {
return res.data.message;
}
return Promise.reject(new Error(res.data.message));
}
/**
* 批量删除合同
*/
export async function removeBatchInvoicingSettle(data: (number | undefined)[]) {
const res = await request.delete<ApiResult<unknown>>(
'/tower/tower-invoicing-settle/batch',
{
data
}
);
if (res.data.code === 0) {
return res.data.message;
}
return Promise.reject(new Error(res.data.message));
}

View File

@@ -0,0 +1,21 @@
import type { PageParam } from '@/api';
/**
* 合同
*/
export interface InvoicingSettle {
invoicingSettleId?: any;
invoicingId?: any;
settleId?: any;
shareAmount?: any;
settleNumber?: any;
startDate?: any;
settleAmount?: any;
}
/**
* 合同搜索条件
*/
export interface InvoicingSettleParam extends PageParam {
invoicingId?: string;
}

View File

@@ -0,0 +1,129 @@
import request from '@/utils/request';
import type {ApiResult, PageResult} from '@/api';
import type {Lending, LendingParam} from './model';
/**
* 分页查询结算
*/
export async function pageLending(params: LendingParam) {
const res = await request.get<ApiResult<PageResult<Lending>>>(
'/tower/tower-lending/page',
{
params
}
);
if (res.data.code === 0) {
return res.data.data;
}
return Promise.reject(new Error(res.data.message));
}
/**
* 查询合同列表
*/
export async function listLending(params?: LendingParam) {
const res = await request.get<ApiResult<Lending[]>>(
'/tower/tower-lending',
{
params
}
);
if (res.data.code === 0 && res.data.data) {
return res.data.data;
}
return Promise.reject(new Error(res.data.message));
}
/**
* 根据id查询合同
*/
export async function getLending(id: number) {
const res = await request.get<ApiResult<Lending>>(
'/tower/tower-lending/' + id
);
if (res.data.code === 0 && res.data.data) {
return res.data.data;
}
return Promise.reject(new Error(res.data.message));
}
/**
* 添加合同
*/
export async function addLending(data: Lending) {
const res = await request.post<ApiResult<unknown>>(
'/tower/tower-lending',
data
);
if (res.data.code === 0) {
return res.data;
}
return Promise.reject(new Error(res.data.message));
}
/**
* 修改合同
*/
export async function updateLending(data: Lending) {
const res = await request.put<ApiResult<unknown>>(
'/tower/tower-lending',
data
);
if (res.data.code === 0) {
return res.data;
}
return Promise.reject(new Error(res.data.message));
}
/**
* 批量修改合同
*/
export async function updateBatchLending(data: Lending[]) {
const res = await request.put<ApiResult<unknown>>(
'/tower/tower-lending/batch',
data
);
if (res.data.code === 0) {
return res.data.message;
}
return Promise.reject(new Error(res.data.message));
}
export async function addBatchLending(data: Lending[]) {
const res = await request.post<ApiResult<unknown>>(
'/tower/tower-lending/batch',
data
);
if (res.data.code === 0) {
return res.data.message;
}
return Promise.reject(new Error(res.data.message));
}
/**
* 删除合同
*/
export async function removeLending(id?: number) {
const res = await request.delete<ApiResult<unknown>>(
'/tower/tower-lending/' + id
);
if (res.data.code === 0) {
return res.data.message;
}
return Promise.reject(new Error(res.data.message));
}
/**
* 批量删除合同
*/
export async function removeBatchLending(data: (number | undefined)[]) {
const res = await request.delete<ApiResult<unknown>>(
'/tower/tower-lending/batch',
{
data
}
);
if (res.data.code === 0) {
return res.data.message;
}
return Promise.reject(new Error(res.data.message));
}

View File

@@ -0,0 +1,28 @@
import type { PageParam } from '@/api';
/**
* 合同
*/
export interface Lending {
lendingId?: any;
contractId?: any;
contactNumber?: any;
signDate?: any;
projectName?: any;
customerName?: any;
companyName?: any;
propertyCompany?: any;
settleDate?: any;
settleAmount?: any;
fileList?: any;
remark?: any;
userId?: any;
}
/**
* 合同搜索条件
*/
export interface LendingParam extends PageParam {
projectName?: string;
contractNo?: string;
}

View File

@@ -0,0 +1,129 @@
import request from '@/utils/request';
import type {ApiResult, PageResult} from '@/api';
import type {LendingSettle, LendingSettleParam} from './model';
/**
* 分页查询结算
*/
export async function pageLendingSettle(params: LendingSettleParam) {
const res = await request.get<ApiResult<PageResult<LendingSettle>>>(
'/tower/tower-lending-settle/page',
{
params
}
);
if (res.data.code === 0) {
return res.data.data;
}
return Promise.reject(new Error(res.data.message));
}
/**
* 查询合同列表
*/
export async function listLendingSettle(params?: LendingSettleParam) {
const res = await request.get<ApiResult<LendingSettle[]>>(
'/tower/tower-lending-settle',
{
params
}
);
if (res.data.code === 0 && res.data.data) {
return res.data.data;
}
return Promise.reject(new Error(res.data.message));
}
/**
* 根据id查询合同
*/
export async function getLendingSettle(id: number) {
const res = await request.get<ApiResult<LendingSettle>>(
'/tower/tower-lending-settle/' + id
);
if (res.data.code === 0 && res.data.data) {
return res.data.data;
}
return Promise.reject(new Error(res.data.message));
}
/**
* 添加合同
*/
export async function addLendingSettle(data: LendingSettle) {
const res = await request.post<ApiResult<unknown>>(
'/tower/tower-lending-settle',
data
);
if (res.data.code === 0) {
return res.data;
}
return Promise.reject(new Error(res.data.message));
}
/**
* 修改合同
*/
export async function updateLendingSettle(data: LendingSettle) {
const res = await request.put<ApiResult<unknown>>(
'/tower/tower-lending-settle',
data
);
if (res.data.code === 0) {
return res.data;
}
return Promise.reject(new Error(res.data.message));
}
/**
* 批量修改合同
*/
export async function updateBatchLending(data: LendingSettle[]) {
const res = await request.put<ApiResult<unknown>>(
'/tower/tower-lending-settle/batch',
data
);
if (res.data.code === 0) {
return res.data.message;
}
return Promise.reject(new Error(res.data.message));
}
export async function addBatchLendingSettle(data: LendingSettle[]) {
const res = await request.post<ApiResult<unknown>>(
'/tower/tower-lending-settle/batch',
data
);
if (res.data.code === 0) {
return res.data.message;
}
return Promise.reject(new Error(res.data.message));
}
/**
* 删除合同
*/
export async function removeLendingSettle(id?: number) {
const res = await request.delete<ApiResult<unknown>>(
'/tower/tower-lending-settle/' + id
);
if (res.data.code === 0) {
return res.data.message;
}
return Promise.reject(new Error(res.data.message));
}
/**
* 批量删除合同
*/
export async function removeBatchLendingSettle(data: (number | undefined)[]) {
const res = await request.delete<ApiResult<unknown>>(
'/tower/tower-lending-settle/batch',
{
data
}
);
if (res.data.code === 0) {
return res.data.message;
}
return Promise.reject(new Error(res.data.message));
}

View File

@@ -0,0 +1,40 @@
import type { PageParam } from '@/api';
/**
* 合同
*/
export interface LendingSettle {
lendingSettleListId?: any;
lendingId?: any;
equipmentId?: any;
lendingPath?: any;
coopWay?: any;
startDate?: any;
stopDate?: any;
calDay?: any;
isFullMonth?: any;
daysInMonth?: any;
monthRentAmount?: any;
shouldPayRentAmount?: any;
dailyRentAmount?: any;
shouldSupplementAmount?: any;
shouldDeductionAmount?: any;
paidAmount?: any;
taxRate?: any;
taxAmount?: any;
totalAmountWithTax?: any;
remark?: any;
userId?: any;
equipmentName?: any;
equipmentModel?: any;
equipmentNo?: any;
}
/**
* 合同搜索条件
*/
export interface LendingSettleParam extends PageParam {
projectName?: string;
contractNo?: string;
lendingId?: string;
}

View File

@@ -1,6 +1,19 @@
import request from '@/utils/request';
import type { ApiResult, PageResult } from '@/api';
import type { Project, ProjectParam } from '@/api/tower/project/model';
/**
* 项目数据
*/
export async function towerProjectData() {
const res = await request.get(
'/tower/tower-project/data'
);
if (res.data.code === 0) {
return res.data.data;
}
return Promise.reject(new Error(res.data.message));
}
/**
* 分页查询仓库
*/
@@ -43,6 +56,16 @@ export async function addProject(data: Project) {
}
return Promise.reject(new Error(res.data.message));
}
export async function addBatchProject(data: Project[]) {
const res = await request.post<ApiResult<unknown>>(
'/tower/tower-project/batch',
data
);
if (res.data.code === 0) {
return res.data.message;
}
return Promise.reject(new Error(res.data.message));
}
/**
* 修改仓库

View File

@@ -17,11 +17,16 @@ export interface Project {
projectId?: number;
projectName?: string;
projectImage?: string;
filingNo?: string;
files?: FileItem[];
companyName?: string;
companyId?: number;
customerName?: string;
customerId?: number;
projectRegion?: string;
placeList?: string;
projectAddress?: string;
projectCity?: string;
longitude?: string;
latitude?: string;
superviseNo?: string;

View File

@@ -6,9 +6,12 @@ import type { PageParam } from '@/api';
export interface ProjectOrder {
// 合同预定设备清单id
projectOrderId?: number;
equipmentId?: number;
equipmentName?: string;
equipmentModel?: string;
equipmentNum?: number;
filingNo?: string;
factoryNo?: string;
key?: string;
unit?: string;
startTime?: string;

View File

@@ -1,4 +1,4 @@
import type { PageParam } from '@/api';
import type { PageParam } from "@/api";
/**
* 合同
@@ -9,12 +9,13 @@ export interface Settle {
status?: any;
contractId?: any;
startDate?: any;
endDate?: string;
settleMethod?: number;
endDate?: any;
settleMethod?: any;
extendMonthDate?: number;
totalAmount?: number;
userId?: any;
contactNumber?: any;
projectName?: any;
}
@@ -25,3 +26,5 @@ export interface SettleParam extends PageParam {
settleNo?: string;
contractId?: string;
}
export const SETTLE_STATUS_LIST = ["未认证", "已认证", "已失效"];

View File

@@ -22,6 +22,12 @@ export interface SettleDetail {
userId?: any;
days?: any;
dailyAmount?: any;
month?: any;
day?: any;
payRate?: any;
inDate?: any;
outDate?: any;
realAmount?: any;
}
/**

View File

@@ -0,0 +1,143 @@
import request from "@/utils/request";
import type { ApiResult, PageResult } from "@/api";
import type { Worksheet, WorksheetParam } from "./model";
/**
* 分页查询结算
*/
export async function pageWorksheet(params: WorksheetParam) {
const res = await request.get<ApiResult<PageResult<Worksheet>>>(
"/tower/tower-worksheet/page",
{
params
}
);
if (res.data.code === 0) {
return res.data.data;
}
return Promise.reject(new Error(res.data.message));
}
/**
* 查询合同列表
*/
export async function listWorksheet(params?: WorksheetParam) {
const res = await request.get<ApiResult<Worksheet[]>>(
"/tower/tower-worksheet",
{
params
}
);
if (res.data.code === 0 && res.data.data) {
return res.data.data;
}
return Promise.reject(new Error(res.data.message));
}
/**
* 根据id查询合同
*/
export async function getWorksheet(id: number) {
const res = await request.get<ApiResult<Worksheet>>(
"/tower/tower-worksheet/" + id
);
if (res.data.code === 0 && res.data.data) {
return res.data.data;
}
return Promise.reject(new Error(res.data.message));
}
/**
* 根据id查询合同
*/
export async function getWorksheetByWordType(projectId: number, workType: number) {
const res = await request.post<ApiResult<Worksheet[]>>(
"/tower/tower-worksheet/by-work-type", { projectId, workType }
);
if (res.data.code === 0 && res.data.data) {
return res.data.data;
}
return Promise.reject(new Error(res.data.message));
}
/**
* 添加合同
*/
export async function addWorksheet(data: Worksheet) {
const res = await request.post<ApiResult<unknown>>(
"/tower/tower-worksheet",
data
);
if (res.data.code === 0) {
return res.data;
}
return Promise.reject(new Error(res.data.message));
}
/**
* 修改合同
*/
export async function updateWorksheet(data: Worksheet) {
const res = await request.put<ApiResult<unknown>>(
"/tower/tower-worksheet",
data
);
if (res.data.code === 0) {
return res.data;
}
return Promise.reject(new Error(res.data.message));
}
/**
* 批量修改合同
*/
export async function updateBatchWorksheet(data: Worksheet[]) {
const res = await request.put<ApiResult<unknown>>(
"/tower/tower-worksheet/batch",
data
);
if (res.data.code === 0) {
return res.data.message;
}
return Promise.reject(new Error(res.data.message));
}
export async function addBatchWorksheet(data: Worksheet[]) {
const res = await request.post<ApiResult<unknown>>(
"/tower/tower-worksheet/batch",
data
);
if (res.data.code === 0) {
return res.data.message;
}
return Promise.reject(new Error(res.data.message));
}
/**
* 删除合同
*/
export async function removeWorksheet(id?: number) {
const res = await request.delete<ApiResult<unknown>>(
"/tower/tower-worksheet/" + id
);
if (res.data.code === 0) {
return res.data.message;
}
return Promise.reject(new Error(res.data.message));
}
/**
* 批量删除合同
*/
export async function removeBatchWorksheet(data: (number | undefined)[]) {
const res = await request.delete<ApiResult<unknown>>(
"/tower/tower-worksheet/batch",
{
data
}
);
if (res.data.code === 0) {
return res.data.message;
}
return Promise.reject(new Error(res.data.message));
}

View File

@@ -0,0 +1,66 @@
import type { PageParam } from "@/api";
import { User } from "@/api/system/user/model";
/**
* 合同
*/
export interface Worksheet {
worksheetId?: any;
type?: any;
startUid?: any;
projectId?: any;
planInDate?: any;
receiveDate?: any;
equipmentType?: any;
workType?: any;
auditStatus?: number;
status?: number;
detail?: any;
setUp?: any;
parts?: any;
check?: any;
projectName?: any;
projectRegion?: any;
projectAddress?: string;
address?: string;
contactPhone?: any;
productionMangerUser?: User;
documentUser?: User;
classManagerUser?: User;
assetUser?: User;
fixUser?: User;
carDispatchUser?: User;
auditList?: any[];
carDispatchList?: any[];
documentDoneTime?:string,
assetDoneTime?:string,
fixDoneTime?:string,
}
/**
* 合同搜索条件
*/
export interface WorksheetParam extends PageParam {
projectName?: string;
contractNo?: string;
}
export const WORKSHEET_STATUS_LIST = [
"已取消",
"待派单",
"待整理资料",
"待到场",
"待确认",
"已完成"
];
export const WORKSHEET_EQUIPMENT_TYPE = ["塔式起重机", "施工升降机", "物料提升机"];
export const WORKSHEET_WORK_TYPE = ["安装单", "加高单", "拆卸单"];
export const WORKSHEET_AUDIT_STATUS_LIST = [
"无需审核",
"待审核",
"审核通过",
"审核解决",
]

View File

@@ -89,7 +89,7 @@ const columns = ref<ColumnItem[]>([
},
{
title: "合同编号",
dataIndex: "contractNumber"
dataIndex: "contactNumber"
},
{
title: "项目名称",

View File

@@ -1,6 +1,6 @@
<template>
<ele-modal
:width="750"
width="50%"
:visible="visible"
:maskClosable="false"
:title="title"
@@ -17,14 +17,17 @@
:pagination="false"
>
<template #toolbar>
<a-input-search
allow-clear
v-model:value="searchText"
placeholder="请输入搜索关键词"
style="width: 200px"
@search="reload"
@pressEnter="reload"
/>
<a-space>
<a-input-search
allow-clear
v-model:value="searchText"
placeholder="请输入搜索关键词"
style="width: 200px"
@search="reload"
@pressEnter="reload"
/>
<a-checkbox v-model:checked="idleOnly" @change="reload">仅显示未绑定项目设备</a-checkbox>
</a-space>
</template>
<template #bodyCell="{ column, record }">
<template v-if="column.key === 'action'">
@@ -38,124 +41,121 @@
</template>
<script lang="ts" setup>
import { ref } from 'vue';
import {
ColumnItem,
DatasourceFunction
} from 'ele-admin-pro/es/ele-pro-table/types';
import { EleProTable } from 'ele-admin-pro';
import { TowerEquipment, TowerEquipmentParam } from "@/api/tower/equipment/model";
import { pageTowerEquipment } from "@/api/tower/equipment";
import { ref } from "vue";
import {
ColumnItem,
DatasourceFunction
} from "ele-admin-pro/es/ele-pro-table/types";
import { EleProTable } from "ele-admin-pro";
import { TowerEquipment, TowerEquipmentParam } from "@/api/tower/equipment/model";
import { pageTowerEquipment } from "@/api/tower/equipment";
const props = defineProps<{
// 弹窗是否打开
visible: boolean;
// 标题
title?: string;
// 修改回显的数据
data?: TowerEquipment | null;
}>();
const props = defineProps<{
// 弹窗是否打开
visible: boolean;
// 标题
title?: string;
// 修改回显的数据
data?: TowerEquipment | null;
}>();
const emit = defineEmits<{
(e: 'done', data: TowerEquipment): void;
(e: 'update:visible', visible: boolean): void;
}>();
const emit = defineEmits<{
(e: "done", data: TowerEquipment): void;
(e: "update:visible", visible: boolean): void;
}>();
/* 更新visible */
const updateVisible = (value: boolean) => {
emit('update:visible', value);
};
/* 更新visible */
const updateVisible = (value: boolean) => {
emit("update:visible", value);
};
// 搜索内容
const searchText = ref(null);
// 搜索内容
const searchText = ref(null);
// 表格实例
const tableRef = ref<InstanceType<typeof EleProTable> | null>(null);
// 表格实例
const tableRef = ref<InstanceType<typeof EleProTable> | null>(null);
// 表格配置
const columns = ref<ColumnItem[]>([
{
title: 'ID',
dataIndex: 'id'
},
{
title: '设备名称',
dataIndex: 'name',
key: 'name',
showSorterTooltip: false,
ellipsis: true
},
{
title: '设备型号',
key: 'model',
showSorterTooltip: false,
ellipsis: true
},
{
title: '出场编号',
dataIndex: 'factoryNo',
key: 'factoryNo',
showSorterTooltip: false,
ellipsis: true
},
{
title: '设备编号',
dataIndex: 'equipmentNo',
key: 'equipmentNo',
showSorterTooltip: false,
ellipsis: true
},
{
title: '制造单位',
dataIndex: 'manufactor',
key: 'manufactor',
showSorterTooltip: false,
ellipsis: true
},
{
title: '产权单位',
dataIndex: 'company',
key: 'company',
showSorterTooltip: false,
ellipsis: true
},
{
title: '操作',
key: 'action',
align: 'center'
// 表格配置
const columns = ref<ColumnItem[]>([
{
title: "设备名称",
dataIndex: "name",
key: "name",
showSorterTooltip: false,
ellipsis: true
},
{
title: "设备型号",
dataIndex: "model",
showSorterTooltip: false,
ellipsis: true
},
{
title: "出场编号",
dataIndex: "factoryNo",
key: "factoryNo",
showSorterTooltip: false,
ellipsis: true
},
{
title: "设备编号",
dataIndex: "equipmentNo",
key: "equipmentNo",
showSorterTooltip: false,
ellipsis: true
},
{
title: "备案编号",
dataIndex: "filingNo",
key: "filingNo",
showSorterTooltip: false
},
{
title: "制造单位",
dataIndex: "manufactor",
key: "manufactor",
showSorterTooltip: false,
ellipsis: true
},
{
title: "操作",
key: "action",
align: "center"
}
]);
const idleOnly = ref<boolean>(false)
// 表格数据源
const datasource: DatasourceFunction = ({ page, limit, where, orders }) => {
where = {};
// 搜索条件
if (searchText.value) {
where.keywords = searchText.value;
}
where.isStaff = true;
where.idleOnly = idleOnly.value;
return pageTowerEquipment({
...where,
...orders,
page,
limit
});
};
/* 搜索 */
const reload = (where?: TowerEquipmentParam) => {
tableRef?.value?.reload({ page: 1, where });
};
/* 自定义行属性 */
const customRow = (record: TowerEquipment) => {
return {
// 行点击事件
onClick: () => {
updateVisible(false);
emit("done", record);
}
]);
// 表格数据源
const datasource: DatasourceFunction = ({ page, limit, where, orders }) => {
where = {};
// 搜索条件
if (searchText.value) {
where.keywords = searchText.value;
}
where.isStaff = true;
return pageTowerEquipment({
...where,
...orders,
page,
limit
});
};
/* 搜索 */
const reload = (where?: TowerEquipmentParam) => {
tableRef?.value?.reload({ page: 1, where });
};
/* 自定义行属性 */
const customRow = (record: TowerEquipment) => {
return {
// 行点击事件
onClick: () => {
updateVisible(false);
emit('done', record);
}
};
};
};
</script>
<style lang="less"></style>

View File

@@ -31,7 +31,7 @@ export const LAYOUT_PATH = '/';
export const REDIRECT_PATH = '/redirect';
// 开启页签栏是否缓存组件
//export const TAB_KEEP_ALIVE = !import.meta.env.DEV;
export const TAB_KEEP_ALIVE = true;
export const TAB_KEEP_ALIVE = false;
// token 传递的 header 名称
export const TOKEN_HEADER_NAME = 'Authorization';
// token 存储的名称

View File

@@ -23,13 +23,13 @@
<!-- >-->
<!-- </a-select>-->
<!-- </div>-->
<div class="ele-admin-header-tool-item" @click="myOrder"> 费用 </div>
<!-- <div class="ele-admin-header-tool-item" @click="myOrder"> 费用 </div>-->
<!-- 工单系统 -->
<div class="ele-admin-header-tool-item">
<a-dropdown placement="bottom" :overlay-style="{ minWidth: '100px' }">
<div class="ele-admin-header-avatar">
<span :class="{ 'hidden-sm-and-down': styleResponsive }"> 工单 </span>
</div>
<!-- <div class="ele-admin-header-avatar">-->
<!-- <span :class="{ 'hidden-sm-and-down': styleResponsive }"> 工单 </span>-->
<!-- </div>-->
<template #overlay>
<a-menu :selectable="false" @click="onUserDropClick">
<a-menu-item key="taskAdd">
@@ -143,7 +143,7 @@
<div class="ele-cell" align="center">
<div class="ele-cell-content">
<logout-outlined />
{{ t('layout.header.logout') }}
退出登录
</div>
</div>
</a-menu-item>
@@ -240,8 +240,8 @@
} else if (key === 'logout') {
// 退出登录
Modal.confirm({
title: t('layout.logout.title'),
content: t('layout.logout.message'),
title: '提示',
content: '确认退出吗',
icon: createVNode(ExclamationCircleOutlined),
maskClosable: true,
onOk: () => {

View File

@@ -2,13 +2,13 @@
<template>
<div class="ele-text-center" style="padding: 16px 0">
<div class="ele-text-secondary" style="margin-top: 8px">
{{ t('layout.footer.copyright') }}
<!-- {{ t('layout.footer.copyright') }}-->
</div>
</div>
</template>
<script lang="ts" setup>
import { useI18n } from 'vue-i18n';
// import { useI18n } from 'vue-i18n';
const { t } = useI18n();
// const { t } = useI18n();
</script>

View File

@@ -77,7 +77,7 @@
const aoa = utils.sheet_to_json<string[]>(worksheet, { header: 1 });
console.log(aoa);
aoa.slice(1).map((d) => {
const array = ['闲置', '报废', '注销', '转卖'];
const array = ['闲置', '报废', '注销', '转卖', '在用', '场地'];
importData.value.push({
status: array.indexOf(d[0]),
name: d[1],

View File

@@ -51,7 +51,7 @@
<a-input-password
size="large"
v-model:value="form.password"
:placeholder="t('login.password')"
:placeholder="'请输入密码'"
@pressEnter="submit"
>
<template #prefix>
@@ -67,7 +67,7 @@
type="text"
:maxlength="5"
v-model:value="form.code"
:placeholder="t('login.code')"
:placeholder="'请输入验证码'"
@pressEnter="submit"
>
<template #prefix>
@@ -81,7 +81,7 @@
</a-form-item>
<a-form-item>
<a-checkbox v-model:checked="form.remember">
{{ t('login.remember') }}
记住密码
</a-checkbox>
<!-- <router-link-->
<!-- to="/forget"-->
@@ -99,7 +99,7 @@
:loading="loading"
@click="submit"
>
{{ loading ? t('login.loading') : t('login.login') }}
{{ loading ? '登录中' : '登录' }}
</a-button>
</a-form-item>
</template>
@@ -150,7 +150,7 @@
WechatOutlined,
WeiboOutlined
} from '@ant-design/icons-vue';
// import I18nIcon from '@/layout/components/i18n-icon.vue';
import I18nIcon from '@/layout/components/i18n-icon.vue';
// import { getToken } from '@/utils/token-util';
// import { TENANT_ID } from '@/config/setting';
import { goHomeRoute, cleanPageTabs } from '@/utils/page-tab-util';
@@ -189,21 +189,21 @@
username: [
{
required: true,
message: t('login.username'),
message: '请输入用户名',
type: 'string'
}
],
password: [
{
required: true,
message: t('login.password'),
message: '请输入密码',
type: 'string'
}
],
code: [
{
required: true,
message: t('login.code'),
message: '请输入验证码',
type: 'string'
}
]

View File

@@ -1,192 +1,193 @@
<template>
<div class="ele-body">
<a-card :bordered="false" :body-style="{ padding: '16px' }">
<ele-split-layout
width="266px"
allow-collapse
:right-style="{ overflow: 'hidden' }"
:style="{ minHeight: 'calc(100vh - 152px)' }"
>
<!-- 表格 -->
<ele-pro-table
ref="tableRef"
row-key="dictId"
:columns="columns"
:datasource="datasource"
v-model:current="current"
selection-type="radio"
:row-selection="{ columnWidth: 32 }"
:need-page="false"
:toolkit="[]"
height="calc(100vh - 290px)"
tools-theme="default"
class="sys-dict-table"
@done="done"
>
<template #toolbar>
<a-space :size="10">
<a-button type="primary" class="ele-btn-icon" @click="openEdit()">
<template #icon>
<plus-outlined />
<div class="ele-body">
<a-card :bordered="false" :body-style="{ padding: '16px' }">
<ele-split-layout
width="266px"
allow-collapse
:right-style="{ overflow: 'hidden' }"
:style="{ minHeight: 'calc(100vh - 152px)' }"
>
<!-- 表格 -->
<ele-pro-table
ref="tableRef"
row-key="dictId"
:columns="columns"
:datasource="datasource"
v-model:current="current"
selection-type="radio"
:row-selection="{ columnWidth: 32 }"
:need-page="false"
:toolkit="[]"
height="calc(100vh - 290px)"
tools-theme="default"
class="sys-dict-table"
@done="done"
>
<template #toolbar>
<a-space :size="10">
<a-button type="primary" class="ele-btn-icon" @click="openEdit()">
<template #icon>
<plus-outlined />
</template>
<span>新建</span>
</a-button>
<a-button
type="primary"
:disabled="!current"
class="ele-btn-icon"
@click="openEdit(current)"
>
<template #icon>
<edit-outlined />
</template>
<span>修改</span>
</a-button>
<a-button
danger
type="primary"
:disabled="!current"
class="ele-btn-icon"
@click="remove"
>
<template #icon>
<delete-outlined />
</template>
<span>删除</span>
</a-button>
</a-space>
</template>
<template #bodyCell="{ column, record }">
<template v-if="column.key === 'dictName'">
<div>
<span>{{ record.dictName }}</span>
<span class="ele-text-placeholder">{{ record.dictCode }}</span>
</div>
</template>
</template>
</ele-pro-table>
<template #content>
<dict-data
v-if="current && current.dictId"
:dict-id="current.dictId"
/>
</template>
<span>新建</span>
</a-button>
<a-button
type="primary"
:disabled="!current"
class="ele-btn-icon"
@click="openEdit(current)"
>
<template #icon>
<edit-outlined />
</template>
<span>修改</span>
</a-button>
<a-button
danger
type="primary"
:disabled="!current"
class="ele-btn-icon"
@click="remove"
>
<template #icon>
<delete-outlined />
</template>
<span>删除</span>
</a-button>
</a-space>
</template>
<template #bodyCell="{ column, record }">
<template v-if="column.key === 'dictName'">
{{ record.dictName }}
<span class="ele-text-placeholder">
{{ record.dictCode }}
</span>
</template>
</template>
</ele-pro-table>
<template #content>
<dict-data
v-if="current && current.dictId"
:dict-id="current.dictId"
/>
</template>
</ele-split-layout>
</a-card>
<!-- 编辑弹窗 -->
<dict-edit v-model:visible="showEdit" :data="editData" @done="reload" />
</div>
</ele-split-layout>
</a-card>
<!-- 编辑弹窗 -->
<dict-edit v-model:visible="showEdit" :data="editData" @done="reload" />
</div>
</template>
<script lang="ts" setup>
import { createVNode, ref } from 'vue';
import { message, Modal } from 'ant-design-vue';
import {
import { createVNode, ref } from "vue";
import { message, Modal } from "ant-design-vue";
import {
PlusOutlined,
EditOutlined,
DeleteOutlined,
ExclamationCircleOutlined
} from '@ant-design/icons-vue';
import type { EleProTable } from 'ele-admin-pro';
import type {
} from "@ant-design/icons-vue";
import type { EleProTable } from "ele-admin-pro";
import type {
DatasourceFunction,
ColumnItem,
EleProTableDone
} from 'ele-admin-pro/es/ele-pro-table/types';
import DictData from './components/dict-data.vue';
import DictEdit from './components/dict-edit.vue';
import { listDictionaries, removeDict } from '@/api/system/dict';
import type { Dict } from '@/api/system/dict/model';
} from "ele-admin-pro/es/ele-pro-table/types";
import DictData from "./components/dict-data.vue";
import DictEdit from "./components/dict-edit.vue";
import { listDictionaries, removeDict } from "@/api/system/dict";
import type { Dict } from "@/api/system/dict/model";
// 表格实例
const tableRef = ref<InstanceType<typeof EleProTable> | null>(null);
// 表格实例
const tableRef = ref<InstanceType<typeof EleProTable> | null>(null);
// 表格列配置
const columns = ref<ColumnItem[]>([
// 表格列配置
const columns = ref<ColumnItem[]>([
{
key: 'index',
width: 35,
ellipsis: true,
align: 'center',
fixed: 'left',
hideInSetting: true,
customRender: ({ index }) => index + (tableRef.value?.tableIndex ?? 0)
key: "index",
width: 35,
ellipsis: true,
align: "center",
fixed: "left",
hideInSetting: true,
customRender: ({ index }) => index + (tableRef.value?.tableIndex ?? 0)
},
{
title: '字典名称',
dataIndex: 'dictName',
key: 'dictName'
title: "字典名称",
dataIndex: "dictName",
key: "dictName"
}
]);
]);
// 表格选中数据
const current = ref<Dict | null>(null);
// 表格选中数据
const current = ref<Dict | null>(null);
// 是否显示编辑弹窗
const showEdit = ref(false);
// 是否显示编辑弹窗
const showEdit = ref(false);
// 编辑回显数据
const editData = ref<Dict | null>(null);
// 编辑回显数据
const editData = ref<Dict | null>(null);
// 表格数据源
const datasource: DatasourceFunction = () => {
// 表格数据源
const datasource: DatasourceFunction = () => {
return listDictionaries();
};
};
/* 表格渲染完成回调 */
const done: EleProTableDone<Dict> = (res) => {
/* 表格渲染完成回调 */
const done: EleProTableDone<Dict> = (res) => {
if (res.data?.length) {
current.value = res.data[0];
current.value = res.data[0];
}
};
};
/* 刷新表格 */
const reload = () => {
/* 刷新表格 */
const reload = () => {
tableRef?.value?.reload();
};
};
/* 打开编辑弹窗 */
const openEdit = (row?: Dict | null) => {
/* 打开编辑弹窗 */
const openEdit = (row?: Dict | null) => {
editData.value = row ?? null;
showEdit.value = true;
};
};
/* 删除 */
const remove = () => {
/* 删除 */
const remove = () => {
Modal.confirm({
title: '提示',
content: '确定要删除选中的字典吗?',
icon: createVNode(ExclamationCircleOutlined),
maskClosable: true,
onOk: () => {
const hide = message.loading('请求中..', 0);
removeDict(current.value?.dictId)
.then((msg) => {
hide();
message.success(msg);
reload();
})
.catch((e) => {
hide();
message.error(e.message);
});
}
title: "提示",
content: "确定要删除选中的字典吗?",
icon: createVNode(ExclamationCircleOutlined),
maskClosable: true,
onOk: () => {
const hide = message.loading("请求中..", 0);
removeDict(current.value?.dictId)
.then((msg) => {
hide();
message.success(msg);
reload();
})
.catch((e) => {
hide();
message.error(e.message);
});
}
});
};
};
</script>
<script lang="ts">
export default {
name: 'SystemDict'
};
export default {
name: "SystemDict"
};
</script>
<style lang="less" scoped>
.sys-dict-table :deep(.ant-table-body) {
.sys-dict-table :deep(.ant-table-body) {
overflow: auto !important;
overflow: overlay !important;
}
.dict-code {
}
.dict-code {
color: #cccccc;
}
}
</style>

View File

@@ -1,10 +1,10 @@
<!-- 机构编辑弹窗 -->
<!-- 部门编辑弹窗 -->
<template>
<ele-modal
:width="620"
:visible="visible"
:confirm-loading="loading"
:title="isUpdate ? '修改机构' : '添加机构'"
:title="isUpdate ? '修改部门' : '添加部门'"
:body-style="{ paddingBottom: '8px' }"
@update:visible="updateVisible"
@ok="save"
@@ -20,53 +20,28 @@
<a-col
v-bind="styleResponsive ? { md: 12, sm: 24, xs: 24 } : { span: 12 }"
>
<a-form-item label="上级机构" name="parentId">
<a-form-item label="上级部门" name="parentId">
<org-select
:data="organizationList"
placeholder="请选择上级机构"
placeholder="请选择上级部门"
v-model:value="form.parentId"
/>
</a-form-item>
<a-form-item label="机构名称" name="organizationName">
<a-form-item label="部门名称" name="organizationName">
<a-input
allow-clear
:maxlength="20"
placeholder="请输入机构名称"
placeholder="请输入部门名称"
v-model:value="form.organizationName"
/>
</a-form-item>
<a-form-item label="机构全称" name="organizationFullName">
<a-input
allow-clear
:maxlength="100"
placeholder="请输入机构全称"
v-model:value="form.organizationFullName"
/>
</a-form-item>
<a-form-item label="机构代码">
<a-input
allow-clear
:maxlength="20"
placeholder="请输入机构代码"
v-model:value="form.organizationCode"
/>
</a-form-item>
</a-col>
<a-col
v-bind="styleResponsive ? { md: 12, sm: 24, xs: 24 } : { span: 12 }"
>
<a-form-item label="机构类型" name="organizationType">
<a-form-item label="部门类型" name="organizationType">
<org-type-select v-model:value="form.organizationType" />
</a-form-item>
<a-form-item label="排序号" name="sortNumber">
<a-input-number
:min="0"
:max="99999"
class="ele-fluid"
placeholder="请输入排序号"
v-model:value="form.sortNumber"
/>
</a-form-item>
<a-form-item label="备注">
<a-textarea
:rows="4"
@@ -110,9 +85,9 @@
visible: boolean;
// 修改回显的数据
data?: Organization | null;
// 机构id
// 部门id
organizationId?: number;
// 全部机构
// 全部部门
organizationList: Organization[];
}>();
@@ -142,15 +117,7 @@
organizationName: [
{
required: true,
message: '请输入机构名称',
type: 'string',
trigger: 'blur'
}
],
organizationFullName: [
{
required: true,
message: '请输入机构全称',
message: '请输入部门名称',
type: 'string',
trigger: 'blur'
}
@@ -158,19 +125,11 @@
organizationType: [
{
required: true,
message: '请选择机构类型',
message: '请选择部门类型',
type: 'string',
trigger: 'blur'
}
],
sortNumber: [
{
required: true,
message: '请输入排序号',
type: 'number',
trigger: 'blur'
}
]
});
/* 保存编辑 */

View File

@@ -53,13 +53,21 @@
v-model:value="form.realName"
/>
</a-form-item>
<a-form-item label="所属机构" name="type">
<a-form-item label="所属部门" name="type">
<org-select
:data="organizationList"
placeholder="请选择所属机构"
placeholder="请选择所属部门"
v-model:value="form.organizationId"
/>
</a-form-item>
<a-form-item label="小程序权限" name="type">
<a-select placeholder="必选项" style="width: 250px" size="small"
v-model:value="form.userLevel">
<a-select-option v-for="(item, index) in USER_LEVEL_LIST" :key="index" :value="index">
{{ item }}
</a-select-option>
</a-select>
</a-form-item>
</a-col>
<a-col
v-bind="styleResponsive ? { md: 12, sm: 24, xs: 24 } : { span: 12 }"
@@ -124,6 +132,7 @@
import OrgSelect from './org-select.vue';
// import { getDictionaryOptions } from '@/utils/common';
import { Organization } from '@/api/system/organization/model';
import { USER_LEVEL_LIST } from "@/api/system/user/model";
// 是否开启响应式布局
const themeStore = useThemeStore();
@@ -153,6 +162,7 @@
// 提交状态
const loading = ref(false);
// 表单数据
const { form, resetFields, assignFields } = useFormData<User>({
type: undefined,
@@ -168,6 +178,7 @@
password: '',
introduction: '',
organizationId: undefined,
userLevel: undefined,
birthday: '',
idCard: '',
comments: ''

View File

@@ -103,6 +103,11 @@
{{ formatNumber(record.expendMoney) }}
</span>
</template>
<template v-if="column.key === 'userLevel'">
<span>
{{ USER_LEVEL_LIST[record.userLevel] }}
</span>
</template>
<template v-else-if="column.key === 'status'">
<a-switch
:checked="record.status === 0"
@@ -175,6 +180,7 @@
import { getDictionaryOptions } from '@/utils/common';
import { listOrganizations } from '@/api/system/organization';
import { Organization } from '@/api/system/organization/model';
import { USER_LEVEL_LIST } from "@/api/system/user/model";
// 加载状态
const loading = ref(true);
@@ -256,13 +262,6 @@
hideInSetting: true,
customRender: ({ index }) => index + (tableRef.value?.tableIndex ?? 0)
},
// {
// title: '操作',
// key: 'action',
// width: 200,
// fixed: 'left',
// align: 'center'
// },
{
title: 'ID',
dataIndex: 'userId',
@@ -314,86 +313,6 @@
hideInTable: true,
showSorterTooltip: false
},
{
title: '可用余额',
dataIndex: 'balance',
key: 'balance',
sorter: true,
showSorterTooltip: false
},
{
title: '实际消费金额',
dataIndex: 'expendMoney',
key: 'expendMoney',
sorter: true,
showSorterTooltip: false
},
{
title: '可用积分',
dataIndex: 'points',
sorter: true
},
{
title: '注册来源',
key: 'platform',
dataIndex: 'platform',
sorter: true,
hideInTable: true,
customRender: ({ text }) => ['未知', '网站', '小程序', 'APP'][text]
},
{
title: '证件号码',
dataIndex: 'idCard',
hideInTable: true
},
{
title: '出生日期',
dataIndex: 'birthday',
key: 'birthday',
hideInTable: true
},
{
title: '省份',
dataIndex: 'province',
key: 'province',
hideInTable: true
},
{
title: '城市',
dataIndex: 'city',
key: 'city',
hideInTable: true,
showSorterTooltip: false
},
{
title: '地区',
dataIndex: 'region',
key: 'region',
hideInTable: true,
showSorterTooltip: false
},
{
title: '个人简介',
dataIndex: 'introduction',
key: 'introduction',
hideInTable: true,
showSorterTooltip: false
},
{
title: '邮箱认证',
dataIndex: 'emailVerified',
sorter: true,
hideInTable: true,
showSorterTooltip: false,
customRender: ({ text }) => ['未认证', '已认证'][text]
},
{
title: '实名认证',
dataIndex: 'certification',
sorter: true,
hideInTable: true,
customRender: ({ text }) => ['未认证', '已认证'][text]
},
{
title: '角色',
dataIndex: 'roles',
@@ -403,6 +322,12 @@
filterMultiple: false,
filters: roles.value
},
{
title: '小程序权限',
dataIndex: 'userLevel',
key: 'userLevel',
align: 'center',
},
{
title: '创建时间',
dataIndex: 'createTime',
@@ -419,7 +344,14 @@
showSorterTooltip: false,
width: 90,
align: 'center'
}
},
{
title: '操作',
key: 'action',
width: 200,
fixed: 'left',
align: 'center'
},
]);
// 默认搜索条件

View File

@@ -1,211 +1,219 @@
<!-- 编辑弹窗 -->
<template>
<ele-modal
width="75%"
:visible="visible"
:maskClosable="false"
:maxable="maxable"
:title="isUpdate ? '编辑配件' : '添加配件'"
:body-style="{ paddingBottom: '28px' }"
@update:visible="updateVisible"
@ok="save"
>
<div style="background-color: #f3f3f3; padding: 8px">
<a-form
ref="formRef"
:model="form"
:rules="rules"
:label-col="{ md: { span: 7 }, sm: { span: 4 }, xs: { span: 24 } }"
:wrapper-col="{ md: { span: 17 }, sm: { span: 20 }, xs: { span: 24 } }"
>
<a-card title="基本信息" :bordered="false">
<a-row :gutter="16">
<a-col
v-bind="styleResponsive ? { md: 8, sm: 24, xs: 24 } : { span: 8 }"
<ele-modal
width="75%"
:visible="visible"
:maskClosable="false"
:maxable="maxable"
:title="isUpdate ? '编辑配件' : '添加配件'"
:body-style="{ paddingBottom: '28px' }"
@update:visible="updateVisible"
@ok="save"
>
<div style="background-color: #f3f3f3; padding: 8px">
<a-form
ref="formRef"
:model="form"
:rules="rules"
:label-col="{ md: { span: 7 }, sm: { span: 4 }, xs: { span: 24 } }"
:wrapper-col="{ md: { span: 17 }, sm: { span: 20 }, xs: { span: 24 } }"
>
<a-form-item label="配件分类" name="accessoryCategory">
<AccessoryCategory
v-model:value="form.accessoryCategory"
valueField="label"
placeholder="请选择配件分类"
class="ele-fluid"
/>
</a-form-item>
<a-form-item label="配件规格" name="accessorySpecs">
<a-input
allow-clear
placeholder="请输入配件规格"
v-model:value="form.accessorySpecs"
/>
</a-form-item>
<a-form-item label="重量" name="accessoryWeight">
<a-input
allow-clear
placeholder="请输入配件规格"
v-model:value="form.accessoryWeight"
/>
</a-form-item>
</a-col>
<a-col
v-bind="styleResponsive ? { md: 8, sm: 24, xs: 24 } : { span: 8 }"
>
<a-form-item label="配件名称" name="accessoryName">
<a-input
allow-clear
placeholder="请输入配件名称"
v-model:value="form.accessoryName"
/>
</a-form-item>
<a-form-item label="单位" name="accessoryUnit">
<a-input
allow-clear
placeholder="请输入配件单位"
v-model:value="form.accessoryUnit"
/>
</a-form-item>
<a-form-item label="单价" name="accessoryPrice">
<a-input-number
allow-clear
:min="0"
:precision="2"
style="width: 200px"
placeholder="请输入配件单价"
v-model:value="form.accessoryPrice"
/>
</a-form-item>
</a-col>
<a-col
v-bind="styleResponsive ? { md: 8, sm: 24, xs: 24 } : { span: 8 }"
>
<a-form-item label="设备型号" name="accessoryModel">
<TowerSelectModel
:placeholder="`请选择设备型号`"
v-model:value="form.accessoryModel"
@done="chooseAccessoryModel"
/>
</a-form-item>
<a-form-item label="使用年限" name="lifeYear">
<a-input
allow-clear
placeholder="请输入使用年限"
v-model:value="form.lifeYear"
/>
</a-form-item>
</a-col>
</a-row>
</a-card>
<a-divider style="height: 8px" />
<a-card title="出厂信息" :bordered="false">
<a-row :gutter="16">
<a-col
v-bind="styleResponsive ? { md: 8, sm: 24, xs: 24 } : { span: 8 }"
>
<a-form-item label="配件编号" name="accessoryNo">
<a-input
allow-clear
placeholder="请输入当前位置"
v-model:value="form.accessoryNo"
/>
</a-form-item>
<a-form-item label="产权单位" name="companyName">
<DictSelect
:placeholder="'请选择产权单位'"
v-model:value="form.companyName"
:dict-code="'PropertyCompany'"
@done="chooseCompanyName"
/>
</a-form-item>
<a-form-item label="备注" name="comments">
<a-textarea
:rows="4"
:maxlength="200"
placeholder="请输入备注"
v-model:value="form.comments"
/>
</a-form-item>
</a-col>
<a-col
v-bind="styleResponsive ? { md: 8, sm: 24, xs: 24 } : { span: 8 }"
>
<a-form-item label="制造厂商" name="manufactor">
<a-input
allow-clear
placeholder="请输入制造厂商"
v-model:value="form.manufactor"
/>
</a-form-item>
<a-form-item label="厂商编号" name="manufactorNo">
<a-input
allow-clear
placeholder="请输入厂商编号"
v-model:value="form.manufactorNo"
/>
</a-form-item>
</a-col>
<a-col
v-bind="styleResponsive ? { md: 8, sm: 24, xs: 24 } : { span: 8 }"
>
<a-form-item label="出厂日期" name="factoryDate">
<a-date-picker
class="ele-fluid"
value-format="YYYY-MM-DD"
placeholder="请选择日期"
v-model:value="form.factoryDate"
/>
</a-form-item>
<a-form-item label="报废日期" name="scrapDate">
<a-date-picker
class="ele-fluid"
value-format="YYYY-MM-DD"
placeholder="请选择日期"
v-model:value="form.scrapDate"
/>
</a-form-item>
</a-col>
</a-row>
</a-card>
<a-divider style="height: 8px" />
<a-card title="多选适配设备型号" :bordered="false">
<a-row :gutter="16">
<a-col
v-bind="styleResponsive ? { md: 8, sm: 24, xs: 24 } : { span: 8 }"
>
<a-form-item label="设备型号" name="accessoryModelMultiple">
<TowerSelectModelMultiple
:placeholder="`请选择设备型号`"
v-model:value="form.accessoryModelMultiple"
@done="chooseMultiple"
/>
</a-form-item>
</a-col>
</a-row>
</a-card>
</a-form>
</div>
</ele-modal>
<a-card title="基本信息" :bordered="false">
<a-row :gutter="16">
<a-col
v-bind="styleResponsive ? { md: 8, sm: 24, xs: 24 } : { span: 8 }"
>
<a-form-item label="配件分类" name="accessoryCategory">
<AccessoryCategory
v-model:value="form.accessoryCategory"
valueField="label"
placeholder="请选择配件分类"
class="ele-fluid"
/>
</a-form-item>
<a-form-item label="配件规格" name="accessorySpecs">
<a-input
allow-clear
placeholder="请输入配件规格"
v-model:value="form.accessorySpecs"
/>
</a-form-item>
<a-form-item label="重量" name="accessoryWeight">
<a-input
allow-clear
placeholder="请输入配件规格"
v-model:value="form.accessoryWeight"
/>
</a-form-item>
<a-form-item label="购买数量">
<a-input
allow-clear
placeholder="请输入购买数量"
v-model:value="form.accessoryNum"
/>
</a-form-item>
</a-col>
<a-col
v-bind="styleResponsive ? { md: 8, sm: 24, xs: 24 } : { span: 8 }"
>
<a-form-item label="生成厂家" name="accessoryName">
<a-input
allow-clear
placeholder="请输入生成厂家"
v-model:value="form.accessoryName"
/>
</a-form-item>
<a-form-item label="单位" name="accessoryUnit">
<a-input
allow-clear
placeholder="请输入配件单位"
v-model:value="form.accessoryUnit"
/>
</a-form-item>
<a-form-item label="单价" name="accessoryPrice">
<a-input-number
allow-clear
:min="0"
:precision="2"
style="width: 200px"
placeholder="请输入配件单价"
v-model:value="form.accessoryPrice"
/>
</a-form-item>
</a-col>
<a-col
v-bind="styleResponsive ? { md: 8, sm: 24, xs: 24 } : { span: 8 }"
>
<a-form-item label="设备型号" name="accessoryModel">
<TowerSelectModel
:placeholder="`请选择设备型号`"
v-model:value="form.accessoryModel"
@done="chooseAccessoryModel"
/>
</a-form-item>
<a-form-item label="使用年限" name="lifeYear">
<a-input
allow-clear
placeholder="请输入使用年限"
v-model:value="form.lifeYear"
/>
</a-form-item>
<a-form-item label="购买日期" name="lifeYear">
<a-date-picker
class="ele-fluid"
value-format="YYYY-MM-DD"
placeholder="请选择日期"
v-model:value="form.buyDate"
/>
</a-form-item>
</a-col>
</a-row>
</a-card>
<a-divider style="height: 8px" />
<a-card title="出厂信息" :bordered="false">
<a-row :gutter="16">
<a-col
v-bind="styleResponsive ? { md: 8, sm: 24, xs: 24 } : { span: 8 }"
>
<a-form-item label="配件编号" name="accessoryNo">
<a-input
allow-clear
placeholder="请输入当前位置"
v-model:value="form.accessoryNo"
/>
</a-form-item>
<a-form-item label="产权单位" name="companyName">
<DictSelect
:placeholder="'请选择产权单位'"
v-model:value="form.companyName"
:dict-code="'PropertyCompany'"
@done="chooseCompanyName"
/>
</a-form-item>
</a-col>
<a-col
v-bind="styleResponsive ? { md: 8, sm: 24, xs: 24 } : { span: 8 }"
>
<a-form-item label="制造厂商" name="manufactor">
<a-input
allow-clear
placeholder="请输入制造厂商"
v-model:value="form.manufactor"
/>
</a-form-item>
<a-form-item label="报废日期" name="scrapDate">
<a-date-picker
class="ele-fluid"
value-format="YYYY-MM-DD"
placeholder="请选择日期"
v-model:value="form.scrapDate"
/>
</a-form-item>
</a-col>
<a-col
v-bind="styleResponsive ? { md: 8, sm: 24, xs: 24 } : { span: 8 }"
>
<a-form-item label="出厂日期" name="factoryDate">
<a-date-picker
class="ele-fluid"
value-format="YYYY-MM-DD"
placeholder="请选择日期"
v-model:value="form.factoryDate"
/>
</a-form-item>
<a-form-item label="备注" name="comments">
<a-textarea
:rows="4"
:maxlength="200"
placeholder="请输入备注"
v-model:value="form.comments"
/>
</a-form-item>
</a-col>
</a-row>
</a-card>
<a-divider style="height: 8px" />
<a-card title="多选适配设备型号" :bordered="false">
<a-row :gutter="16">
<a-col
v-bind="styleResponsive ? { md: 8, sm: 24, xs: 24 } : { span: 8 }"
>
<a-form-item label="设备型号" name="accessoryModelMultiple">
<TowerSelectModelMultiple
:placeholder="`请选择设备型号`"
v-model:value="form.accessoryModelMultiple"
@done="chooseMultiple"
/>
</a-form-item>
</a-col>
</a-row>
</a-card>
</a-form>
</div>
</ele-modal>
</template>
<script lang="ts" setup>
import { ref, reactive, watch } from 'vue';
import { Form, message } from 'ant-design-vue';
import { assignObject } from 'ele-admin-pro';
import { addAccessory, updateAccessory } from '@/api/tower/accessory';
import { Accessory } from '@/api/tower/accessory/model';
import { useThemeStore } from '@/store/modules/theme';
import { storeToRefs } from 'pinia';
import { FormInstance } from 'ant-design-vue/es/form';
import { Customer } from '@/api/oa/customer/model';
import { Category } from '@/api/goods/category/model';
import { TowerModel } from '@/api/tower/model/model';
import { ref, reactive, watch } from "vue";
import { Form, message } from "ant-design-vue";
import { assignObject } from "ele-admin-pro";
import { addAccessory, updateAccessory } from "@/api/tower/accessory";
import { Accessory } from "@/api/tower/accessory/model";
import { useThemeStore } from "@/store/modules/theme";
import { storeToRefs } from "pinia";
import { FormInstance } from "ant-design-vue/es/form";
import { Customer } from "@/api/oa/customer/model";
import { Category } from "@/api/goods/category/model";
import { TowerModel } from "@/api/tower/model/model";
// 是否是修改
const isUpdate = ref(false);
const useForm = Form.useForm;
// 是否开启响应式布局
const themeStore = useThemeStore();
const { styleResponsive } = storeToRefs(themeStore);
// 是否是修改
const isUpdate = ref(false);
const useForm = Form.useForm;
// 是否开启响应式布局
const themeStore = useThemeStore();
const { styleResponsive } = storeToRefs(themeStore);
const props = defineProps<{
const props = defineProps<{
// 弹窗是否打开
visible: boolean;
// 修改回显的数据
@@ -213,186 +221,183 @@
categoryList?: Category[];
modelTree?: TowerModel[];
modelList?: TowerModel[];
}>();
}>();
const emit = defineEmits<{
(e: 'done'): void;
(e: 'update:visible', visible: boolean): void;
}>();
const emit = defineEmits<{
(e: "done"): void;
(e: "update:visible", visible: boolean): void;
}>();
// 提交状态
const loading = ref(false);
// 是否显示最大化切换按钮
const maxable = ref(true);
// 表格选中数据
const formRef = ref<FormInstance | null>(null);
// 提交状态
const loading = ref(false);
// 是否显示最大化切换按钮
const maxable = ref(true);
// 表格选中数据
const formRef = ref<FormInstance | null>(null);
// 用户信息
const form = reactive<Accessory>({
// 用户信息
const form = reactive<Accessory>({
accessoryId: undefined,
accessoryName: '',
accessoryNo: '',
accessoryName: "",
accessoryNo: "",
accessoryCategory: undefined,
accessoryModel: '',
accessoryModel: "",
accessoryModelMultiple: [],
accessorySpecs: '',
accessorySpecs: "",
accessoryPrice: 0,
accessoryUnit: '',
accessoryStock: '',
companyName: '',
manufactor: '',
accessoryWeight: '',
manufactorNo: '',
accessoryUnit: "",
accessoryNum: 0,
accessoryStock: "",
companyName: "",
manufactor: "",
accessoryWeight: "",
manufactorNo: "",
lifeYear: undefined,
factoryDate: '',
scrapDate: '',
factoryDate: "",
scrapDate: "",
status: undefined,
comments: '',
comments: "",
sortNumber: undefined,
userId: undefined,
createTime: '',
updateTime: ''
});
createTime: "",
updateTime: "",
buyDate: ""
});
/* 更新visible */
const updateVisible = (value: boolean) => {
emit('update:visible', value);
};
/* 更新visible */
const updateVisible = (value: boolean) => {
emit("update:visible", value);
};
// 表单验证规则
const rules = reactive({
// 表单验证规则
const rules = reactive({
accessoryCategory: [
{
required: true,
type: 'array',
message: '请输入配件分类',
trigger: 'blur'
}
{
required: true,
type: "array",
message: "请输入配件分类",
trigger: "blur"
}
],
accessoryName: [
{
required: true,
type: 'string',
message: '请输入配件名称',
trigger: 'blur'
}
{
required: true,
type: "string",
message: "请输入生成厂家",
trigger: "blur"
}
],
accessoryModel: [
{
required: true,
type: 'string',
message: '请输入设备型号',
trigger: 'blur'
}
],
accessoryWeight: [
{
required: true,
type: 'string',
message: '请输入设备重量',
trigger: 'blur'
}
{
required: true,
type: "string",
message: "请输入设备型号",
trigger: "blur"
}
],
accessorySpecs: [
{
required: true,
type: 'string',
message: '请输入设备规格',
trigger: 'blur'
}
{
required: true,
type: "string",
message: "请输入设备规格",
trigger: "blur"
}
],
accessoryUnit: [
{
required: true,
type: 'string',
message: '请输入单位',
trigger: 'blur'
}
{
required: true,
type: "string",
message: "请输入单位",
trigger: "blur"
}
]
});
});
const { resetFields } = useForm(form, rules);
const chooseCompanyName = (data: Customer) => {
const { resetFields } = useForm(form, rules);
const chooseCompanyName = (data: Customer) => {
form.companyName = data.customerName;
};
const chooseAccessoryModel = (data: TowerModel) => {
};
const chooseAccessoryModel = (data: TowerModel) => {
form.accessoryModel = data.name?.concat(String(data.model));
form.lifeYear = data.yearLife;
};
const chooseMultiple = (data) => {
};
const chooseMultiple = (data) => {
form.accessoryModelMultiple = [];
data.map((d) => {
form.accessoryModelMultiple?.push(`${d.name}${d.model}`);
form.accessoryModelMultiple?.push(`${d.name}${d.model}`);
});
};
};
/* 保存编辑 */
const save = () => {
/* 保存编辑 */
const save = () => {
if (!formRef.value) {
return;
return;
}
formRef.value
.validate()
.then(() => {
loading.value = true;
console.log(form.accessoryCategory?.[0]);
const formData = {
...form,
accessoryCategory: `${form.accessoryCategory?.[0]} / ${form.accessoryCategory?.[1]}`,
accessoryModelMultiple: JSON.stringify(form.accessoryModelMultiple)
};
const saveOrUpdate = isUpdate.value ? updateAccessory : addAccessory;
saveOrUpdate(formData)
.then((msg) => {
loading.value = false;
message.success(msg);
updateVisible(false);
emit('done');
})
.catch((e) => {
loading.value = false;
message.error(e.message);
});
})
.catch(() => {});
};
.validate()
.then(() => {
loading.value = true;
console.log(form.accessoryCategory?.[0]);
const formData = {
...form,
accessoryCategory: `${form.accessoryCategory?.[0]} / ${form.accessoryCategory?.[1]}`,
accessoryModelMultiple: JSON.stringify(form.accessoryModelMultiple)
};
const saveOrUpdate = isUpdate.value ? updateAccessory : addAccessory;
saveOrUpdate(formData)
.then((msg) => {
loading.value = false;
message.success(msg);
updateVisible(false);
emit("done");
})
.catch((e) => {
loading.value = false;
message.error(e.message);
});
})
.catch(() => {
});
};
watch(
watch(
() => props.visible,
(visible) => {
if (visible) {
if (props.data) {
assignObject(form, props.data);
const accessoryCategory = String(props.data.accessoryCategory);
const split = accessoryCategory?.split(' / ');
if (typeof split == 'object') {
form.accessoryCategory = split;
}
if (props.data.accessoryModelMultiple) {
form.accessoryModelMultiple = JSON.parse(
String(form.accessoryModelMultiple)
);
}
isUpdate.value = true;
if (visible) {
if (props.data) {
assignObject(form, props.data);
const accessoryCategory = String(props.data.accessoryCategory);
const split = accessoryCategory?.split(" / ");
if (typeof split == "object") {
form.accessoryCategory = split;
}
if (props.data.accessoryModelMultiple) {
form.accessoryModelMultiple = JSON.parse(
String(form.accessoryModelMultiple)
);
}
isUpdate.value = true;
} else {
isUpdate.value = false;
}
} else {
isUpdate.value = false;
resetFields();
}
} else {
resetFields();
}
}
);
);
</script>
<style lang="less"></style>
<style lang="less">
.tab-pane {
.tab-pane {
min-height: 300px;
}
.ml-10 {
}
.ml-10 {
margin-left: 5px;
}
.upload-text {
}
.upload-text {
margin-right: 70px;
}
}
</style>

View File

@@ -1,406 +1,406 @@
<template>
<div class="page">
<div class="ele-body">
<a-card :bordered="false" :body-style="{ padding: '16px' }">
<ele-pro-table
ref="tableRef"
row-key="accessoryId"
:columns="columns"
:datasource="datasource"
v-model:selection="selection"
:customRow="customRow"
tool-class="ele-toolbar-form"
:scroll="{ x: 3000 }"
class="sys-org-table"
>
<template #toolbar>
<search
@search="reload"
:selection="selection"
@add="openEdit"
@remove="removeBatch"
@batchMove="openMove"
/>
</template>
<template #bodyCell="{ column, record }">
<template v-if="column.key === 'accessoryName'">
<a-avatar
:size="30"
:src="`${record.accessoryAvatar}`"
style="margin-right: 4px"
:srcset="`https://file.wsdns.cn/${record.accessoryAvatar}`"
>
<template #icon>
<UserOutlined />
</template>
</a-avatar>
<a-tooltip title="查看详情">
<a href="#" @click="openInfo(record)">{{
record.accessoryName
}}</a>
</a-tooltip>
</template>
<template v-if="column.key === 'progress'">
<div v-for="(d, i) in progressDict" :key="i">
<span v-if="d.value === record.progress">{{ d.label }}</span>
</div>
</template>
<template v-if="column.key === 'accessoryType'">
<div v-for="(d, i) in JSON.parse(accessoryType)" :key="i">
<span v-if="d.value === record.accessoryType">{{
d.value
}}</span>
</div>
</template>
<template v-if="column.key === 'status'">
<a-tag v-if="record.status === 0" color="green">正常</a-tag>
<a-tag v-if="record.status === 1" color="red">待审核</a-tag>
<a-tag v-if="record.status === 2" color="purple">已驳回</a-tag>
</template>
<template v-if="column.key === 'nickname'">
<a-tooltip :title="`${record.nickname}`">
<a-avatar :src="record.userAvatar" size="small" />
</a-tooltip>
</template>
<template v-if="column.key === 'createTime'">
<a-tooltip :title="`${toDateString(record.createTime)}`">
{{ timeAgo(record.createTime) }}
</a-tooltip>
</template>
<template v-if="column.key === 'action'">
<a-space>
<a @click="openEdit(record)">修改</a>
<a-divider type="vertical" />
<a>库存分布</a>
<a-divider type="vertical" />
<a-popconfirm
title="确定要删除此记录吗?"
@confirm="remove(record)"
<div class="page">
<div class="ele-body">
<a-card :bordered="false" :body-style="{ padding: '16px' }">
<ele-pro-table
ref="tableRef"
row-key="accessoryId"
:columns="columns"
:datasource="datasource"
v-model:selection="selection"
:customRow="customRow"
tool-class="ele-toolbar-form"
:scroll="{ x: 3000 }"
class="sys-org-table"
>
<a class="ele-text-danger">删除</a>
</a-popconfirm>
</a-space>
</template>
</template>
</ele-pro-table>
</a-card>
<template #toolbar>
<search
@search="reload"
:selection="selection"
@add="openEdit"
@remove="removeBatch"
@batchMove="openMove"
/>
</template>
<template #bodyCell="{ column, record }">
<template v-if="column.key === 'accessoryName'">
<a-avatar
:size="30"
:src="`${record.accessoryAvatar}`"
style="margin-right: 4px"
:srcset="`https://file.wsdns.cn/${record.accessoryAvatar}`"
>
<template #icon>
<UserOutlined />
</template>
</a-avatar>
<a-tooltip title="查看详情">
<a href="#" @click="openInfo(record)">{{
record.accessoryName
}}</a>
</a-tooltip>
</template>
<template v-if="column.key === 'progress'">
<div v-for="(d, i) in progressDict" :key="i">
<span v-if="d.value === record.progress">{{ d.label }}</span>
</div>
</template>
<template v-if="column.key === 'accessoryType'">
<div v-for="(d, i) in JSON.parse(accessoryType)" :key="i">
<span v-if="d.value === record.accessoryType">{{
d.value
}}</span>
</div>
</template>
<template v-if="column.key === 'status'">
<a-tag v-if="record.status === 0" color="green">正常</a-tag>
<a-tag v-if="record.status === 1" color="red">待审核</a-tag>
<a-tag v-if="record.status === 2" color="purple">已驳回</a-tag>
</template>
<template v-if="column.key === 'nickname'">
<a-tooltip :title="`${record.nickname}`">
<a-avatar :src="record.userAvatar" size="small" />
</a-tooltip>
</template>
<template v-if="column.key === 'createTime'">
<a-tooltip :title="`${toDateString(record.createTime)}`">
{{ timeAgo(record.createTime) }}
</a-tooltip>
</template>
<template v-if="column.key === 'action'">
<a-space>
<a @click="openEdit(record)">修改</a>
<!-- <a-divider type="vertical" />-->
<!-- <a>库存分布</a>-->
<a-divider type="vertical" />
<a-popconfirm
title="确定要删除此记录吗?"
@confirm="remove(record)"
>
<a class="ele-text-danger">删除</a>
</a-popconfirm>
</a-space>
</template>
</template>
</ele-pro-table>
</a-card>
<!-- 编辑弹窗 -->
<AccessoryEdit
v-model:visible="showEdit"
:data="current"
:category-list="data"
:model-tree="data2"
:model-list="data2List"
@done="reload"
/>
<!-- 批量转移弹窗 -->
<!-- <AccessoryMove v-model:visible="showMove" :data="selection" @done="batchMove" />-->
<!-- 编辑弹窗 -->
<AccessoryEdit
v-model:visible="showEdit"
:data="current"
:category-list="data"
:model-tree="data2"
:model-list="data2List"
@done="reload"
/>
<!-- 批量转移弹窗 -->
<!-- <AccessoryMove v-model:visible="showMove" :data="selection" @done="batchMove" />-->
</div>
</div>
</div>
</template>
<script lang="ts" setup>
import { computed, createVNode, ref } from 'vue';
import { message, Modal } from 'ant-design-vue';
import {
import { computed, createVNode, ref } from "vue";
import { message, Modal } from "ant-design-vue";
import {
ExclamationCircleOutlined,
UserOutlined
} from '@ant-design/icons-vue';
import type { EleProTable } from 'ele-admin-pro';
import type {
} from "@ant-design/icons-vue";
import type { EleProTable } from "ele-admin-pro";
import type {
DatasourceFunction,
ColumnItem
} from 'ele-admin-pro/es/ele-pro-table/types';
import { toDateString, toTreeData } from 'ele-admin-pro';
import Search from './components/search.vue';
import AccessoryEdit from './components/accessory-edit.vue';
import {
} from "ele-admin-pro/es/ele-pro-table/types";
import { toDateString, toTreeData } from "ele-admin-pro";
import Search from "./components/search.vue";
import AccessoryEdit from "./components/accessory-edit.vue";
import {
pageAccessory,
removeAccessory,
removeBatchAccessory
} from '@/api/tower/accessory';
import { timeAgo } from 'ele-admin-pro';
import type { Accessory, AccessoryParam } from '@/api/tower/accessory/model';
import { useUserStore } from '@/store/modules/user';
import { Category } from '@/api/goods/category/model';
import { listCategory } from '@/api/goods/category';
import { listTowerModel } from '@/api/tower/model';
import { TowerModel } from '@/api/tower/model/model';
} from "@/api/tower/accessory";
import { timeAgo } from "ele-admin-pro";
import type { Accessory, AccessoryParam } from "@/api/tower/accessory/model";
import { useUserStore } from "@/store/modules/user";
import { Category } from "@/api/goods/category/model";
import { listCategory } from "@/api/goods/category";
import { listTowerModel } from "@/api/tower/model";
import { TowerModel } from "@/api/tower/model/model";
const userStore = useUserStore();
// 当前用户信息
const loginUser = computed(() => userStore.info ?? {});
const accessoryType = localStorage.getItem('accessoryType');
const userStore = useUserStore();
// 当前用户信息
const loginUser = computed(() => userStore.info ?? {});
const accessoryType = localStorage.getItem("accessoryType");
// 表格实例
const tableRef = ref<InstanceType<typeof EleProTable> | null>(null);
// 表格实例
const tableRef = ref<InstanceType<typeof EleProTable> | null>(null);
// 表格选中数据
const selection = ref<Accessory[]>([]);
// 当前编辑数据
const current = ref<Accessory | null>(null);
// 树形数据
const data = ref<Category[]>([]);
const data2 = ref<TowerModel[]>([]);
const data2List = ref<TowerModel[]>([]);
// 表格选中数据
const selection = ref<Accessory[]>([]);
// 当前编辑数据
const current = ref<Accessory | null>(null);
// 树形数据
const data = ref<Category[]>([]);
const data2 = ref<TowerModel[]>([]);
const data2List = ref<TowerModel[]>([]);
// 是否显示资产详情
const showInfo = ref(false);
// 是否显示编辑弹窗
const showEdit = ref(false);
// 是否显示批量移动弹窗
const showMove = ref(false);
// 加载状态
const loading = ref(true);
// 树展开的key
const expandedRowKeys = ref<number[]>([]);
// 树选中的key
const selectedRowKeys = ref<number[]>([]);
// 是否显示资产详情
const showInfo = ref(false);
// 是否显示编辑弹窗
const showEdit = ref(false);
// 是否显示批量移动弹窗
const showMove = ref(false);
// 加载状态
const loading = ref(true);
// 树展开的key
const expandedRowKeys = ref<number[]>([]);
// 树选中的key
const selectedRowKeys = ref<number[]>([]);
// 表格数据源
const datasource: DatasourceFunction = ({
page,
limit,
where,
orders,
filters
}) => {
// 表格数据源
const datasource: DatasourceFunction = ({
page,
limit,
where,
orders,
filters
}) => {
if (filters) {
where.progress = filters.progress;
where.accessorySource = filters.accessorySource;
where.accessoryType = filters.accessoryType;
where.status = filters.status;
where.progress = filters.progress;
where.accessorySource = filters.accessorySource;
where.accessoryType = filters.accessoryType;
where.status = filters.status;
}
return pageAccessory({
...where,
...orders,
page,
limit
...where,
...orders,
page,
limit
});
};
};
// 表格列配置
const columns = ref<ColumnItem[]>([
// 表格列配置
const columns = ref<ColumnItem[]>([
{
key: 'index',
width: 48,
align: 'center',
fixed: 'left',
hideInSetting: true,
customRender: ({ index }) => index + (tableRef.value?.tableIndex ?? 0)
key: "index",
width: 48,
align: "center",
fixed: "left",
hideInSetting: true,
customRender: ({ index }) => index + (tableRef.value?.tableIndex ?? 0)
},
{
title: '配件编号',
dataIndex: 'accessoryNo'
title: "配件编号",
dataIndex: "accessoryNo"
},
{
title: '配件名称',
dataIndex: 'accessoryName'
title: "生成厂家",
dataIndex: "accessoryName"
},
{
title: '配件分类',
dataIndex: 'accessoryCategory'
title: "配件分类",
dataIndex: "accessoryCategory"
},
{
title: '适用设备型号',
dataIndex: 'accessoryModel'
title: "适用设备型号",
dataIndex: "accessoryModel"
},
{
title: '配件规格',
dataIndex: 'accessorySpecs'
title: "配件规格",
dataIndex: "accessorySpecs"
},
{
title: '单价',
dataIndex: 'accessoryPrice'
title: "单价",
dataIndex: "accessoryPrice"
},
{
title: '配件单位',
dataIndex: 'accessoryUnit'
title: "购买数量",
dataIndex: "accessoryNum"
},
{
title: '库存总量',
dataIndex: 'accessoryStock'
title: "配件单位",
dataIndex: "accessoryUnit"
},
{
title: '产权单位名称',
dataIndex: 'companyName'
title: "产权单位名称",
dataIndex: "companyName"
},
{
title: '制造厂商',
dataIndex: 'manufactor'
title: "制造厂商",
dataIndex: "manufactor"
},
{
title: '制造厂商编号',
dataIndex: 'manufactorNo'
title: "制造厂商编号",
dataIndex: "manufactorNo"
},
{
title: '使用年限',
dataIndex: 'lifeYear'
title: "使用年限",
dataIndex: "lifeYear"
},
{
title: '出厂日期',
dataIndex: 'factoryDate',
customRender: ({ text }) => toDateString(text, 'yyyy-MM-dd')
title: "出厂日期",
dataIndex: "factoryDate",
customRender: ({ text }) => toDateString(text, "yyyy-MM-dd")
},
{
title: '报废日期',
dataIndex: 'scrapDate',
customRender: ({ text }) => toDateString(text, 'yyyy-MM-dd')
title: "报废日期",
dataIndex: "scrapDate",
customRender: ({ text }) => toDateString(text, "yyyy-MM-dd")
},
{
title: '操作',
key: 'action',
width: 200,
fixed: 'right',
align: 'center',
hideInSetting: true
title: "操作",
key: "action",
width: 200,
fixed: "right",
align: "center",
hideInSetting: true
}
]);
]);
/* 搜索 */
const reload = (where?: AccessoryParam) => {
/* 搜索 */
const reload = (where?: AccessoryParam) => {
console.log(where);
selection.value = [];
tableRef?.value?.reload({ where: where });
};
};
/* 打开编辑弹窗 */
const openEdit = (row?: Accessory) => {
/* 打开编辑弹窗 */
const openEdit = (row?: Accessory) => {
current.value = row ?? null;
showEdit.value = true;
};
};
/* 打开批量移动弹窗 */
const openMove = () => {
/* 打开批量移动弹窗 */
const openMove = () => {
showMove.value = true;
};
};
/* 打开用户详情弹窗 */
const openInfo = (row?: Accessory) => {
/* 打开用户详情弹窗 */
const openInfo = (row?: Accessory) => {
current.value = row ?? null;
showInfo.value = true;
};
};
/* 删除单个 */
const remove = (row: Accessory) => {
const hide = message.loading('请求中..', 0);
/* 删除单个 */
const remove = (row: Accessory) => {
const hide = message.loading("请求中..", 0);
removeAccessory(row.accessoryId)
.then((msg) => {
hide();
message.success(msg);
reload();
})
.catch((e) => {
hide();
message.error(e.message);
});
};
/* 批量转移 */
const batchMove = (userId) => {
console.log(userId, '批量转移0000');
console.log(selection.value);
};
/* 批量删除 */
const removeBatch = () => {
if (!selection.value.length) {
message.error('请至少选择一条数据');
return;
}
Modal.confirm({
title: '提示',
content: '确定要删除选中的记录吗?',
icon: createVNode(ExclamationCircleOutlined),
maskClosable: true,
onOk: () => {
const hide = message.loading('请求中..', 0);
removeBatchAccessory(
selection.value.map((d) => {
if (loginUser.value.userId === d.userId) {
return d.accessoryId;
}
})
)
.then((msg) => {
.then((msg) => {
hide();
message.success(msg);
reload();
})
.catch((e) => {
})
.catch((e) => {
hide();
message.error(e.message);
});
}
});
};
});
};
/* 查询 */
const query = () => {
/* 批量转移 */
const batchMove = (userId) => {
console.log(userId, "批量转移0000");
console.log(selection.value);
};
/* 批量删除 */
const removeBatch = () => {
if (!selection.value.length) {
message.error("请至少选择一条数据");
return;
}
Modal.confirm({
title: "提示",
content: "确定要删除选中的记录吗?",
icon: createVNode(ExclamationCircleOutlined),
maskClosable: true,
onOk: () => {
const hide = message.loading("请求中..", 0);
removeBatchAccessory(
selection.value.map((d) => {
if (loginUser.value.userId === d.userId) {
return d.accessoryId;
}
})
)
.then((msg) => {
hide();
message.success(msg);
reload();
})
.catch((e) => {
hide();
message.error(e.message);
});
}
});
};
/* 查询 */
const query = () => {
loading.value = true;
listCategory()
.then((list) => {
loading.value = false;
const eks: number[] = [];
list.forEach((d) => {
d.key = d.categoryId;
d.value = d.categoryId;
if (typeof d.categoryId === 'number') {
eks.push(d.categoryId);
}
.then((list) => {
loading.value = false;
const eks: number[] = [];
list.forEach((d) => {
d.key = d.categoryId;
d.value = d.categoryId;
if (typeof d.categoryId === "number") {
eks.push(d.categoryId);
}
});
expandedRowKeys.value = eks;
data.value = toTreeData({
data: list,
idField: "categoryId",
parentIdField: "parentId"
});
if (list.length) {
if (typeof list[0].categoryId === "number") {
selectedRowKeys.value = [list[0].categoryId];
}
} else {
selectedRowKeys.value = [];
}
})
.catch((e) => {
loading.value = false;
message.error(e.message);
});
expandedRowKeys.value = eks;
data.value = toTreeData({
data: list,
idField: 'categoryId',
parentIdField: 'parentId'
});
if (list.length) {
if (typeof list[0].categoryId === 'number') {
selectedRowKeys.value = [list[0].categoryId];
}
} else {
selectedRowKeys.value = [];
}
})
.catch((e) => {
loading.value = false;
message.error(e.message);
});
};
};
/* 自定义行属性 */
const customRow = (record: Accessory) => {
/* 自定义行属性 */
const customRow = (record: Accessory) => {
return {
// 行点击事件
onClick: () => {
// console.log(record);
},
// 行双击事件
onDblclick: () => {
openEdit(record);
}
// 行点击事件
onClick: () => {
// console.log(record);
},
// 行双击事件
onDblclick: () => {
openEdit(record);
}
};
};
};
query();
query();
</script>
<script lang="ts">
export default {
name: 'Accessory'
};
export default {
name: "Accessory"
};
</script>
<style lang="less" scoped>
.sys-org-table :deep(.ant-table-body) {
.sys-org-table :deep(.ant-table-body) {
overflow: auto !important;
overflow: overlay !important;
}
}
.sys-org-table :deep(.ant-table-pagination.ant-pagination) {
.sys-org-table :deep(.ant-table-pagination.ant-pagination) {
padding: 0 4px;
margin-bottom: 0;
}
}
</style>

View File

@@ -41,7 +41,6 @@
<a-form-item label="合同编号" v-bind="validateInfos.contactNumber">
<a-input
allow-clear
:maxlength="20"
placeholder="请输入合同编号"
v-model:value="form.contactNumber"
/>
@@ -54,37 +53,31 @@
valueFormat="YYYY-MM-DD"
/>
</a-form-item>
<a-form-item label="合同存档">
<a-switch :checked="form.isInStock" :checked-value="1" :un-checked-value="0" checked-children="已归档"
un-checked-children="未归档" @change="changeInStock" />
<a-form-item label="其他说明备注">
<a-input
allow-clear
v-model:value="form.remark"
/>
</a-form-item>
</a-col>
<a-col :md="8" :sm="24" :xs="24">
<a-form-item label="出租单位" v-bind="validateInfos.companyId">
<SelectCompany
:placeholder="`请选择出租单位`"
v-model:value="companyName"
@done="chooseCompany"
/>
{{ companyName }}
<!-- <SelectCompany-->
<!-- :placeholder="`请选择出租单位`"-->
<!-- v-model:value="companyName"-->
<!-- @done="chooseCompany"-->
<!-- />-->
</a-form-item>
<a-form-item label="承租单位" v-bind="validateInfos.customerId">
<SelectCustomer
:placeholder="`请选择承租单位`"
v-model:value="customerName"
@done="chooseCustomer"
/>
</a-form-item>
<a-form-item label="合同金额">
<a-input
allow-clear
:maxlength="20"
placeholder="请输入合同金额"
v-model:value="form.contractAmount"
>
<template #addonAfter>
<span></span>
</template>
</a-input>
{{ customerName }}
<!-- <SelectCustomer-->
<!-- :placeholder="`请选择承租单位`"-->
<!-- v-model:value="customerName"-->
<!-- @done="chooseCustomer"-->
<!-- />-->
</a-form-item>
<a-form-item label="截止日期">
<a-date-picker
@@ -94,6 +87,10 @@
valueFormat="YYYY-MM-DD"
/>
</a-form-item>
<a-form-item label="合同存档">
<a-switch :checked="form.isInStock" :checked-value="1" :un-checked-value="0" checked-children="已归档"
un-checked-children="未归档" @change="changeInStock" />
</a-form-item>
</a-col>
<a-col :md="8" :sm="24" :xs="24">
<a-form-item label="业务负责人">
@@ -123,22 +120,48 @@
</template>
</a-input>
</a-form-item>
<a-form-item label="是否自动结算">
<a-switch :checked="form.autoSettle" :checked-value="1" :un-checked-value="0" checked-children=""
un-checked-children="" @change="changeAutoSettle" />
<a-form-item label="是否自动结算">
<a-switch :checked="form.autoSettle" :checked-value="1" :un-checked-value="0" checked-children=""
un-checked-children="" @change="changeAutoSettle" />
</a-form-item>
</a-col>
</a-row>
<a-row :gutter="16">
<a-col :span="8">
<a-form-item label="实际结算金额汇总">
<p style="margin-bottom: 0">{{ form.totalSettleAmount }}</p>
</a-form-item>
</a-col>
<a-col :span="8">
<a-form-item label="实收金额汇总">
<p style="margin-bottom: 0">{{ form.totalIncomeAmount }}</p>
</a-form-item>
</a-col>
<a-col :span="8">
<a-form-item label="欠收金额汇总">
<p style="margin-bottom: 0">{{ form.totalSettleAmount - form.totalIncomeAmount }}</p>
</a-form-item>
</a-col>
</a-row>
</a-form>
<div class="flex flex-col justify-start justify-start"
style="padding: 1rem 0;border-top: 1px solid #dcdfe6; border-bottom: 1px solid #dcdfe6">
<div class="flex justify-between items-center">
<span>合同电子存档</span>
<UploadFile @update:value="uploadFile" />
</div>
<div class="flex justify-start flex-wrap items-start">
<a-tag closable @close="delFile(index)" v-for="(item, index) in contractFileList" :key="index">{{ item.path }}
</a-tag>
<div>
<p>合同电子存档</p>
<div class="flex justify-start">
<a-upload
v-model:file-list="fileList"
name="file"
action="https://file.wsdns.cn/api/file/image"
:headers="{ Authorization: token }"
@change="onFileUpload"
>
<a-button>
<upload-outlined />
上传
</a-button>
</a-upload>
</div>
</div>
</div>
<div class="flex justify-start items-center"
@@ -153,9 +176,12 @@
<a-col :span="3" class="p-05 border-r-white">
<span>设备名称</span>
</a-col>
<a-col :span="3" class="p-05 border-r-white">
<a-col :span="2" class="p-05 border-r-white">
<span>规格型号</span>
</a-col>
<a-col :span="3" class="p-05 border-r-white">
<span>备案编号</span>
</a-col>
<a-col :span="2" class="p-05 border-r-white">
<span>签订数量</span>
</a-col>
@@ -163,21 +189,21 @@
<span>计划租期()</span>
</a-col>
<a-col :span="2" class="p-05 border-r-white">
<span>租金()</span>
<span>租金(/)</span>
</a-col>
<a-col :span="2" class="p-05 border-r-white">
<span>进退场费()</span>
<span>进退场费(/)</span>
</a-col>
<a-col :span="2" class="p-05 border-r-white">
<span>劳务费用()</span>
<span>劳务费用(/)</span>
</a-col>
<a-col :span="2" class="p-05 border-r-white">
<span>其他费用()</span>
<span>其他费用(/)</span>
</a-col>
<a-col :span="2" class="p-05 border-r-white">
<span>预埋费()</span>
<span>预埋费(/)</span>
</a-col>
<a-col :span="2" class="p-05 border-r-white">
<a-col :span="1" class="p-05 border-r-white">
<span>备注</span>
</a-col>
<a-col :span="1" class="p-05">
@@ -192,20 +218,18 @@
<a-row class="text-center" v-for="(item, index) in contractEquipmentList"
:key="index">
<a-col :span="3" class="p-05 border-r-white">
<a-select placeholder="必选项" style="width: 100%" size="small"
v-model:value="contractEquipmentList[index].equipmentName">
<a-select-option v-for="(item, index) in equipmentList" :key="index" :value="item.name">{{ item.name
}}
<a-select placeholder="必选项" style="width: 100%" size="small" @change="changeEquipment($event, index)"
v-model:value="contractEquipmentList[index].equipmentId">
<a-select-option v-for="(item, index) in equipmentList" :key="index" :value="item.equipmentId">
{{ item.name }}({{ item.model }})
</a-select-option>
</a-select>
</a-col>
<a-col :span="2" class="p-05 border-r-white">
<a-input v-model:value="contractEquipmentList[index].equipmentModel" size="small" readonly/>
</a-col>
<a-col :span="3" class="p-05 border-r-white">
<a-select placeholder="必选项" style="width: 100%" size="small"
v-model:value="contractEquipmentList[index].equipmentModel">
<a-select-option v-for="(item, index) in equipmentList" :key="index" :value="item.model">{{ item.model
}}
</a-select-option>
</a-select>
<a-input v-model:value="contractEquipmentList[index].filingNo" size="small" readonly/>
</a-col>
<a-col :span="2" class="p-05 border-r-white">
<a-input v-model:value="contractEquipmentList[index].num" size="small" placeholder="必填项" type="number">
@@ -233,10 +257,10 @@
type="number" />
</a-col>
<a-col :span="2" class="p-05 border-r-white">
<a-input v-model:value="contractEquipmentList[index].preBuryAmount" size="small" placeholder="必填项"
<a-input v-model:value="contractEquipmentList[index].preBuryAmount" size="small"
type="number" />
</a-col>
<a-col :span="2" class="p-05 border-r-white">
<a-col :span="1" class="p-05 border-r-white">
<a-input v-model:value="contractEquipmentList[index].remark" size="small" placeholder="可选项" />
</a-col>
<a-col :span="1" class="p-05">
@@ -262,7 +286,7 @@
<script lang="ts" setup>
import { ref, reactive, watch, computed } from "vue";
import { Form, message } from "ant-design-vue";
import { Form, message, UploadFile } from "ant-design-vue";
import { assignObject } from "ele-admin-pro";
import { updateContract, addContract } from "@/api/tower/contract";
import { useUserStore } from "@/store/modules/user";
@@ -273,7 +297,7 @@ import { ContractFile } from "@/api/tower/contractFile/model";
import {
PlusOutlined,
UnorderedListOutlined,
CloseCircleOutlined
CloseCircleOutlined, UploadOutlined
} from "@ant-design/icons-vue";
import { ContractEquipment } from "@/api/tower/contractEquipment/model";
import { TowerModel } from "@/api/tower/model/model";
@@ -282,10 +306,16 @@ import { addBatchContractFile, listContractFile } from "@/api/tower/contractFile
import { addBatchContractEquipment, listContractEquipment } from "@/api/tower/contractEquipment";
import { Company } from "@/api/system/company/model";
import { Customer } from "@/api/oa/customer/model";
import { listTowerEquipment } from "@/api/tower/equipment";
import { TowerEquipment } from "@/api/tower/equipment/model";
import { TOKEN_STORE_NAME } from "@/config/setting";
import { FileItem } from "ele-admin-pro/es/ele-file-list/types";
import { Equipment } from "@/api/apps/equipment/model";
const userStore = useUserStore();
// 当前用户信息
const loginUser = computed(() => userStore.info ?? {});
const token = localStorage.getItem(TOKEN_STORE_NAME);
const now = dayjs().format("YYYY-MM-DD HH:mm:ss");
@@ -322,8 +352,13 @@ const form = reactive<Contract>({
endDate: "",
contractAmount: undefined,
contactAgreeAmount: undefined,
totalSettleAmount: 0,
totalIncomeAmount: 0,
isInStock: 0,
autoSettle: 0
autoSettle: 0,
payRate: undefined,
remark: "",
fileList: "[]"
});
/* 更新visible */
@@ -340,13 +375,13 @@ const rules = reactive({
trigger: "blur"
}
],
contactNumber: [
{
required: true,
message: "请输入合同编号",
trigger: "blur"
}
],
// contactNumber: [
// {
// required: true,
// message: "请输入合同编号",
// trigger: "blur"
// }
// ],
companyId: [
{
required: true,
@@ -365,8 +400,15 @@ const rules = reactive({
const projectName = ref<string>("");
const chooseProject = (res) => {
// console.log(res)
projectName.value = res.projectName;
form.projectId = res.projectId;
companyName.value = res.companyName;
form.companyId = res.companyId;
customerName.value = res.customerName;
form.customerId = res.customerId;
};
const companyName = ref<string>();
@@ -391,6 +433,25 @@ const changeAutoSettle = (checked) => {
};
const fileList = ref<FileItem[]>([]);
interface FileInfo {
file: FileItem;
fileList: FileItem[];
}
const onFileUpload = (info: FileInfo) => {
let resFileList = [...info.fileList];
fileList.value = resFileList.map((file) => {
if (file.response) {
// Component will show file.url as link
file.url = file.response.url;
}
return file;
});
form.fileList = JSON.stringify(fileList.value);
};
const contractFileList = ref<ContractFile[]>([]);
const uploadFile = path => {
contractFileList.value.push({ path, contractId: 0, userId: loginUser.value.userId });
@@ -401,17 +462,22 @@ const delFile = index => {
};
const getContractFileList = async () => {
contractFileList.value = await listContractFile({ contactId: props.data?.contractId });
contractFileList.value = await listContractFile({ contractId: props.data?.contractId });
};
const equipmentList = ref<TowerModel[]>([]);
const equipmentList = ref<TowerEquipment[]>([]);
const getEquipmentList = async () => {
equipmentList.value = await listTowerModel();
equipmentList.value = await listTowerEquipment();
};
const equipmentModelList = ref<TowerModel[]>([]);
const getEquipmentModelList = async () => {
equipmentModelList.value = await listTowerModel();
};
const contractEquipmentList = ref<ContractEquipment[]>([]);
const getContractEquipmentList = async () => {
contractEquipmentList.value = await listContractEquipment({ contactId: props.data?.contractId });
contractEquipmentList.value = await listContractEquipment({ contractId: props.data?.contractId });
};
const chooseEquipmentName = (res, index) => {
@@ -426,6 +492,7 @@ const addEquipment = () => {
contractEquipmentList.value.push({
contractEquipmentId: null,
contractId: null,
equipmentId: undefined,
equipmentName: "",
equipmentModel: "",
num: null,
@@ -456,8 +523,7 @@ const save = () => {
...form
};
for (let i = 0; i < contractEquipmentList.value.length; i++) {
if (!contractEquipmentList.value[i].equipmentName) {
console.log(contractEquipmentList.value[i].equipmentName);
if (!contractEquipmentList.value[i].equipmentId) {
loading.value = false;
message.error("请选择设备");
return;
@@ -497,11 +563,6 @@ const save = () => {
message.error("请输入其他费用");
return;
}
if (contractEquipmentList.value[i].preBuryAmount === null) {
loading.value = false;
message.error("请输入预埋费");
return;
}
}
// 转字符串
const saveOrUpdate = isUpdate.value ? updateContract : addContract;
@@ -509,11 +570,11 @@ const save = () => {
loading.value = false;
message.error(e.message);
});
const contractId = res.data;
if (contractFileList.value.length > 0) await saveFileList(contractId);
const contractId = res?.data;
// if (contractFileList.value.length > 0) await saveFileList(contractId);
if (contractEquipmentList.value.length > 0) await saveEquipmentList(contractId);
loading.value = false;
message.success(res.message);
message.success(res?.message);
updateVisible(false);
emit("done");
@@ -536,11 +597,19 @@ const saveEquipmentList = async (contractId) => {
await addBatchContractEquipment(contractEquipmentList.value);
};
const changeEquipment = (equipmentId, index) => {
const equip = equipmentList.value.filter(item => item.equipmentId === equipmentId)[0]
console.log(equip)
contractEquipmentList.value[index].equipmentModel = equip.model
contractEquipmentList.value[index].filingNo = equip.filingNo
}
watch(
() => props.visible,
(visible) => {
if (visible) {
getEquipmentList();
getEquipmentModelList();
if (props.data) {
loading.value = false;
assignObject(form, props.data);
@@ -550,11 +619,16 @@ watch(
projectName.value = props.data.projectName;
customerName.value = props.data.customerName;
companyName.value = props.data.companyName;
if (props.data.fileList) {
fileList.value = JSON.parse(props.data.fileList);
}
} else {
isUpdate.value = false;
}
} else {
projectName.value = customerName.value = companyName.value = "";
contractFileList.value = [];
fileList.value = [];
resetFields();
}
}

View File

@@ -64,9 +64,19 @@
<template v-if="column.key === 'workerAmountSum'">
<span>{{ record.rentMonth * record.workerAmount }}</span>
</template>
<template v-if="column.key === 'otherAmountCalMode'">
<a-select style="width: 100px" size="small"
v-model:value="record.otherAmountCalMode">
<a-select-option :value="0">按月</a-select-option>
<a-select-option :value="1">一次</a-select-option>
</a-select>
</template>
<template v-if="column.key === 'otherAmount'">
<a-input v-model:value="record.otherAmount" type="number" />
</template>
<template v-if="column.key === 'preBuryAmount'">
<a-input v-model:value="record.preBuryAmount" type="number" />
</template>
<template v-if="column.key === 'remark'">
<a-input v-model:value="record.remark" />
</template>
@@ -94,7 +104,9 @@
<a-table-summary-cell>
{{ totals.workerAmountSum }}
</a-table-summary-cell>
<a-table-summary-cell />
<a-table-summary-cell>
{{ totals.otherAmountSum }}
</a-table-summary-cell>
<a-table-summary-cell />
</a-table-summary-row>
</template>
@@ -167,6 +179,9 @@ import { ContractSettleRule } from "@/api/tower/contractSettle/rule/model";
import { updateContract } from "@/api/tower/contract";
import { addBatchContractSettleEquipment, listContractSettleEquipment } from "@/api/tower/contractSettle/equipment";
import { addBatchContractSettleRule, listContractSettleRule } from "@/api/tower/contractSettle/rule";
import { TowerEquipment } from "@/api/tower/equipment/model";
import { listContractEquipment } from "@/api/tower/contractEquipment";
import { ContractEquipment } from "@/api/tower/contractEquipment/model";
const userStore = useUserStore();
@@ -199,7 +214,7 @@ const maxable = ref(true);
const showSelectEquip = ref<Boolean>(false);
const onSelectEquip = data => {
const onSelectEquip = (data: TowerEquipment) => {
addEquipment(data);
};
@@ -275,6 +290,17 @@ const equipmentColumns = ref<ColumnItem[]>([
dataIndex: "otherAmount",
key: "otherAmount"
},
{
title: "其他费用结算模式",
dataIndex: "otherAmountCalMode",
key: "otherAmountCalMode",
width: 100
},
{
title: "预埋费(元)",
dataIndex: "preBuryAmount",
key: "preBuryAmount"
},
{
title: "备注",
dataIndex: "remark",
@@ -286,23 +312,49 @@ const equipmentColumns = ref<ColumnItem[]>([
key: "action"
}
]);
const equipmentList = ref<ContractEquipment[]>([]);
const getEquipmentList = async () => {
equipmentList.value = await listContractEquipment({ contractId: props.data?.contractId });
};
const settleEquipmentList = ref<ContractSettleEquipment[]>([]);
const getSettleEquipmentList = async () => {
settleEquipmentList.value = await listContractSettleEquipment({ contractId: contract.contractId });
if (settleEquipmentList.value.length === 0) {
equipmentList.value.forEach(item => {
addEquipment(item, item.planRentMonth, item.rentAmount, item.inOutAmount, item.workerAmount, item.otherAmount, item.otherAmount);
});
}
};
const addEquipment = data => {
const contractEquipmentList = ref<ContractEquipment[]>([]);
const getContractEquipmentList = async () => {
contractEquipmentList.value = await listContractEquipment({ contractId: props.data?.contractId });
contractEquipmentList.value.forEach(data => {
data.name = data.equipmentName
data.model = data?.equipmentModel
addEquipment(data);
});
};
const addEquipment = (data, rentMonth = 0, rentAmount = 0, inOutAmount = 0, workerAmount = 0, otherAmount = 0, preBuryAmount = 0) => {
settleEquipmentList.value = [...settleEquipmentList.value, {
contractSettleId: 0,
equipmentId: data.equipmentId,
contractId: props.data?.contractId,
equipmentName: data.name,
equipmentModel: data.model,
factoryNo: data.factoryNo,
filingNo: data.filingNo,
equipmentNo: data.equipmentNo,
rentMonth: 0,
rentAmount: 0,
inOutAmount: 0,
workerAmount: 0,
otherAmount: 0,
rentMonth,
rentAmount,
inOutAmount,
workerAmount,
otherAmount,
otherAmountCalMode: 0,
preBuryAmount,
remark: "",
userId: loginUser.value.userId
}];
@@ -364,12 +416,15 @@ const delRule = index => {
const totals = computed(() => {
let rentAmountSum = 0;
let workerAmountSum = 0;
let otherAmountSum = 0;
settleEquipmentList.value.forEach(({ rentMonth, rentAmount, workerAmount }) => {
settleEquipmentList.value.forEach(({ rentMonth, rentAmount, workerAmount, otherAmountCalMode, otherAmount }) => {
rentAmountSum += rentMonth * rentAmount;
workerAmountSum += rentMonth * workerAmount;
if (otherAmountCalMode === 0) otherAmountSum += rentMonth * otherAmount;
else otherAmountSum += otherAmount;
});
return { rentAmountSum, workerAmountSum };
return { rentAmountSum, workerAmountSum, otherAmountSum };
});
/* 更新visible */
@@ -377,12 +432,6 @@ const updateVisible = (value: boolean) => {
emit("update:visible", value);
};
const equipmentList = ref<TowerModel[]>([]);
const getEquipmentList = async () => {
equipmentList.value = await listTowerModel();
};
/* 保存编辑 */
const save = () => {
if (contract.settleMethod === undefined) {
@@ -408,28 +457,30 @@ const save = () => {
}
}
loading.value = true;
updateContract(contract);
addBatchContractSettleEquipment(settleEquipmentList.value);
addBatchContractSettleRule(settleRuleList.value);
loading.value = false;
// message.success(res.message);
updateVisible(false);
emit("done");
Promise.all([updateContract(contract), addBatchContractSettleEquipment(settleEquipmentList.value), addBatchContractSettleRule(settleRuleList.value)])
.then(() => {
loading.value = false;
// message.success(res.message);
updateVisible(false);
emit("done");
});
};
watch(
() => props.visible,
(visible) => {
async (visible) => {
if (visible) {
for (let i = 2; i < 28; i++) dateList.value.push(i);
getEquipmentList();
await getEquipmentList();
settleEquipmentList.value = [];
if (props.data) {
loading.value = false;
assignObject(contract, props.data);
getSettleEquipmentList();
getSettleRuleList();
await getSettleEquipmentList();
await getSettleRuleList();
isUpdate.value = true;
} else {
await getContractEquipmentList();
isUpdate.value = false;
}
}

View File

@@ -27,6 +27,12 @@
{{ timeAgo(record.createTime) }}
</a-tooltip>
</template>
<template v-if="column.key === 'needPay'">
<span v-if="record.payRate && record.totalSettleAmount">{{ (record.payRate / 100 * record.totalSettleAmount).toFixed(2) }}</span>
</template>
<template v-if="column.key === 'totalUnReceivableAmount'">
<p>{{ record.totalSettleAmount - record.totalIncomeAmount }}</p>
</template>
<template v-if="column.key === 'action'">
<a-space>
<a @click="openSettle(record)">合同结算设置</a>
@@ -131,9 +137,8 @@
},
{
title: '合同编号',
dataIndex: 'contractNumber',
key: 'contractNumber',
ellipsis: true
dataIndex: 'contactNumber',
key: 'contactNumber'
},
{
title: '项目名称',
@@ -141,11 +146,24 @@
},
{
title: '预计产值',
dataIndex: ''
dataIndex: 'contractAmount'
},
{
title: '结算产值',
dataIndex: ''
title: '实际结算金额',
dataIndex: 'totalSettleAmount'
},
{
title: '实际收款金额',
dataIndex: 'totalIncomeAmount'
},
{
title: '累计开票金额',
dataIndex: 'totalInvoicingAmount'
},
{
title: '欠收金额',
dataIndex: 'totalUnReceivableAmount',
key: 'totalUnReceivableAmount'
},
{
title: '业务联系人',
@@ -170,7 +188,6 @@
/* 搜索 */
const reload = (where?: ContractParam) => {
console.log(where);
selection.value = [];
tableRef?.value?.reload({ where: where });
};

View File

@@ -0,0 +1,102 @@
<!-- 用户编辑弹窗 -->
<template>
<ele-modal
:width="600"
:visible="visible"
:maskClosable="false"
:title="`导入客户`"
:body-style="{ paddingBottom: '28px' }"
@update:visible="updateVisible"
:footer="null"
>
<a-upload-dragger
name="file"
:show-upload-list="false"
accept=".xls,.xlsx"
:before-upload="handleImport"
>
<p class="ant-upload-drag-icon">
<InboxOutlined />
</p>
<p class="ant-upload-text">单击或拖动文件到此区域进行上传</p>
<p class="ant-upload-hint" style="max-width: 550px">
提示附件上传中请不要做任何操作 支持的文件类型为*.xls, *.xlsx!
</p>
</a-upload-dragger>
<div style="margin: 20px auto; display: flex; justify-content: center">
<a
href="http://1.14.159.185:10042/template/customer_template.xlsx"
target="_blank"
>下载客户导入模板</a
>
</div>
</ele-modal>
</template>
<script lang="ts" setup>
import { InboxOutlined } from "@ant-design/icons-vue";
import { message } from "ant-design-vue";
import { addBatchTowerEquipment } from "@/api/tower/equipment";
import { read, utils } from "xlsx";
import { ref } from "vue";
import type { Customer } from '@/api/oa/customer/model';
import { addBatchCustomer } from "@/api/oa/customer";
const emit = defineEmits<{
(e: "done"): void;
(e: "update:visible", visible: boolean): void;
}>();
/* 更新visible */
const updateVisible = (value: boolean) => {
emit("update:visible", value);
};
// 导入的数据
const importData = ref<Customer[]>([]);
const handleImport = (file: File) => {
if (
![
"application/vnd.ms-excel",
"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
].includes(file.type)
) {
message.error("只能选择 excel 文件");
return false;
}
if (file.size / 1024 / 1024 > 20) {
message.error("大小不能超过 20MB");
return false;
}
const reader = new FileReader();
importData.value = []
reader.onload = (e) => {
const data = new Uint8Array(e.target?.result as any);
const workbook = read(data, { type: "array" });
const sheetNames = workbook.SheetNames;
const worksheet = workbook.Sheets[sheetNames[0]];
// 解析成二维数组
const aoa = utils.sheet_to_json<string[]>(worksheet, { header: 1 });
console.log(aoa);
aoa.slice(1).map((d) => {
if (d[1] && d[0]) {
importData.value.push({
name: d[0],
creditCode: d[1],
fullName: d[2],
address: d[3],
contact: d[4],
telPhone: d[5],
phone: d[6],
});
}
});
addBatchCustomer(importData.value).then(() => {
message.success("导入成功");
updateVisible(false);
emit("done");
});
};
reader.readAsArrayBuffer(file);
return false;
};
</script>

View File

@@ -7,15 +7,11 @@
</template>
<span>添加客户</span>
</a-button>
<a-upload
:before-upload="importBatch"
:show-upload-list="false"
accept=".xls,.xlsx"
>
<a-button class="ele-btn-icon"> <DownloadOutlined />批量导入 </a-button>
</a-upload>
<a-button class="ele-btn-icon">
<span>下载客户模板</span>
<a-button class="ele-btn-icon" @click="openImport">
<template #icon>
<UploadOutlined />
</template>
<span>导入客户</span>
</a-button>
<a-upload
:before-upload="importBatch"
@@ -50,6 +46,7 @@
@search="search"
/>
</a-space>
<Import v-model:visible="showImport" @done="search" />
</template>
<script lang="ts" setup>
@@ -65,6 +62,7 @@
import { utils, read } from 'xlsx';
// import { assignObject } from 'ele-admin-pro';
import { message } from 'ant-design-vue/es';
import Import from "@/views/tower/customer/components/import.vue";
const props = withDefaults(
defineProps<{
@@ -216,6 +214,11 @@
search();
};
const showImport = ref(false)
const openImport = () => {
showImport.value = true;
};
watch(
() => props.selection,
() => {}

File diff suppressed because it is too large Load Diff

View File

@@ -25,87 +25,90 @@
</a-upload-dragger>
<div style="margin: 20px auto; display: flex; justify-content: center">
<a
href="https://file.wsdns.cn/download/20230523/2f5ffa06b0684e138184c6786f6fbb68.xlsx"
href="http://1.14.159.185:10042/template/2f5ffa06b0684e138184c6786f6fbb68.xlsx"
target="_blank"
>下载设备导入模板</a
>下载设备导入模板</a
>
</div>
</ele-modal>
</template>
<script lang="ts" setup>
import { InboxOutlined } from '@ant-design/icons-vue';
import { message } from 'ant-design-vue';
import { addBatchTowerEquipment } from '@/api/tower/equipment';
import { TowerEquipment } from '@/api/tower/equipment/model';
import { read, utils } from 'xlsx';
import { ref } from 'vue';
import { InboxOutlined } from "@ant-design/icons-vue";
import { message } from "ant-design-vue";
import { addBatchTowerEquipment } from "@/api/tower/equipment";
import { TowerEquipment } from "@/api/tower/equipment/model";
import { read, utils } from "xlsx";
import { ref } from "vue";
import dayjs from "dayjs";
const emit = defineEmits<{
(e: 'done'): void;
(e: 'update:visible', visible: boolean): void;
}>();
const emit = defineEmits<{
(e: "done"): void;
(e: "update:visible", visible: boolean): void;
}>();
/* 更新visible */
const updateVisible = (value: boolean) => {
emit('update:visible', value);
};
/* 更新visible */
const updateVisible = (value: boolean) => {
emit("update:visible", value);
};
// 导入的数据
const importData = ref<TowerEquipment[]>([]);
const handleImport = (file: File) => {
if (
![
'application/vnd.ms-excel',
'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
].includes(file.type)
) {
message.error('只能选择 excel 文件');
return false;
}
if (file.size / 1024 / 1024 > 20) {
message.error('大小不能超过 20MB');
return false;
}
const reader = new FileReader();
reader.onload = (e) => {
const data = new Uint8Array(e.target?.result as any);
const workbook = read(data, { type: 'array' });
const sheetNames = workbook.SheetNames;
const worksheet = workbook.Sheets[sheetNames[0]];
// 解析成二维数组
const aoa = utils.sheet_to_json<string[]>(worksheet, { header: 1 });
console.log(aoa);
aoa.slice(1).map((d) => {
const array = ['闲置', '报废', '注销', '转卖'];
importData.value.push({
status: array.indexOf(d[0]),
name: d[1],
factoryNo: d[2],
model: d[3],
manufactor: d[4],
buyDate: d[5],
filingNo: d[6],
factoryDate: d[7],
company: d[8],
source: d[9],
warehouse: d[10],
users: d[11],
equipmentNo: d[12],
ratedLoad: d[13],
maxLiftingHeight: d[14],
armLength: d[15],
currentLocation: d[16],
machineNo: d[17]
});
});
addBatchTowerEquipment(importData.value).then(() => {
message.success('导入成功');
updateVisible(false);
emit('done');
});
};
reader.readAsArrayBuffer(file);
// 导入的数据
const importData = ref<TowerEquipment[]>([]);
const handleImport = (file: File) => {
if (
![
"application/vnd.ms-excel",
"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
].includes(file.type)
) {
message.error("只能选择 excel 文件");
return false;
}
if (file.size / 1024 / 1024 > 20) {
message.error("大小不能超过 20MB");
return false;
}
const reader = new FileReader();
importData.value = []
reader.onload = (e) => {
const data = new Uint8Array(e.target?.result as any);
const workbook = read(data, { type: "array" });
const sheetNames = workbook.SheetNames;
const worksheet = workbook.Sheets[sheetNames[0]];
// 解析成二维数组
const aoa = utils.sheet_to_json<string[]>(worksheet, { header: 1 });
aoa.slice(1).map((d) => {
const array = ["闲置", "报废", "注销", "转卖", "在用", "停工"];
if (d[1]) {
importData.value.push({
name: d[1],
filingNo: d[2],
factoryNo: d[3],
model: d[4],
manufactor: d[5],
company: d[6],
factoryDate: d[7],
status: array.indexOf(d[8]),
lifeYear: d[9],
buyDate: d[10],
source: d[11],
warehouse: d[12],
users: d[13],
equipmentNo: d[14],
ratedLoad: d[15],
maxLiftingHeight: d[16],
armLength: d[17],
scrapDate: (d[7] && d[9]) ? (dayjs(d[7] ).add(parseInt(d[9]) , 'year').format('YYYY-MM-DD')) : ''
});
}
});
addBatchTowerEquipment(importData.value).then(() => {
message.success("导入成功");
updateVisible(false);
emit("done");
});
};
reader.readAsArrayBuffer(file);
return false;
};
</script>

View File

@@ -0,0 +1,44 @@
<template>
<ele-modal
width="80%"
:visible="visible"
:maskClosable="false"
:maxable="maxable"
title="历史项目"
:body-style="{ paddingBottom: '28px' }"
@update:visible="updateVisible"
>
<a-card v-for="(item, index) in data?.projectList" :key="index">
<a-descriptions :title="item.projectName">
<a-descriptions-item label="项目地址">{{ item.projectRegion + item.projectAddress }}</a-descriptions-item>
<a-descriptions-item label="主管部门">{{ item.competentDepartment }}</a-descriptions-item>
<a-descriptions-item label="租赁单位">{{ item.companyName }}</a-descriptions-item>
<a-descriptions-item label="承租单位">{{ item.customerName }}</a-descriptions-item>
</a-descriptions>
</a-card>
</ele-modal>
</template>
<script lang="ts" setup>
import { ref } from "vue";
import { TowerEquipment } from "@/api/tower/equipment/model";
import { WORKSHEET_WORK_TYPE } from "@/api/tower/worksheet/model";
const props = defineProps<{
// 弹窗是否打开
visible: boolean;
// 修改回显的数据
data?: TowerEquipment | null;
}>();
const emit = defineEmits<{
(e: "update:visible", visible: boolean): void;
}>();
const maxable = ref(true);
const updateVisible = (value: boolean) => {
emit("update:visible", value);
};
</script>

View File

@@ -1,203 +1,237 @@
<!-- 搜索表单 -->
<template>
<a-space :size="10" style="flex-wrap: wrap">
<a-button type="primary" class="ele-btn-icon" @click="add">
<template #icon>
<PlusOutlined />
</template>
<span>添加设备</span>
</a-button>
<a-button
danger
type="primary"
class="ele-btn-icon"
:disabled="selection.length === 0"
@click="removeBatch"
>
<template #icon>
<DeleteOutlined />
</template>
<span>批量删除</span>
</a-button>
<a-button class="ele-btn-icon" @click="openImport">
<template #icon>
<UploadOutlined />
</template>
<span>导入设备</span>
</a-button>
<a-button class="ele-btn-icon" @click="handleExport">
<template #icon>
<DownloadOutlined />
</template>
<span>导出设备</span>
</a-button>
<a-radio-group v-model:value="status" @change="handleStatus">
<a-radio-button :value="1">报废</a-radio-button>
<a-radio-button :value="2">注销</a-radio-button>
<a-radio-button :value="0">恢复</a-radio-button>
<a-radio-button :value="3">转卖</a-radio-button>
</a-radio-group>
<a-input-search
allow-clear
placeholder="请输入关键词"
v-model:value="searchText"
@pressEnter="search"
@search="search"
/>
<!-- 导入弹窗 -->
<Import v-model:visible="showImport" @done="search" />
</a-space>
<a-space :size="10" style="flex-wrap: wrap">
<a-button type="primary" class="ele-btn-icon" @click="add">
<template #icon>
<PlusOutlined />
</template>
<span>添加设备</span>
</a-button>
<a-button
danger
type="primary"
class="ele-btn-icon"
:disabled="selection.length === 0"
@click="removeBatch"
>
<template #icon>
<DeleteOutlined />
</template>
<span>批量删除</span>
</a-button>
<a-button class="ele-btn-icon" @click="openImport">
<template #icon>
<UploadOutlined />
</template>
<span>导入设备</span>
</a-button>
<a-button class="ele-btn-icon" @click="handleExport">
<template #icon>
<DownloadOutlined />
</template>
<span>导出设备</span>
</a-button>
<a-radio-group v-model:value="status" @change="handleStatus" :disabled="selection.length === 0">
<a-radio-button :value="0">闲置</a-radio-button>
<a-radio-button :value="1">报废</a-radio-button>
<a-radio-button :value="2">注销</a-radio-button>
<a-radio-button :value="3">转卖</a-radio-button>
<a-radio-button :value="4">在用</a-radio-button>
<a-radio-button :value="5">停工</a-radio-button>
</a-radio-group>
<a-select placeholder="设备状态筛选" style="width: 250px" @change="search"
@clear="search"
v-model:value="statusFilter" allow-clear>
<a-select-option :value="null">全部</a-select-option>
<a-select-option :value="0">闲置</a-select-option>
<a-select-option :value="1">报废</a-select-option>
<a-select-option :value="2">注销</a-select-option>
<a-select-option :value="3">转卖</a-select-option>
<a-select-option :value="4">在用</a-select-option>
<a-select-option :value="5">停工</a-select-option>
</a-select>
<a-input-search
allow-clear
placeholder="请输入关键词"
v-model:value="searchText"
@pressEnter="search"
@search="search"
/>
<a-input-search
:min="0"
type="number"
allow-clear
placeholder="剩余可用年份筛选"
v-model:value="yearFilter"
@pressEnter="search"
@search="search"
/>
<!-- 导入弹窗 -->
<Import v-model:visible="showImport" @done="search" />
</a-space>
</template>
<script lang="ts" setup>
import {
import {
PlusOutlined,
UploadOutlined,
DownloadOutlined,
DeleteOutlined
} from '@ant-design/icons-vue';
import useSearch from '@/utils/use-search';
import { ref, watch } from 'vue';
import { utils, writeFile } from 'xlsx';
import { TowerEquipment } from '@/api/tower/equipment/model';
import { TowerEquipmentParam } from '@/api/tower/equipment/model';
import Import from './import.vue';
import { message } from 'ant-design-vue';
} from "@ant-design/icons-vue";
import useSearch from "@/utils/use-search";
import { ref, watch } from "vue";
import { utils, writeFile } from "xlsx";
import { TowerEquipment } from "@/api/tower/equipment/model";
import { TowerEquipmentParam } from "@/api/tower/equipment/model";
import Import from "./import.vue";
import { message } from "ant-design-vue";
import { ContractSettleMethod } from "@/api/tower/contract/model";
const props = withDefaults(
const props = withDefaults(
defineProps<{
// 选中的角色
selection?: [];
// 选中的角色
selection?: [];
}>(),
{}
);
);
const emit = defineEmits<{
(e: 'search', where?: TowerEquipmentParam): void;
(e: 'add'): void;
(e: 'remove'): void;
(e: 'update', status?: number): void;
(e: 'import'): void;
}>();
const emit = defineEmits<{
(e: "search", where?: TowerEquipmentParam): void;
(e: "add"): void;
(e: "remove"): void;
(e: "update", status?: number): void;
(e: "import"): void;
}>();
// 表单数据
const { where, resetFields } = useSearch<TowerEquipmentParam>({
// 表单数据
const { where, resetFields } = useSearch<TowerEquipmentParam>({
equipmentId: undefined,
name: undefined,
keywords: ''
});
// 下来选项
const type = ref('keywords');
// 搜索内容
const searchText = ref('');
// 状态
const status = ref<number>();
// 是否显示导入弹窗
const showImport = ref(false);
keywords: "",
status: undefined,
yearFilter: undefined,
});
// 下来选项
const type = ref("keywords");
// 搜索内容
const searchText = ref("");
const yearFilter = ref<number>();
const statusFilter = ref(undefined);
// 状态
const status = ref<number>();
// 是否显示导入弹窗
const showImport = ref(false);
/* 搜索 */
const search = () => {
/* 搜索 */
const search = () => {
resetFields();
if (type.value == 'keywords') {
where.keywords = searchText.value;
if (type.value == "keywords") {
where.keywords = searchText.value;
}
emit('search', {
...where
if (statusFilter.value !== undefined) {
where.status = statusFilter.value;
}
if (yearFilter.value !== undefined) {
where.yearFilter = yearFilter.value;
}
emit("search", {
...where
});
};
};
// 导出
const handleExport = () => {
// 导出
const handleExport = () => {
if (!props.selection?.length) {
message.error('请至少选择一条数据');
return;
message.error("请至少选择一条数据");
return;
}
const array: (string | number)[][] = [
[
'设备状态',
'设备名称',
'出厂编号',
'设备型号',
'制造厂商',
'采购日期',
'备案编号',
'出厂日期',
'产权单位',
'设备来源',
'所属仓库',
'所属人员',
'自编号',
'额定载重',
'最大起升高度(m)',
'臂长',
'当前位置',
'楼号'
]
[
"设备状态",
"设备名称",
"出厂编号",
"设备型号",
"制造厂商",
"采购日期",
"备案编号",
"出厂日期",
"产权单位",
"设备来源",
"所属仓库",
"所属人员",
"自编号",
"额定载重",
"最大起升高度(m)",
"臂长",
"当前位置",
"楼号"
]
];
props.selection?.forEach((d: TowerEquipment) => {
array.push([
`${['闲置', '报废', '注销', '转卖'][Number(d.status)]}`,
`${d.name}`,
`${d.factoryNo}`,
`${d.model}`,
`${d.manufactor}`,
`${d.buyDate ? d.buyDate : ''}`,
`${d.filingNo}`,
`${d.factoryDate ? d.factoryDate : ''}`,
`${d.company}`,
`${d.source}`,
`${d.warehouse}`,
`${d.users}`,
`${d.equipmentNo}`,
`${d.ratedLoad}`,
`${d.maxLiftingHeight}`,
`${d.armLength}`,
`${d.currentLocation}`,
`${d.machineNo}`
]);
array.push([
`${["闲置", "报废", "注销", "转卖", "在用", "停工"][Number(d.status)]}`,
`${d.name}`,
`${d.factoryNo}`,
`${d.model}`,
`${d.manufactor}`,
`${d.buyDate ? d.buyDate : ""}`,
`${d.filingNo}`,
`${d.factoryDate ? d.factoryDate : ""}`,
`${d.company}`,
`${d.source}`,
`${d.warehouse}`,
`${d.users}`,
`${d.equipmentNo}`,
`${d.ratedLoad}`,
`${d.maxLiftingHeight}`,
`${d.armLength}`,
`${d.currentLocation}`,
`${d.machineNo}`
]);
});
const sheetName = '设备导出列表';
const sheetName = "设备导出列表";
const workbook = {
SheetNames: [sheetName],
Sheets: {}
SheetNames: [sheetName],
Sheets: {}
};
const sheet = utils.aoa_to_sheet(array);
workbook.Sheets[sheetName] = sheet;
// 设置列宽
sheet['!cols'] = [
{ wch: 10 },
{ wch: 10 },
{ wch: 10 },
{ wch: 10 },
{ wch: 20 },
{ wch: 40 },
{ wch: 10 }
sheet["!cols"] = [
{ wch: 10 },
{ wch: 10 },
{ wch: 10 },
{ wch: 10 },
{ wch: 20 },
{ wch: 40 },
{ wch: 10 }
];
writeFile(workbook, '导出设备管理表.xlsx');
};
writeFile(workbook, "导出设备管理表.xlsx");
};
// 发布设备
const add = () => {
emit('add');
};
// 发布设备
const add = () => {
emit("add");
};
// 导入
const openImport = () => {
// 导入
const openImport = () => {
showImport.value = true;
};
};
const handleStatus = () => {
emit('update', status.value);
};
const handleStatus = () => {
emit("update", status.value);
};
// 批量删除
const removeBatch = () => {
emit('remove');
};
// 批量删除
const removeBatch = () => {
emit("remove");
};
watch(
watch(
() => props.selection,
() => {}
);
() => {
}
);
</script>

View File

@@ -1,282 +1,348 @@
<template>
<div class="page">
<div class="ele-body">
<a-card :bordered="false">
<!-- 表格 -->
<ele-pro-table
ref="tableRef"
row-key="equipmentId"
:columns="columns"
:datasource="datasource"
v-model:selection="selection"
:customRow="customRow"
tool-class="ele-toolbar-form"
:scroll="{ x: 1200 }"
class="sys-org-table"
:striped="true"
>
<template #toolbar>
<search
@search="reload"
:selection="selection"
@add="openEdit"
@remove="removeBatch"
@update="handleStatus"
/>
</template>
<template #bodyCell="{ column, record }">
<template v-if="column.key === 'nickname'">
{{ record.nickname }}
<div>
<a-card title="设备数据">
<a-row :gutter="10">
<a-col :span="4">
<span>设备总数:{{ equipmentData.totalNum }}</span>
</a-col>
<a-col :span="4">
<span>闲置设备总数:{{ equipmentData.idleNum }}</span>
</a-col>
<a-col :span="4">
<span>已达报废年限设备总数:{{ equipmentData.scrapNum }}</span>
</a-col>
</a-row>
</a-card>
<div class="page">
<div class="ele-body">
<a-card :bordered="false">
<!-- 表格 -->
<ele-pro-table
ref="tableRef"
row-key="equipmentId"
:columns="columns"
:datasource="datasource"
v-model:selection="selection"
:customRow="customRow"
tool-class="ele-toolbar-form"
:scroll="{ x: 1200 }"
class="sys-org-table"
:striped="true"
>
<template #toolbar>
<search
@search="reload"
:selection="selection"
@add="openEdit"
@remove="removeBatch"
@update="handleStatus"
/>
</template>
<template v-if="column.key === 'createTime'">
{{ record.createTime }}
<template #bodyCell="{ column, record }">
<template v-if="column.key === 'useYear'">
<span v-if="record.factoryDate">{{ dayjs().diff(dayjs(record.factoryDate), "year") }}</span>
</template>
<template v-if="column.key === 'canUseYear'">
<span v-if="record.scrapDate">{{ dayjs(record.scrapDate).diff(dayjs(), "year") + 1 }}</span>
</template>
<template v-if="column.key === 'createTime'">
{{ record.createTime }}
</template>
<template v-if="column.key === 'inProject'">
<div>
<p v-for="(item, index) in record.projectList" :key="index" style="line-height: 1.5">
{{ item.projectName }}
</p>
</div>
</template>
<template v-if="column.key === 'status'">
<a-tag v-if="record.status === 0" color="green">闲置</a-tag>
<a-tag v-if="record.status === 1" color="red">报废</a-tag>
<a-tag v-if="record.status === 2" color="purple">注销</a-tag>
<a-tag v-if="record.status === 3" color="orange">转卖</a-tag>
</template>
<template v-if="column.key === 'action'">
<a-space>
<a @click="showProjectList(record)">历史项目</a>
<a-divider type="vertical" />
<a @click="openEdit(record)">一机一档</a>
<a-divider type="vertical" />
<a @click="showQr(record)">设备名片</a>
</a-space>
</template>
</template>
<template v-if="column.key === 'status'">
<a-tag v-if="record.status === 0" color="green">闲置</a-tag>
<a-tag v-if="record.status === 1" color="red">报废</a-tag>
<a-tag v-if="record.status === 2" color="purple">注销</a-tag>
<a-tag v-if="record.status === 3" color="orange">转卖</a-tag>
</template>
<template v-if="column.key === 'action'">
<a-space>
<a @click="openEdit(record)">一机一档</a>
<a-divider type="vertical" />
<a @click="openEdit(record)">设备名片</a>
</a-space>
</template>
</template>
</ele-pro-table>
</a-card>
</ele-pro-table>
</a-card>
</div>
<!-- 编辑弹窗 -->
<EquipmentEdit v-model:visible="showEdit" :data="current" @done="reload" />
<ProjectList v-model:visible="showProject" :data="current" />
</div>
<!-- 编辑弹窗 -->
<EquipmentEdit v-model:visible="showEdit" :data="current" @done="reload" />
</div>
</template>
<script lang="ts" setup>
import { createVNode, ref } from 'vue';
import { message, Modal } from 'ant-design-vue';
import { ExclamationCircleOutlined } from '@ant-design/icons-vue';
import type { EleProTable } from 'ele-admin-pro';
import type {
DatasourceFunction,
ColumnItem
} from 'ele-admin-pro/es/ele-pro-table/types';
import { toDateString } from 'ele-admin-pro';
import Search from './components/search.vue';
import EquipmentEdit from './components/equipment-edit.vue';
import {
pageTowerEquipment,
removeBatchTowerEquipment,
updateBatchTowerEquipment
} from '@/api/tower/equipment';
import {
TowerEquipment,
TowerEquipmentParam
} from '@/api/tower/equipment/model';
import { createVNode, reactive, ref } from "vue";
import { message, Modal } from "ant-design-vue";
import { ExclamationCircleOutlined } from "@ant-design/icons-vue";
import type { EleProTable } from "ele-admin-pro";
import type {
DatasourceFunction,
ColumnItem
} from "ele-admin-pro/es/ele-pro-table/types";
import { toDateString } from "ele-admin-pro";
import Search from "./components/search.vue";
import EquipmentEdit from "./components/equipment-edit.vue";
import {
pageTowerEquipment,
removeBatchTowerEquipment, towerEquipmentData, towerEquipmentQr,
updateBatchTowerEquipment
} from "@/api/tower/equipment";
import {
TowerEquipment,
TowerEquipmentParam
} from "@/api/tower/equipment/model";
import { ApiResult, PageResult } from "@/api";
import dayjs from "dayjs";
import ProjectList from "@/views/tower/equipment/components/project-list.vue";
defineProps<{
activeKey?: boolean;
data?: any;
}>();
defineProps<{
activeKey?: boolean;
data?: any;
}>();
// 表格实例
const tableRef = ref<InstanceType<typeof EleProTable> | null>(null);
// 表格实例
const tableRef = ref<InstanceType<typeof EleProTable> | null>(null);
// 表格列配置
const columns = ref<ColumnItem[]>([
{
key: 'index',
width: 48,
align: 'center',
fixed: 'left',
hideInSetting: true,
customRender: ({ index }) => index + (tableRef.value?.tableIndex ?? 0)
},
{
title: '设备状态',
dataIndex: 'status',
key: 'status',
customRender: ({ text }) => ['闲置', '报废', '注销', '转卖'][text]
},
{
title: '设备名称',
dataIndex: 'name',
key: 'name'
},
{
title: '设备型号',
dataIndex: 'model',
key: 'model'
},
{
title: '制造厂商',
dataIndex: 'manufactor',
key: 'manufactor'
},
{
title: '当前位置',
dataIndex: 'currentLocation',
key: 'currentLocation'
},
{
title: '产权单位(个人)',
dataIndex: 'company',
key: 'company'
},
{
title: '创建时间',
dataIndex: 'createTime',
key: 'createTime',
align: 'center',
sorter: true,
customRender: ({ text }) => toDateString(text)
},
{
title: '操作',
key: 'action',
width: 200,
align: 'center',
hideInSetting: true
}
]);
// 表格列配置
const columns = ref<ColumnItem[]>([
{
key: "index",
width: 48,
align: "center",
fixed: "left",
hideInSetting: true,
customRender: ({ index }) => index + (tableRef.value?.tableIndex ?? 0)
},
{
title: "设备状态",
dataIndex: "status",
key: "status",
customRender: ({ text }) => ["闲置", "报废", "注销", "转卖", "在用", "停工"][text]
},
{
title: "设备名称",
dataIndex: "name",
key: "name"
},
{
title: "出厂编号",
dataIndex: "factoryNo"
},
{
title: "设备型号",
dataIndex: "model",
key: "model"
},
{
title: "备案编号",
dataIndex: "filingNo"
},
{
title: "制造厂商",
dataIndex: "manufactor",
key: "manufactor"
},
{
title: "所在项目",
key: "inProject"
},
{
title: "产权单位(个人)",
dataIndex: "company",
key: "company"
},
{
title: "购买日期",
dataIndex: "buyDate"
},
{
title: "已使用年份",
key: "useYear"
},
{
title: "剩余可使用年份",
key: "canUseYear"
},
{
title: "操作",
key: "action",
width: 200,
align: "center",
hideInSetting: true
}
]);
// 表格选中数据
const selection = ref<TowerEquipment[]>([]);
// 当前编辑数据
const current = ref<TowerEquipment | null>(null);
// 是否显示编辑弹窗
const showEdit = ref(false);
let equipmentData = reactive({
totalNum: 0,
idleNum: 0,
scrapNum: 0
});
const getData = async () => {
const res = await towerEquipmentData();
for (let key in equipmentData) equipmentData[key] = res[key];
};
// 表格数据
const datasource: DatasourceFunction = ({
// 表格选中数据
const selection = ref<TowerEquipment[]>([]);
// 当前编辑数据
const current = ref<TowerEquipment | null>(null);
// 是否显示编辑弹窗
const showEdit = ref(false);
// 表格数据源
const datasource: DatasourceFunction = ({
page,
limit,
where,
orders,
filters
}) => {
// 搜索条件
if (filters.payMethod) {
where.payMethod = filters.payMethod;
}
if (filters.deliveryType) {
where.deliveryType = filters.deliveryType;
}
if (filters.payStatus) {
where.payStatus = filters.payStatus;
}
if (filters.orderSource) {
where.orderSource = filters.orderSource;
}
where.tenantId = localStorage.getItem("tenantId");
where.payStatus = 20;
return pageTowerEquipment({
...where,
...orders,
page,
limit,
where,
orders,
filters
}) => {
// 搜索条件
if (filters.payMethod) {
where.payMethod = filters.payMethod;
}
if (filters.deliveryType) {
where.deliveryType = filters.deliveryType;
}
if (filters.payStatus) {
where.payStatus = filters.payStatus;
}
if (filters.orderSource) {
where.orderSource = filters.orderSource;
}
where.tenantId = localStorage.getItem('tenantId');
where.payStatus = 20;
return pageTowerEquipment({
...where,
...orders,
page,
limit
});
};
limit
});
};
/* 搜索 */
const reload = (where?: TowerEquipmentParam) => {
selection.value = [];
tableRef?.value?.reload({ where: where });
};
/* 搜索 */
const reload = (where?: TowerEquipmentParam) => {
selection.value = [];
tableRef?.value?.reload({ where: where });
getData();
};
/* 打开编辑弹窗 */
const openEdit = (row?: TowerEquipment) => {
current.value = row ?? null;
showEdit.value = true;
};
/* 打开编辑弹窗 */
const openEdit = (row?: TowerEquipment) => {
current.value = row ?? null;
showEdit.value = true;
};
/* 批量修改 */
const handleStatus = (status) => {
if (!selection.value.length) {
message.error('请至少选择一条数据');
return;
}
const data = selection.value.map((d) => {
return {
equipmentId: d.equipmentId,
status
};
});
console.log(data);
updateBatchTowerEquipment(data).then((msg) => {
message.success(msg);
reload();
});
};
const showQr = async (row?: TowerEquipment) => {
const res = towerEquipmentQr({ equipmentId: row?.equipmentId })
console.log(res)
};
/* 批量删除 */
const removeBatch = () => {
if (!selection.value.length) {
message.error('请至少选择一条数据');
return;
}
Modal.confirm({
title: '提示',
content: '确定要删除选中的记录吗?',
icon: createVNode(ExclamationCircleOutlined),
maskClosable: true,
onOk: () => {
const hide = message.loading('请求中..', 0);
removeBatchTowerEquipment(selection.value.map((d) => d.equipmentId))
.then((msg) => {
hide();
message.success(msg);
reload();
})
.catch((e) => {
hide();
message.error(e.message);
});
}
});
};
const showProject = ref<Boolean>(false)
const showProjectList = async (row?: TowerEquipment) => {
current.value = row ?? null;
showProject.value = true;
};
/* 自定义行属性 */
const customRow = (record: TowerEquipment) => {
/* 批量修改 */
const handleStatus = (status) => {
if (!selection.value.length) {
message.error("请至少选择一条数据");
return;
}
const data = selection.value.map((d) => {
return {
// 行点击事件
onClick: () => {
// console.log(record);
},
// 行双击事件
onDblclick: () => {
openEdit(record);
}
equipmentId: d.equipmentId,
status
};
};
});
updateBatchTowerEquipment(data).then((msg) => {
message.success(msg);
reload();
});
};
reload();
/* 批量删除 */
const removeBatch = () => {
if (!selection.value.length) {
message.error("请至少选择一条数据");
return;
}
Modal.confirm({
title: "提示",
content: "确定要删除选中的记录吗?",
icon: createVNode(ExclamationCircleOutlined),
maskClosable: true,
onOk: () => {
const hide = message.loading("请求中..", 0);
removeBatchTowerEquipment(selection.value.map((d) => d.equipmentId))
.then((msg) => {
hide();
message.success(msg);
reload();
})
.catch((e) => {
hide();
message.error(e.message);
});
}
});
};
/* 自定义行属性 */
const customRow = (record: TowerEquipment) => {
return {
// 行点击事件
onClick: () => {
// console.log(record);
},
// 行双击事件
onDblclick: () => {
openEdit(record);
}
};
};
reload();
</script>
<script lang="ts">
export default {
name: 'TowerEquipmentIndex'
};
export default {
name: "TowerEquipmentIndex"
};
</script>
<style lang="less" scoped>
p {
line-height: 0.8;
}
.sys-org-table :deep(.ant-table-body) {
overflow: auto !important;
overflow: overlay !important;
}
p {
line-height: 0.8;
}
.sys-org-table :deep(.ant-table-pagination.ant-pagination) {
padding: 0 4px;
margin-bottom: 0;
}
.price-edit {
padding-right: 5px;
}
.comments {
max-width: 200px;
}
.sys-org-table :deep(.ant-table-body) {
overflow: auto !important;
overflow: overlay !important;
}
.sys-org-table :deep(.ant-table-pagination.ant-pagination) {
padding: 0 4px;
margin-bottom: 0;
}
.price-edit {
padding-right: 5px;
}
.comments {
max-width: 200px;
}
</style>

View File

@@ -44,14 +44,14 @@
v-model:value="form.factory"
/>
</a-form-item>
<a-form-item label="产权单位" name="companyId">
<DictSelect
:placeholder="'请选择产权单位'"
v-model:value="form.companyName"
:dict-code="'PropertyCompany'"
@done="chooseCompanyName"
/>
</a-form-item>
<!-- <a-form-item label="产权单位" name="companyId">-->
<!-- <DictSelect-->
<!-- :placeholder="'请选择产权单位'"-->
<!-- v-model:value="form.companyName"-->
<!-- :dict-code="'PropertyCompany'"-->
<!-- @done="chooseCompanyName"-->
<!-- />-->
<!-- </a-form-item>-->
<a-form-item label="出厂日期" name="factoryDate">
<a-date-picker
class="ele-fluid"
@@ -68,6 +68,14 @@
v-model:value="form.discardDate"
/>
</a-form-item>
<a-form-item label="检测日期日期" name="checkDate">
<a-date-picker
class="ele-fluid"
value-format="YYYY-MM-DD"
placeholder="请选择日期"
v-model:value="form.checkDate"
/>
</a-form-item>
</a-col>
</a-row>
</a-card>
@@ -222,6 +230,7 @@ const form = reactive<TowerFall>({
factory: "",
factoryDate: "",
discardDate: undefined,
checkDate: undefined,
file1: "[]",
file2: "[]",
file3: "[]",

View File

@@ -77,7 +77,7 @@
const aoa = utils.sheet_to_json<string[]>(worksheet, { header: 1 });
console.log(aoa);
aoa.slice(1).map((d) => {
const array = ['闲置', '报废', '注销', '转卖'];
const array = ['闲置', '报废', '注销', '转卖', '在用', '场地'];
importData.value.push({
status: array.indexOf(d[0]),
name: d[1],

View File

@@ -28,6 +28,11 @@
<template v-if="column.key === 'nickname'">
{{ record.nickname }}
</template>
<template v-if="column.key === 'checkDate'">
<span
:style="{color: record.checkDate ? (dayjs().diff(dayjs(record.checkDate), 'day') < 30 ? 'red' : 'black') : 'black'}">
{{ record.checkDate }}</span>
</template>
<template v-if="column.key === 'createTime'">
{{ record.createTime }}
</template>
@@ -59,252 +64,261 @@
</template>
<script lang="ts" setup>
import { createVNode, ref } from 'vue';
import { message, Modal } from 'ant-design-vue';
import { ExclamationCircleOutlined } from '@ant-design/icons-vue';
import type { EleProTable } from 'ele-admin-pro';
import type {
DatasourceFunction,
ColumnItem
} from 'ele-admin-pro/es/ele-pro-table/types';
import { toDateString } from 'ele-admin-pro';
import Search from './components/search.vue';
import FallEdit from './components/fall-edit.vue';
import {
pageTowerFall,
removeBatchTowerFall,
updateBatchTowerFall
} from '@/api/tower/fall';
import { TowerFall, TowerFallParam } from '@/api/tower/fall/model';
import { pageCompany } from '@/api/system/company';
import { Customer } from '@/api/oa/customer/model';
import { Company } from '@/api/system/company/model';
import { createVNode, ref } from "vue";
import { message, Modal } from "ant-design-vue";
import { ExclamationCircleOutlined } from "@ant-design/icons-vue";
import type { EleProTable } from "ele-admin-pro";
import type {
DatasourceFunction,
ColumnItem
} from "ele-admin-pro/es/ele-pro-table/types";
import { toDateString } from "ele-admin-pro";
import Search from "./components/search.vue";
import FallEdit from "./components/fall-edit.vue";
import {
pageTowerFall,
removeBatchTowerFall,
updateBatchTowerFall
} from "@/api/tower/fall";
import { TowerFall, TowerFallParam } from "@/api/tower/fall/model";
import { pageCompany } from "@/api/system/company";
import { Customer } from "@/api/oa/customer/model";
import { Company } from "@/api/system/company/model";
import dayjs from "dayjs";
defineProps<{
activeKey?: boolean;
data?: any;
}>();
defineProps<{
activeKey?: boolean;
data?: any;
}>();
// 表格实例
const tableRef = ref<InstanceType<typeof EleProTable> | null>(null);
// 表格实例
const tableRef = ref<InstanceType<typeof EleProTable> | null>(null);
// 表格列配置
const columns = ref<ColumnItem[]>([
{
key: 'index',
width: 48,
align: 'center',
fixed: 'left',
hideInSetting: true,
customRender: ({ index }) => index + (tableRef.value?.tableIndex ?? 0)
},
// {
// title: '设备状态',
// dataIndex: 'status',
// key: 'status',
// customRender: ({ text }) => ['闲置', '报废', '注销', '转卖'][text]
// },
{
title: '防坠器编号',
dataIndex: 'code',
key: 'code'
},
{
title: '防坠器型号',
dataIndex: 'model',
key: 'model'
},
{
title: '制造厂商',
dataIndex: 'factory',
key: 'factory'
},
{
title: '产权单位',
dataIndex: 'companyName',
key: 'companyName'
},
{
title: '出厂日期',
dataIndex: 'factoryDate',
key: 'factoryDate'
},
{
title: '报废日期',
dataIndex: 'discardDate',
key: 'discardDate'
},
{
title: '创建时间',
dataIndex: 'createTime',
key: 'createTime',
align: 'center',
sorter: true,
customRender: ({ text }) => toDateString(text)
},
{
title: '操作',
key: 'action',
width: 200,
align: 'center',
hideInSetting: true
}
]);
// 表格列配置
const columns = ref<ColumnItem[]>([
{
key: "index",
width: 48,
align: "center",
fixed: "left",
hideInSetting: true,
customRender: ({ index }) => index + (tableRef.value?.tableIndex ?? 0)
},
// {
// title: '设备状态',
// dataIndex: 'status',
// key: 'status',
// customRender: ({ text }) => ['闲置', '报废', '注销', '转卖'][text]
// },
{
title: "防坠器编号",
dataIndex: "code",
key: "code"
},
{
title: "防坠器型号",
dataIndex: "model",
key: "model"
},
{
title: "制造厂商",
dataIndex: "factory",
key: "factory"
},
{
title: "产权单位",
dataIndex: "companyName",
key: "companyName"
},
{
title: "出厂日期",
dataIndex: "factoryDate",
key: "factoryDate"
},
{
title: "报废日期",
dataIndex: "discardDate",
key: "discardDate"
},
{
title: "检测日期",
dataIndex: "checkDate",
key: "checkDate"
},
{
title: "创建时间",
dataIndex: "createTime",
key: "createTime",
align: "center",
sorter: true,
customRender: ({ text }) => toDateString(text)
},
{
title: "操作",
key: "action",
width: 200,
align: "center",
hideInSetting: true
}
]);
// 表格选中数据
const selection = ref<TowerFall[]>([]);
// 当前编辑数据
const current = ref<TowerFall | null>(null);
// 是否显示编辑弹窗
const showEdit = ref(false);
const companys = ref<Company[] | undefined>();
pageCompany({
companyTypeMultiple: '产权单位'
}).then((res) => {
companys.value = res?.list;
});
// 表格数据源
const datasource: DatasourceFunction = ({
// 表格选中数据
const selection = ref<TowerFall[]>([]);
// 当前编辑数据
const current = ref<TowerFall | null>(null);
// 是否显示编辑弹窗
const showEdit = ref(false);
const companys = ref<Company[] | undefined>();
pageCompany({
companyTypeMultiple: "产权单位"
}).then((res) => {
companys.value = res?.list;
});
// 表格数据源
const datasource: DatasourceFunction = ({
page,
limit,
where,
orders,
filters
}) => {
// 搜索条件
if (filters.payMethod) {
where.payMethod = filters.payMethod;
}
if (filters.deliveryType) {
where.deliveryType = filters.deliveryType;
}
if (filters.payStatus) {
where.payStatus = filters.payStatus;
}
if (filters.orderSource) {
where.orderSource = filters.orderSource;
}
where.tenantId = localStorage.getItem("tenantId");
where.payStatus = 20;
return pageTowerFall({
...where,
...orders,
page,
limit,
where,
orders,
filters
}) => {
// 搜索条件
if (filters.payMethod) {
where.payMethod = filters.payMethod;
}
if (filters.deliveryType) {
where.deliveryType = filters.deliveryType;
}
if (filters.payStatus) {
where.payStatus = filters.payStatus;
}
if (filters.orderSource) {
where.orderSource = filters.orderSource;
}
where.tenantId = localStorage.getItem('tenantId');
where.payStatus = 20;
return pageTowerFall({
...where,
...orders,
page,
limit
});
};
limit
});
};
/* 搜索 */
const reload = (where?: TowerFallParam) => {
selection.value = [];
tableRef?.value?.reload({ where: where });
};
/* 搜索 */
const reload = (where?: TowerFallParam) => {
selection.value = [];
tableRef?.value?.reload({ where: where });
};
/* 打开编辑弹窗 */
const openEdit = (row?: TowerFall) => {
current.value = row ?? null;
showEdit.value = true;
};
/* 删除单个 */
const remove = (row: TowerFall) => {
const hide = message.loading('请求中..', 0);
removeBatchTowerFall([row.id])
.then((msg) => {
hide();
message.success(msg);
reload();
})
.catch((e) => {
hide();
message.error(e.message);
});
};
/* 批量修改 */
const handleStatus = (status) => {
if (!selection.value.length) {
message.error('请至少选择一条数据');
return;
}
const data = selection.value.map((d) => {
return {
fallId: d.id,
status
};
});
console.log(data);
updateBatchTowerFall(data).then((msg) => {
/* 打开编辑弹窗 */
const openEdit = (row?: TowerFall) => {
current.value = row ?? null;
showEdit.value = true;
};
/* 删除单个 */
const remove = (row: TowerFall) => {
const hide = message.loading("请求中..", 0);
removeBatchTowerFall([row.id])
.then((msg) => {
hide();
message.success(msg);
reload();
})
.catch((e) => {
hide();
message.error(e.message);
});
};
/* 批量删除 */
const removeBatch = () => {
if (!selection.value.length) {
message.error('请至少选择一条数据');
return;
}
Modal.confirm({
title: '提示',
content: '确定要删除选中的记录吗?',
icon: createVNode(ExclamationCircleOutlined),
maskClosable: true,
onOk: () => {
const hide = message.loading('请求中..', 0);
removeBatchTowerFall(selection.value.map((d) => d.id))
.then((msg) => {
hide();
message.success(msg);
reload();
})
.catch((e) => {
hide();
message.error(e.message);
});
}
});
};
/* 自定义行属性 */
const customRow = (record: TowerFall) => {
};
/* 批量修改 */
const handleStatus = (status) => {
if (!selection.value.length) {
message.error("请至少选择一条数据");
return;
}
const data = selection.value.map((d) => {
return {
// 行点击事件
onClick: () => {
// console.log(record);
},
// 行双击事件
onDblclick: () => {
openEdit(record);
}
fallId: d.id,
status
};
};
});
console.log(data);
updateBatchTowerFall(data).then((msg) => {
message.success(msg);
reload();
});
};
reload();
/* 批量删除 */
const removeBatch = () => {
if (!selection.value.length) {
message.error("请至少选择一条数据");
return;
}
Modal.confirm({
title: "提示",
content: "确定要删除选中的记录吗?",
icon: createVNode(ExclamationCircleOutlined),
maskClosable: true,
onOk: () => {
const hide = message.loading("请求中..", 0);
removeBatchTowerFall(selection.value.map((d) => d.id))
.then((msg) => {
hide();
message.success(msg);
reload();
})
.catch((e) => {
hide();
message.error(e.message);
});
}
});
};
/* 自定义行属性 */
const customRow = (record: TowerFall) => {
return {
// 行点击事件
onClick: () => {
// console.log(record);
},
// 行双击事件
onDblclick: () => {
openEdit(record);
}
};
};
reload();
</script>
<script lang="ts">
export default {
name: 'TowerFallIndex'
};
export default {
name: "TowerFallIndex"
};
</script>
<style lang="less" scoped>
p {
line-height: 0.8;
}
.sys-org-table :deep(.ant-table-body) {
overflow: auto !important;
overflow: overlay !important;
}
p {
line-height: 0.8;
}
.sys-org-table :deep(.ant-table-pagination.ant-pagination) {
padding: 0 4px;
margin-bottom: 0;
}
.price-edit {
padding-right: 5px;
}
.comments {
max-width: 200px;
}
.sys-org-table :deep(.ant-table-body) {
overflow: auto !important;
overflow: overlay !important;
}
.sys-org-table :deep(.ant-table-pagination.ant-pagination) {
padding: 0 4px;
margin-bottom: 0;
}
.price-edit {
padding-right: 5px;
}
.comments {
max-width: 200px;
}
</style>

View File

@@ -0,0 +1,373 @@
<!-- 用户编辑弹窗 -->
<template>
<ele-modal
:width="'90%'"
:visible="visible"
:confirm-loading="loading"
:maskClosable="false"
:maxable="maxable"
:title="isUpdate ? '编辑结算书' : '添加结算书'"
:body-style="{ paddingBottom: '8px' }"
@update:visible="updateVisible"
@ok="save"
>
<a-form
:label-col="{ md: { span: 4 }, sm: { span: 4 }, xs: { span: 4 } }"
:label-align="'left'"
:wrapper-col="{ md: { span: 24 }, sm: { span: 20 }, xs: { span: 24 } }"
>
<a-card title="填报人信息" :bordered="false">
<a-row :gutter="16">
<a-col :md="12" :sm="24" :xs="24">
<a-form-item label="填报人">
<a-input disabled v-model:value="loginUser.username" />
</a-form-item>
</a-col>
<a-col :md="12" :sm="24" :xs="24">
<a-form-item label="填报时间">
<a-input disabled v-model:value="now" />
</a-form-item>
</a-col>
</a-row>
</a-card>
<a-card title="合同信息" :bordered="false">
<a-row :gutter="16">
<a-col :md="8" :sm="24" :xs="24">
<a-form-item label="合同编号" v-bind="validateInfos.contractId">
<TowerContractSelectModel
:placeholder="`请选择合同`"
v-model:value="form.contractNumber"
@done="chooseContract"
/>
</a-form-item>
<a-form-item label="承租单位">
<p style="margin: 0">{{ form.customerName }}</p>
</a-form-item>
<a-form-item label="累计开票金额">
<p style="margin: 0">{{ form.totalInvoicingAmount }}</p>
</a-form-item>
</a-col>
<a-col :md="8" :sm="24" :xs="24">
<a-form-item label="签订日期">
<p style="margin: 0">{{ form.signDate }}</p>
</a-form-item>
<a-form-item label="租赁单位">
<p style="margin: 0">{{ form.companyName }}</p>
</a-form-item>
<a-form-item label="结算总金额">
<p style="margin: 0">{{ form.totalSettleAmount }}</p>
</a-form-item>
</a-col>
<a-col :md="8" :sm="24" :xs="24">
<a-form-item label="项目名称">
<p style="margin: 0">{{ form.projectName }}</p>
</a-form-item>
<a-form-item label="累计收款金额">
<p style="margin: 0">{{ form.totalIncomeAmount }}</p>
</a-form-item>
</a-col>
</a-row>
</a-card>
<a-card title="结算信息" :bordered="false">
<a-row :gutter="16">
<a-col :md="8" :sm="24" :xs="24">
<a-form-item label="结算单位" v-bind="validateInfos.settleCompanyId">
<SelectCompany
:placeholder="`请选择结算单位`"
v-model:value="form.settleCompanyName"
@done="chooseCompany"
/>
</a-form-item>
</a-col>
<a-col :md="8" :sm="24" :xs="24">
<a-form-item label="登记人" v-bind="validateInfos.signName">
<UserChoose @select="selectSignName" />
</a-form-item>
</a-col>
<a-col :md="8" :sm="24" :xs="24">
<a-form-item label="登记日期" v-bind="validateInfos.signDate">
<a-date-picker
class="ele-fluid"
placeholder="请选择登记日期"
v-model:value="form.signDate"
valueFormat="YYYY-MM-DD"
/>
</a-form-item>
</a-col>
</a-row>
<a-form-item label="备注" :label-col="{ md: { span: 1 }, sm: { span: 1 }, xs: { span: 1 } }">
<a-input v-model:value="form.remark" placeholder="请输入备注说明" />
</a-form-item>
<!-- <a-form-item label="附件" name="parentId">-->
<!-- <a-upload-->
<!-- v-model:file-list="fileList"-->
<!-- name="file"-->
<!-- action="https://file.wsdns.cn/api/file/image"-->
<!-- :headers="{ Authorization: token }"-->
<!-- @change="onFile"-->
<!-- >-->
<!-- <a-button>-->
<!-- <upload-outlined />-->
<!-- 上传-->
<!-- </a-button>-->
<!-- </a-upload>-->
<!-- </a-form-item>-->
</a-card>
<a-card title="缺失物品登记">
<a-button @click.native="showSelectItem = true" type="primary" :disabled="!form.contractId">新增
</a-button>
<Table :data-source="lostList" />
</a-card>
</a-form>
</ele-modal>
<ele-modal
:width="'80%'"
:visible="showSelectItem"
:maskClosable="false"
title="选择配件"
:body-style="{ paddingBottom: '8px' }"
@update:visible="showSelectItem"
@cancel="showSelectItem = false"
@ok="showSelectItem = false"
>
<a-row :gutter="16">
<a-col :span="6">配件名称</a-col>
<a-col :span="6">操作</a-col>
</a-row>
<a-row :gutter="16" class="my-05" v-for="(item, index) in categoryList" :key="index">
<a-col :span="6">{{ item.title }}</a-col>
<a-col :span="6">
<a-button type="link" @click.native="selectItem(item)">选择</a-button>
</a-col>
</a-row>
</ele-modal>
</template>
<script lang="ts" setup>
import { ref, reactive, watch, computed } from "vue";
import { Form, message } from "ant-design-vue";
import { assignObject, EleProTable } from "ele-admin-pro";
import { useUserStore } from "@/store/modules/user";
import dayjs from "dayjs";
import { Contract } from "@/api/tower/contract/model";
import Table from "./table.vue";
import { Company } from "@/api/system/company/model";
import { User } from "@/api/user/model";
import { TOKEN_STORE_NAME } from "@/config/setting";
import { UploadOutlined } from "@ant-design/icons-vue";
import { FinalSettle } from "@/api/tower/finalSettle/model";
import { Category } from "@/api/goods/category/model";
import { addFinalSettle, updateFinalSettle } from "@/api/tower/finalSettle";
import { FinalSettleLost } from "@/api/tower/finalSettleLost/model";
import { addBatchFinalSettleLost } from "@/api/tower/finalSettleLost";
import { listCategory } from "@/api/goods/category";
const userStore = useUserStore();
const token = localStorage.getItem(TOKEN_STORE_NAME);
// 当前用户信息
const loginUser = computed(() => userStore.info ?? {});
const now = dayjs().format("YYYY-MM-DD HH:mm:ss");
// 是否是修改
const isUpdate = ref(false);
const useForm = Form.useForm;
const props = defineProps<{
// 弹窗是否打开
visible: boolean;
// 修改回显的数据
data?: FinalSettle | null;
}>();
const emit = defineEmits<{
(e: "done"): void;
(e: "update:visible", visible: boolean): void;
}>();
// 提交状态
const loading = ref(false);
// 是否显示最大化切换按钮
const maxable = ref(true);
const activeKey = ref(0);
const categoryList = ref<Category[]>([]);
const getCategoryList = async () => {
categoryList.value = await listCategory({ parentId: -1 });
};
const showSelectItem = ref(false);
const lostList = ref<FinalSettleLost[]>([]);
const selectItem = (item: Category) => {
lostList.value.push({
finalSettleLostId: null,
finalSettleId: null,
itemId: item.categoryId,
amount: null,
num: null,
itemName: item.title,
total: null
});
showSelectItem.value = false;
};
const chooseContract = (res: Contract) => {
form.contractNumber = res.contactNumber;
form.contractId = res.contractId;
form.companyName = res.companyName;
form.customerName = res.customerName;
form.signDate = res.signDate;
form.projectName = res.projectName;
form.totalInvoicingAmount = res.totalInvoicingAmount;
form.totalIncomeAmount = res.totalIncomeAmount;
};
const chooseCompany = ({ companyName, companyId }: Company) => {
form.settleCompanyId = companyId;
form.settleCompanyName = companyName;
};
const selectSignName = ({ nickname }: User) => {
form.signName = nickname;
};
const fileList = ref<FileItem[]>([]);
interface FileItem {
uid: string;
name?: string;
status?: string;
response?: Response;
thumbUrl?: string;
downloadUrl?: string;
url: string;
}
interface FileInfo {
file: FileItem;
fileList: FileItem[];
}
const onFile = (info: FileInfo) => {
let resFileList = [...info.fileList];
fileList.value = resFileList.map((file) => {
if (file.response) {
file.url = file.response.url;
}
return file;
});
form.fileList = JSON.stringify(fileList.value);
};
const form = reactive<FinalSettle>({
contractFinalSettleId: null,
contractId: null,
settleCompanyId: "",
fileList: "[]",
signName: "",
signDate: dayjs().format("YYYY-MM-DD"),
remark: "",
settleCompanyName: "",
contractNumber: "",
companyName: "",
customerName: "",
projectName: "",
totalInvoicingAmount: "",
totalIncomeAmount: "",
totalSettleAmount: ""
});
/* 更新visible */
const updateVisible = (value: boolean) => {
emit("update:visible", value);
};
// 表单验证规则
const rules = reactive({
contractId: [
{
required: true,
message: "请选择合同",
trigger: "blur"
}
],
settleCompanyId: [
{
required: true,
message: "请选择结算单位",
trigger: "blur"
}
],
signDate: [
{
required: true,
message: "请选择登记日期",
trigger: "blur"
}
],
signName: [
{
required: true,
message: "请选择登记人员",
trigger: "blur"
}
]
});
const { resetFields, validate, validateInfos } = useForm(form, rules);
/* 保存编辑 */
const save = () => {
validate()
.then(async () => {
loading.value = true;
const data = {
...form
};
const saveOrUpdate = isUpdate.value ? updateFinalSettle : addFinalSettle;
const res = await saveOrUpdate(data).catch((e) => {
loading.value = false;
message.error(e.message);
});
if (lostList.value.length > 0) {
const finalSettleId = res?.data;
lostList.value.forEach((item, index) => {
lostList.value[index].finalSettleId = finalSettleId;
});
await addBatchFinalSettleLost(lostList.value);
}
message.success(res?.message);
updateVisible(false);
emit("done");
})
.catch(() => {
});
};
watch(
() => props.visible,
(visible) => {
if (visible) {
getCategoryList();
if (props.data) {
loading.value = false;
assignObject(form, props.data);
isUpdate.value = true;
} else {
isUpdate.value = false;
}
} else {
resetFields();
}
}
);
</script>
<style lang="less">
.title {
font-weight: bold;
font-size: 1.1rem;
padding-bottom: 10px;
border-bottom: 1px solid #dcdfe6;
color: #494949;
margin-bottom: 10px;
}
</style>

View File

@@ -0,0 +1,148 @@
<!-- 用户编辑弹窗 -->
<template>
<ele-modal
width="75%"
:visible="visible"
:confirm-loading="loading"
:title="'合同详情'"
:maxable="true"
:body-style="{ paddingBottom: '8px' }"
@update:visible="updateVisible"
:footer="null"
>
<a-form
:label-col="{ md: { span: 4 }, sm: { span: 24 } }"
:wrapper-col="{ md: { span: 19 }, sm: { span: 24 } }"
>
<div class="base-form" style="margin-bottom: 20px">
<a-descriptions bordered>
<a-descriptions-item label="合同名称">
{{ customer.customerName }}
</a-descriptions-item>
<a-descriptions-item label="社会统一信用代码">
{{ customer.customerCode }}
</a-descriptions-item>
<a-descriptions-item label="跟进状态">
<div color="blue" v-for="(d, index) in progress" :key="index">
<span v-if="d.value == customer.progress">{{ d.label }}</span>
</div>
</a-descriptions-item>
<a-descriptions-item label="联系人">
{{ customer.customerContacts }}
</a-descriptions-item>
<a-descriptions-item label="联系电话">
{{ customer.customerMobile }}
</a-descriptions-item>
<a-descriptions-item label="座机电话">
{{ customer.customerPhone }}
</a-descriptions-item>
<a-descriptions-item label="合同类型">
<div color="blue" v-for="(d, index) in customerType" :key="index">
<span v-if="d.value == customer.customerType">{{ d.value }}</span>
</div>
</a-descriptions-item>
<a-descriptions-item label="联系地址">
{{ customer.customerAddress }}
</a-descriptions-item>
<a-descriptions-item label="备注">
{{ customer.comments }}
</a-descriptions-item>
</a-descriptions>
<!-- <a-descriptions-->
<!-- title="其他信息"-->
<!-- :column="1"-->
<!-- bordered-->
<!-- style="margin-top: 30px"-->
<!-- >-->
<!-- <a-descriptions-item label="相关项目">-->
<!-- {{ customer.comments }}-->
<!-- </a-descriptions-item>-->
<!-- </a-descriptions>-->
</div>
</a-form>
</ele-modal>
</template>
<script lang="ts" setup>
import { ref, reactive, watch } from 'vue';
import { Form } from 'ant-design-vue';
import { assignObject } from 'ele-admin-pro';
import type { Customer } from '@/api/oa/customer/model';
import { FILE_SERVER } from '@/config/setting';
import { getDictionaryOptions } from '@/utils/common';
const useForm = Form.useForm;
const props = defineProps<{
// 弹窗是否打开
visible: boolean;
// 修改回显的数据
data?: Customer | null;
}>();
const emit = defineEmits<{
(e: 'done'): void;
(e: 'update:visible', visible: boolean): void;
}>();
// 用户信息
const customer = reactive<Customer>({
customerCode: '',
customerName: '',
customerType: undefined,
customerMobile: '',
customerAvatar: '',
customerPhone: '',
customerContacts: '',
customerAddress: '',
comments: '',
progress: '',
status: '0',
sortNumber: 100,
customerId: 0
});
// 请求状态
const loading = ref(true);
const { resetFields } = useForm(customer);
/* 更新visible */
const updateVisible = (value: boolean) => {
emit('update:visible', value);
};
/* 打开外部链接 */
// const openUrl = (record) => {
// window.open(record.panel);
// };
/* 获取字典数据 */
const customerType = getDictionaryOptions('customerType');
const progress = getDictionaryOptions('customerFollowStatus');
watch(
() => props.visible,
(visible) => {
if (visible) {
if (props.data) {
loading.value = false;
assignObject(customer, props.data);
}
} else {
resetFields();
}
}
);
</script>
<style lang="less">
.tab-pane {
min-height: 100px;
}
.card-head {
display: flex;
height: 40px;
align-items: center;
margin-bottom: 30px;
}
</style>

View File

@@ -0,0 +1,205 @@
<!-- 搜索表单 -->
<template>
<a-space :size="10" style="flex-wrap: wrap">
<a-button type="primary" class="ele-btn-icon" @click="add">
<template #icon>
<PlusOutlined />
</template>
<span>新增</span>
</a-button>
<a-button
danger
type="primary"
class="ele-btn-icon"
v-if="selection.length > 0"
@click="removeBatch"
>
<template #icon>
<DeleteOutlined />
</template>
<span>批量删除</span>
</a-button>
<!-- <a-button @click="batchMove" v-if="selection.length > 0">-->
<!-- <template #icon>-->
<!-- <UserSwitchOutlined />-->
<!-- </template>-->
<!-- 批量转移-->
<!-- </a-button>-->
<a-input-search
allow-clear
placeholder="请输入关键词"
v-model:value="searchText"
@pressEnter="search"
@search="search"
/>
</a-space>
</template>
<script lang="ts" setup>
import {
PlusOutlined,
DeleteOutlined,
UploadOutlined,
DownloadOutlined
} from '@ant-design/icons-vue';
import useSearch from '@/utils/use-search';
import type { CustomerParam } from '@/api/oa/customer/model';
import { ref, watch } from 'vue';
import { utils, read } from 'xlsx';
// import { assignObject } from 'ele-admin-pro';
import { message } from 'ant-design-vue/es';
const props = withDefaults(
defineProps<{
// 选中的角色
selection?: [];
}>(),
{}
);
const emit = defineEmits<{
(e: 'search', where?: CustomerParam): void;
(e: 'add'): void;
(e: 'remove'): void;
(e: 'batchMove'): void;
}>();
// 表单数据
const { where } = useSearch<CustomerParam>({
name: '',
creditCode: '',
keywords: '',
userId: undefined
});
// 下来选项
// 搜索内容
const searchText = ref('');
/* 搜索 */
const search = () => {
where.keywords = searchText.value;
emit('search', where);
};
// 新增
const add = () => {
emit('add');
};
// 导入数据的列
const importTitle = ref<string[]>(['A', 'B', 'C', 'D', 'E', 'F', 'G']);
// 导入的数据
const importData = ref<Record<string, any>[]>([]);
// 导入数据二维数组形式
const importDataAoa = ref<(string | number)[][]>([]);
/* 导入本地 excel 文件 */
const importBatch = (file: File) => {
if (
![
'application/vnd.ms-excel',
'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
].includes(file.type)
) {
message.error('只能选择 excel 文件');
return false;
}
if (file.size / 1024 / 1024 > 20) {
message.error('大小不能超过 20MB');
return false;
}
const reader = new FileReader();
reader.onload = (e) => {
const data = new Uint8Array(e.target?.result as any);
const workbook = read(data, { type: 'array' });
const sheetNames = workbook.SheetNames;
const worksheet = workbook.Sheets[sheetNames[0]];
// 解析成二维数组
const aoa = utils.sheet_to_json<string[]>(worksheet, { header: 1 });
// 生成表格需要的数据
let list: Record<string, any>[] = [];
let maxCols = 0;
let title: string[] = [];
aoa.forEach((d) => {
if (d.length > maxCols) {
maxCols = d.length;
}
const row = {};
for (let i = 0; i < d.length; i++) {
const key = getCharByIndex(i);
row[key] = d[i];
row['__colspan__' + key] = 1;
row['__rowspan__' + key] = 1;
}
list.push(row);
});
for (let i = 0; i < maxCols; i++) {
title.push(getCharByIndex(i));
}
importTitle.value = title;
importData.value = list;
importDataAoa.value = aoa;
};
console.log(importData.value);
console.log(importDataAoa.value);
reader.readAsArrayBuffer(file);
return false;
};
/* 生成Excel列字母序号 */
const getCharByIndex = (index: number) => {
const chars = [
'A',
'B',
'C',
'D',
'E',
'F',
'G',
'H',
'I',
'J',
'K',
'L',
'M',
'N',
'O',
'P',
'Q',
'R',
'S',
'T',
'U',
'V',
'W',
'X',
'Y',
'Z'
];
if (index < chars.length) {
return chars[index];
}
const n = parseInt(String(index / chars.length));
const m = index % chars.length;
return chars[n] + chars[m];
};
// 转移
// const batchMove = () => {
// emit('batchMove');
// };
// 批量删除
const removeBatch = () => {
emit('remove');
};
const onClear = () => {
where.userId = undefined;
search();
};
watch(
() => props.selection,
() => {}
);
</script>

View File

@@ -0,0 +1,95 @@
<template>
<a-table ref="tableRef"
row-key="contractSettleId" :dataSource="dataList" :columns="columns">
<template #bodyCell="{ column, record, index }">
<template v-if="column.key === 'amount'">
<a-input v-model:value="record.amount" type="number" @change="changeItem($event, index)">
<template #suffix></template>
</a-input>
</template>
<template v-if="column.key === 'num'">
<a-input v-model:value="record.num" type="number" @change="changeItem($event, index)">
<template #suffix></template>
</a-input>
</template>
<template v-if="column.key === 'action'">
<div class="flex justify-center items-center">
<close-circle-outlined style="font-size: 1.5rem; color: pink;cursor: pointer"
@click.native="del(index)" />
</div>
</template>
</template>
</a-table>
</template>
<script setup lang="ts">
import { onMounted, ref, watch } from "vue";
import { ColumnItem } from "ele-admin-pro/es/ele-pro-table/types";
import { assignObject, EleProTable } from "ele-admin-pro";
import {
CloseCircleOutlined
} from "@ant-design/icons-vue";
import { FinalSettleLost } from "@/api/tower/finalSettleLost/model";
const props = defineProps<{
dataSource: FinalSettleLost[]
}>();
const tableRef = ref<InstanceType<typeof EleProTable> | null>(null);
const emits = defineEmits(["total"]);
const columns = ref<ColumnItem[]>([
{
title: "序号",
key: "index",
width: 48,
align: "center",
fixed: "left",
hideInSetting: true,
customRender: ({ index }) => index + (tableRef.value?.tableIndex ?? 1)
},
{
title: "配件名称",
dataIndex: "itemName"
},
{
title: "赔偿单价",
dataIndex: "amount",
key: "amount"
},
{
title: "赔偿数量",
dataIndex: "num",
key: "num"
},
{
title: "赔偿总额",
dataIndex: "total",
},
{
title: "操作",
dataIndex: "action",
key: "action"
}
]);
const changeItem = (value, index) => {
dataList.value[index].total = parseFloat(dataList.value[index].amount) * parseInt(dataList.value[index].num);
};
const dataList = ref<FinalSettleLost[]>([]);
const del = (index: number) => {
dataList.value.splice(index, 1);
};
watch(
() => props.dataSource,
(dataSource) => {
dataList.value = dataSource;
},
{ deep: true }
);
defineExpose({ dataList });
</script>

View File

@@ -0,0 +1,269 @@
<template>
<div class="page">
<div class="ele-body">
<a-card :bordered="false" :body-style="{ padding: '16px' }">
<ele-pro-table
ref="tableRef"
row-key="contractFinalSettleId"
:columns="columns"
:datasource="datasource"
v-model:selection="selection"
tool-class="ele-toolbar-form"
:scroll="{ x: 800 }"
class="sys-org-table"
>
<template #toolbar>
<search
@search="reload"
:selection="selection"
@add="openEdit"
@remove="removeBatch"
@batchMove="openMove"
/>
</template>
<template #bodyCell="{ column, record }">
<template v-if="column.key === 'status'">
<span>{{ INCOME_STATUS_LIST[record.status] }}</span>
</template>
<template v-if="column.key === 'createTime'">
<a-tooltip :title="`${toDateString(record.createTime)}`">
{{ timeAgo(record.createTime) }}
</a-tooltip>
</template>
<template v-if="column.key === 'action'">
<a-space>
<a @click="openEdit(record)">修改</a>
<a-divider type="vertical" />
<a-popconfirm
title="确定要删除此记录吗?"
@confirm="remove(record)"
>
<a class="ele-text-danger">删除</a>
</a-popconfirm>
</a-space>
</template>
</template>
</ele-pro-table>
</a-card>
<!-- 编辑弹窗 -->
<Edit v-model:visible="showEdit" :data="current" @done="reload" />
<!-- 合同详情弹窗 -->
<Info v-model:visible="showInfo" :data="current" @done="reload" />
<!-- 批量转移弹窗 -->
<!-- <CustomerMove v-model:visible="showMove" :data="selection" @done="batchMove" />-->
</div>
</div>
</template>
<script lang="ts" setup>
import { computed, createVNode, ref } from "vue";
import { message, Modal } from "ant-design-vue";
import {
ExclamationCircleOutlined,
UserOutlined
} from "@ant-design/icons-vue";
import type { EleProTable } from "ele-admin-pro";
import type {
DatasourceFunction,
ColumnItem
} from "ele-admin-pro/es/ele-pro-table/types";
import { toDateString } from "ele-admin-pro";
import Search from "./components/search.vue";
import Edit from "./components/edit.vue";
import Info from "./components/info.vue";
import { timeAgo } from "ele-admin-pro";
import { useUserStore } from "@/store/modules/user";
import { FinalSettle, FinalSettleParam } from "@/api/tower/finalSettle/model";
import { pageFinalSettle, removeBatchFinalSettle, removeFinalSettle } from "@/api/tower/finalSettle";
const userStore = useUserStore();
// 当前用户信息
const loginUser = computed(() => userStore.info ?? {});
// 表格实例
const tableRef = ref<InstanceType<typeof EleProTable> | null>(null);
// 表格选中数据
const selection = ref<FinalSettle[]>([]);
// 当前编辑数据
const current = ref<FinalSettle | null>(null);
// 是否显示资产详情
const showInfo = ref(false);
// 是否显示编辑弹窗
const showEdit = ref(false);
// 是否显示批量移动弹窗
const showMove = ref(false);
// 表格数据源
const datasource: DatasourceFunction = ({
page,
limit,
where,
orders,
filters
}) => {
if (filters) {
where.status = filters.status;
}
return pageFinalSettle({
...where,
...orders,
page,
limit
});
};
// 表格列配置
const columns = ref<ColumnItem[]>([
{
key: "index",
width: 48,
align: "center",
fixed: "left",
hideInSetting: true,
customRender: ({ index }) => index + (tableRef.value?.tableIndex ?? 0)
},
{
title: "合同编号",
dataIndex: "contactNumber"
},
{
title: "项目名称",
dataIndex: "projectName"
},
{
title: "承租单位",
dataIndex: "customerName"
},
{
title: "结算单位",
dataIndex: "companyName"
},
{
title: "结算日期",
dataIndex: "signDate"
},
{
title: "结算总金额",
dataIndex: "totalSettleAmount"
},
{
title: "登记人员",
dataIndex: "signName"
},
{
title: "操作日期",
dataIndex: "createtime"
},
{
title: "操作",
key: "action",
width: 200,
align: "center",
hideInSetting: true
}
]);
/* 搜索 */
const reload = (where?: FinalSettleParam) => {
selection.value = [];
tableRef?.value?.reload({ where: where });
};
/* 打开编辑弹窗 */
const openEdit = (row?: FinalSettle) => {
current.value = row ?? null;
showEdit.value = true;
};
const showSettle = ref<Boolean>(false);
const openSettle = (row?: FinalSettle) => {
current.value = row ?? null;
showSettle.value = true;
};
/* 打开批量移动弹窗 */
const openMove = () => {
showMove.value = true;
};
/* 打开用户详情弹窗 */
const openInfo = (row?: FinalSettle) => {
current.value = row ?? null;
showInfo.value = true;
};
/* 删除单个 */
const remove = (row: FinalSettle) => {
const hide = message.loading("请求中..", 0);
removeFinalSettle(row.contractFinalSettleId)
.then((msg) => {
hide();
message.success(msg);
reload();
})
.catch((e) => {
hide();
message.error(e.message);
});
};
/* 批量转移 */
const batchMove = (userId) => {
console.log(userId, "批量转移0000");
console.log(selection.value);
};
/* 批量删除 */
const removeBatch = () => {
if (!selection.value.length) {
message.error("请至少选择一条数据");
return;
}
Modal.confirm({
title: "提示",
content: "确定要删除选中的记录吗?",
icon: createVNode(ExclamationCircleOutlined),
maskClosable: true,
onOk: () => {
const hide = message.loading("请求中..", 0);
removeBatchFinalSettle(
selection.value.map((d) => {
if (loginUser.value.userId === d.userId) {
return d.contractFinalSettleId;
}
})
)
.then((msg) => {
hide();
message.success(msg);
reload();
})
.catch((e) => {
hide();
message.error(e.message);
});
}
});
};
</script>
<script lang="ts">
export default {
name: "Accessory"
};
</script>
<style lang="less" scoped>
.sys-org-table :deep(.ant-table-body) {
overflow: auto !important;
overflow: overlay !important;
}
.sys-org-table :deep(.ant-table-pagination.ant-pagination) {
padding: 0 4px;
margin-bottom: 0;
}
</style>

View File

@@ -0,0 +1,441 @@
<!-- 用户编辑弹窗 -->
<template>
<ele-modal
:width="'90%'"
:visible="visible"
:confirm-loading="loading"
:maskClosable="false"
:maxable="maxable"
:title="isUpdate ? '编辑收款' : '添加收款'"
:body-style="{ paddingBottom: '8px' }"
@update:visible="updateVisible"
@ok="save"
>
<a-form
:label-col="{ md: { span: 4 }, sm: { span: 4 }, xs: { span: 4 } }"
:label-align="'left'"
:wrapper-col="{ md: { span: 24 }, sm: { span: 20 }, xs: { span: 24 } }"
>
<a-card title="填报人信息" :bordered="false">
<a-row :gutter="16">
<a-col :md="12" :sm="24" :xs="24">
<a-form-item label="填报人">
<a-input disabled v-model:value="loginUser.username" />
</a-form-item>
</a-col>
<a-col :md="12" :sm="24" :xs="24">
<a-form-item label="填报时间">
<a-input disabled v-model:value="now" />
</a-form-item>
</a-col>
</a-row>
</a-card>
<a-card title="合同信息" :bordered="false">
<a-row :gutter="16">
<a-col :md="8" :sm="24" :xs="24">
<a-form-item label="合同编号" v-bind="validateInfos.contractId">
<TowerContractSelectModel
:placeholder="`请选择合同`"
v-model:value="form.contractNumber"
@done="chooseContract"
/>
</a-form-item>
<a-form-item label="承租单位">
<p style="margin: 0">{{ form.customerName }}</p>
</a-form-item>
<a-form-item label="累计开票金额">
<p style="margin: 0">{{ form.totalInvoicingAmount }}</p>
</a-form-item>
</a-col>
<a-col :md="8" :sm="24" :xs="24">
<a-form-item label="签订日期">
<p style="margin: 0">{{ form.signDate }}</p>
</a-form-item>
<a-form-item label="租赁单位">
<p style="margin: 0">{{ form.companyName }}</p>
</a-form-item>
</a-col>
<a-col :md="8" :sm="24" :xs="24">
<a-form-item label="项目名称">
<p style="margin: 0">{{ form.projectName }}</p>
</a-form-item>
<a-form-item label="累计收款">
<p style="margin: 0">{{ form.totalIncomeAmount }}</p>
</a-form-item>
</a-col>
</a-row>
</a-card>
<a-card title="收款信息" :bordered="false">
<a-row :gutter="16">
<a-col :md="8" :sm="24" :xs="24">
<a-form-item label="收款单号">
<a-input v-model:value="form.incomeNo" placeholder="请输入收款单号" />
</a-form-item>
<a-form-item label="收款金额" v-bind="validateInfos.amount">
<a-input v-model:value="form.amount" placeholder="请输入收款金额" type="number">
<template #addonAfter></template>
</a-input>
</a-form-item>
<a-form-item label="预计收款日期">
<a-date-picker
class="ele-fluid"
placeholder="请选择预计收款日期"
v-model:value="form.expectIncomeDate"
valueFormat="YYYY-MM-DD"
/>
</a-form-item>
</a-col>
<a-col :md="8" :sm="24" :xs="24">
<a-form-item label="收款日期" v-bind="validateInfos.incomeDate">
<a-date-picker
class="ele-fluid"
placeholder="请选择收款日期"
v-model:value="form.incomeDate"
valueFormat="YYYY-MM-DD"
/>
</a-form-item>
<a-form-item label="收款类型">
<a-select placeholder="请选择收款类型" style="width: 250px" size="small"
v-model:value="form.incomeType">
<a-select-option value="直租">直租</a-select-option>
<a-select-option value="转租">转租</a-select-option>
</a-select>
</a-form-item>
<a-form-item label="预计收款金额">
<a-input v-model:value="form.expectIncomeAmount" placeholder="请输入预计收款金额" type="number">
<template #addonAfter></template>
</a-input>
</a-form-item>
</a-col>
<a-col :md="8" :sm="24" :xs="24">
<a-form-item label="收款单位" v-bind="validateInfos.incomeCompanyId">
<SelectCustomer
:placeholder="`请选择收款单位`"
v-model:value="form.incomeCompanyName"
@done="chooseIncomeCompany"
/>
</a-form-item>
<a-form-item label="付款单位">
<SelectCompany
:placeholder="`请选择付款单位`"
v-model:value="form.payCompanyName"
@done="choosePayCompany"
/>
</a-form-item>
<a-form-item label="登记人" v-bind="validateInfos.signName">
<UserChoose @select="selectSignName" />
</a-form-item>
</a-col>
</a-row>
<a-form-item label="收款方式" :label-col="{ md: { span: 1 }, sm: { span: 1 }, xs: { span: 1 } }">
<DictSelect
dict-code="ContractIncomeMethod"
placeholder="请选择收款方式"
v-model:value="form.incomeMethod"
/>
</a-form-item>
<a-form-item label="发票号" :label-col="{ md: { span: 1 }, sm: { span: 1 }, xs: { span: 1 } }">
<a-input v-model:value="form.invoicingNo" placeholder="请输入发票号" />
</a-form-item>
<a-form-item label="备注" :label-col="{ md: { span: 1 }, sm: { span: 1 }, xs: { span: 1 } }">
<a-input v-model:value="form.remark" placeholder="请输入备注说明" />
</a-form-item>
<a-form-item label="附件" name="parentId">
<a-upload
v-model:file-list="fileList"
name="file"
action="https://file.wsdns.cn/api/file/image"
:headers="{ Authorization: token }"
@change="onFile"
>
<a-button>
<upload-outlined />
上传
</a-button>
</a-upload>
</a-form-item>
</a-card>
<a-card title="费用设备分摊">
<a-button @click.native="showSelectSettle = true" type="primary" :disabled="!form.contractId">新增
</a-button>
<Table :data-source="settleList" />
</a-card>
</a-form>
</ele-modal>
<ele-modal
:width="'80%'"
:visible="showSelectSettle"
:maskClosable="false"
title="选择设备"
:body-style="{ paddingBottom: '8px' }"
@update:visible="showSelectSettle"
@cancel="showSelectSettle = false"
@ok="showSelectSettle = false"
>
<a-row :gutter="16">
<a-col :span="6">设备名称</a-col>
<a-col :span="6">设备型号</a-col>
<a-col :span="6">租金</a-col>
<a-col :span="6">操作</a-col>
</a-row>
<a-row :gutter="16" class="my-05" v-for="(item, index) in contractSettleList" :key="index">
<a-col :span="6">{{ item.equipmentName }}</a-col>
<a-col :span="6">{{ item.equipmentModel }}</a-col>
<a-col :span="6">{{ item.rentAmount }}</a-col>
<a-col :span="6">
<a-button type="link" @click.native="selectSettle(item)">选择</a-button>
</a-col>
</a-row>
</ele-modal>
</template>
<script lang="ts" setup>
import { ref, reactive, watch, computed } from "vue";
import { Form, message } from "ant-design-vue";
import { assignObject, EleProTable } from "ele-admin-pro";
import { useUserStore } from "@/store/modules/user";
import dayjs from "dayjs";
import { Contract } from "@/api/tower/contract/model";
import Table from "./table.vue";
import { Company } from "@/api/system/company/model";
import { User } from "@/api/user/model";
import { TOKEN_STORE_NAME } from "@/config/setting";
import { UploadOutlined } from "@ant-design/icons-vue";
import { addIncome, updateIncome } from "@/api/tower/income";
import { Income } from "@/api/tower/income/model";
import { IncomeEquipment } from "@/api/tower/incomeEquipment/model";
import { addBatchIncomeEquipment } from "@/api/tower/incomeEquipment";
import { ContractSettleEquipment } from "@/api/tower/contractSettle/equipment/model";
import { listContractEquipment } from "@/api/tower/contractEquipment";
import { ContractEquipment } from "@/api/tower/contractEquipment/model";
import { Customer } from "@/api/oa/customer/model";
const userStore = useUserStore();
const token = localStorage.getItem(TOKEN_STORE_NAME);
// 当前用户信息
const loginUser = computed(() => userStore.info ?? {});
const now = dayjs().format("YYYY-MM-DD HH:mm:ss");
// 是否是修改
const isUpdate = ref(false);
const useForm = Form.useForm;
const props = defineProps<{
// 弹窗是否打开
visible: boolean;
// 修改回显的数据
data?: Income | null;
}>();
const emit = defineEmits<{
(e: "done"): void;
(e: "update:visible", visible: boolean): void;
}>();
// 提交状态
const loading = ref(false);
// 是否显示最大化切换按钮
const maxable = ref(true);
const activeKey = ref(0);
const contractSettleList = ref<ContractEquipment[]>([]);
const getContractSettleList = async contractId => {
contractSettleList.value = await listContractEquipment({ contractId });
};
const showSelectSettle = ref(false);
const settleList = ref<IncomeEquipment[]>([]);
const selectSettle = (item: ContractEquipment) => {
settleList.value.push({
incomeEquipmentId: null,
incomeId: null,
equipmentId: item.equipmentId,
equipmentName: item.equipmentName,
equipmentModel: item.equipmentModel,
factoryNo: item.factoryNo,
equipmentNo: item.equipmentNo,
filingNo: item.filingNo,
rentAmount: item.rentAmount,
shareAmount: null
});
showSelectSettle.value = false;
};
const chooseContract = (res: Contract) => {
form.contractNumber = res.contactNumber;
form.contractId = res.contractId;
form.companyName = res.companyName;
form.customerName = res.customerName;
form.signDate = res.signDate;
form.projectName = res.projectName;
form.totalInvoicingAmount = res.totalInvoicingAmount;
form.totalIncomeAmount = res.totalIncomeAmount;
getContractSettleList(res.contractId);
};
const choosePayCompany = ({ companyName, companyId }: Company) => {
form.payCompanyId = companyId;
form.payCompanyName = companyName;
};
const chooseIncomeCompany = ({ customerId, name }: Customer) => {
form.incomeCompanyId = customerId;
form.incomeCompanyName = name;
};
const selectSignName = ({ nickname }: User) => {
form.signName = nickname;
};
const fileList = ref<FileItem[]>([]);
interface FileItem {
uid: string;
name?: string;
status?: string;
response?: Response;
thumbUrl?: string;
downloadUrl?: string;
url: string;
}
interface FileInfo {
file: FileItem;
fileList: FileItem[];
}
const onFile = (info: FileInfo) => {
let resFileList = [...info.fileList];
fileList.value = resFileList.map((file) => {
if (file.response) {
file.url = file.response.url;
}
return file;
});
form.fileList = JSON.stringify(fileList.value);
};
const form = reactive<Income>({
incomeId: "",
contractId: "",
contractNumber: "",
signDate: "",
projectName: "",
customerName: "",
companyName: "",
incomeNo: `I-` + dayjs().format("YYYY-MM-DD"),
incomeCompanyName: "",
incomeCompanyId: "",
payCompanyName: "",
payCompanyId: "",
incomeDate: "",
amount: "",
totalIncomeAmount: "",
totalInvoicingAmount: "",
fileList: "[]",
remark: "",
userId: loginUser.value.userId,
signName: loginUser.value.username
});
/* 更新visible */
const updateVisible = (value: boolean) => {
emit("update:visible", value);
};
// 表单验证规则
const rules = reactive({
contractId: [
{
required: true,
message: "请选择合同",
trigger: "blur"
}
],
amount: [
{
required: true,
message: "请输入收款金额",
trigger: "blur"
}
],
incomeDate: [
{
required: true,
message: "请输入收款日期",
trigger: "blur"
}
],
incomeCompanyId: [
{
required: true,
message: "请选择收款单位",
trigger: "blur"
}
],
signName: [
{
required: true,
message: "请选择登记人员",
trigger: "blur"
}
]
});
const { resetFields, validate, validateInfos } = useForm(form, rules);
/* 保存编辑 */
const save = () => {
validate()
.then(async () => {
loading.value = true;
const data = {
...form
};
const saveOrUpdate = isUpdate.value ? updateIncome : addIncome;
const res = await saveOrUpdate(data).catch((e) => {
message.error(e.message);
});
loading.value = false;
if (settleList.value.length > 0) {
const incomeId = res?.data;
settleList.value.forEach((item, index) => {
settleList.value[index].incomeId = incomeId;
});
await addBatchIncomeEquipment(settleList.value);
}
message.success(res?.message);
updateVisible(false);
emit("done");
})
.catch(() => {
});
};
watch(
() => props.visible,
(visible) => {
if (visible) {
if (props.data) {
loading.value = false;
assignObject(form, props.data);
isUpdate.value = true;
} else {
isUpdate.value = false;
}
} else {
resetFields();
}
}
);
</script>
<style lang="less">
.title {
font-weight: bold;
font-size: 1.1rem;
padding-bottom: 10px;
border-bottom: 1px solid #dcdfe6;
color: #494949;
margin-bottom: 10px;
}
</style>

View File

@@ -0,0 +1,148 @@
<!-- 用户编辑弹窗 -->
<template>
<ele-modal
width="75%"
:visible="visible"
:confirm-loading="loading"
:title="'合同详情'"
:maxable="true"
:body-style="{ paddingBottom: '8px' }"
@update:visible="updateVisible"
:footer="null"
>
<a-form
:label-col="{ md: { span: 4 }, sm: { span: 24 } }"
:wrapper-col="{ md: { span: 19 }, sm: { span: 24 } }"
>
<div class="base-form" style="margin-bottom: 20px">
<a-descriptions bordered>
<a-descriptions-item label="合同名称">
{{ customer.customerName }}
</a-descriptions-item>
<a-descriptions-item label="社会统一信用代码">
{{ customer.customerCode }}
</a-descriptions-item>
<a-descriptions-item label="跟进状态">
<div color="blue" v-for="(d, index) in progress" :key="index">
<span v-if="d.value == customer.progress">{{ d.label }}</span>
</div>
</a-descriptions-item>
<a-descriptions-item label="联系人">
{{ customer.customerContacts }}
</a-descriptions-item>
<a-descriptions-item label="联系电话">
{{ customer.customerMobile }}
</a-descriptions-item>
<a-descriptions-item label="座机电话">
{{ customer.customerPhone }}
</a-descriptions-item>
<a-descriptions-item label="合同类型">
<div color="blue" v-for="(d, index) in customerType" :key="index">
<span v-if="d.value == customer.customerType">{{ d.value }}</span>
</div>
</a-descriptions-item>
<a-descriptions-item label="联系地址">
{{ customer.customerAddress }}
</a-descriptions-item>
<a-descriptions-item label="备注">
{{ customer.comments }}
</a-descriptions-item>
</a-descriptions>
<!-- <a-descriptions-->
<!-- title="其他信息"-->
<!-- :column="1"-->
<!-- bordered-->
<!-- style="margin-top: 30px"-->
<!-- >-->
<!-- <a-descriptions-item label="相关项目">-->
<!-- {{ customer.comments }}-->
<!-- </a-descriptions-item>-->
<!-- </a-descriptions>-->
</div>
</a-form>
</ele-modal>
</template>
<script lang="ts" setup>
import { ref, reactive, watch } from 'vue';
import { Form } from 'ant-design-vue';
import { assignObject } from 'ele-admin-pro';
import type { Customer } from '@/api/oa/customer/model';
import { FILE_SERVER } from '@/config/setting';
import { getDictionaryOptions } from '@/utils/common';
const useForm = Form.useForm;
const props = defineProps<{
// 弹窗是否打开
visible: boolean;
// 修改回显的数据
data?: Customer | null;
}>();
const emit = defineEmits<{
(e: 'done'): void;
(e: 'update:visible', visible: boolean): void;
}>();
// 用户信息
const customer = reactive<Customer>({
customerCode: '',
customerName: '',
customerType: undefined,
customerMobile: '',
customerAvatar: '',
customerPhone: '',
customerContacts: '',
customerAddress: '',
comments: '',
progress: '',
status: '0',
sortNumber: 100,
customerId: 0
});
// 请求状态
const loading = ref(true);
const { resetFields } = useForm(customer);
/* 更新visible */
const updateVisible = (value: boolean) => {
emit('update:visible', value);
};
/* 打开外部链接 */
// const openUrl = (record) => {
// window.open(record.panel);
// };
/* 获取字典数据 */
const customerType = getDictionaryOptions('customerType');
const progress = getDictionaryOptions('customerFollowStatus');
watch(
() => props.visible,
(visible) => {
if (visible) {
if (props.data) {
loading.value = false;
assignObject(customer, props.data);
}
} else {
resetFields();
}
}
);
</script>
<style lang="less">
.tab-pane {
min-height: 100px;
}
.card-head {
display: flex;
height: 40px;
align-items: center;
margin-bottom: 30px;
}
</style>

View File

@@ -0,0 +1,205 @@
<!-- 搜索表单 -->
<template>
<a-space :size="10" style="flex-wrap: wrap">
<a-button type="primary" class="ele-btn-icon" @click="add">
<template #icon>
<PlusOutlined />
</template>
<span>新增</span>
</a-button>
<a-button
danger
type="primary"
class="ele-btn-icon"
v-if="selection.length > 0"
@click="removeBatch"
>
<template #icon>
<DeleteOutlined />
</template>
<span>批量删除</span>
</a-button>
<!-- <a-button @click="batchMove" v-if="selection.length > 0">-->
<!-- <template #icon>-->
<!-- <UserSwitchOutlined />-->
<!-- </template>-->
<!-- 批量转移-->
<!-- </a-button>-->
<a-input-search
allow-clear
placeholder="请输入关键词"
v-model:value="searchText"
@pressEnter="search"
@search="search"
/>
</a-space>
</template>
<script lang="ts" setup>
import {
PlusOutlined,
DeleteOutlined,
UploadOutlined,
DownloadOutlined
} from '@ant-design/icons-vue';
import useSearch from '@/utils/use-search';
import type { CustomerParam } from '@/api/oa/customer/model';
import { ref, watch } from 'vue';
import { utils, read } from 'xlsx';
// import { assignObject } from 'ele-admin-pro';
import { message } from 'ant-design-vue/es';
const props = withDefaults(
defineProps<{
// 选中的角色
selection?: [];
}>(),
{}
);
const emit = defineEmits<{
(e: 'search', where?: CustomerParam): void;
(e: 'add'): void;
(e: 'remove'): void;
(e: 'batchMove'): void;
}>();
// 表单数据
const { where } = useSearch<CustomerParam>({
name: '',
creditCode: '',
keywords: '',
userId: undefined
});
// 下来选项
// 搜索内容
const searchText = ref('');
/* 搜索 */
const search = () => {
where.keywords = searchText.value;
emit('search', where);
};
// 新增
const add = () => {
emit('add');
};
// 导入数据的列
const importTitle = ref<string[]>(['A', 'B', 'C', 'D', 'E', 'F', 'G']);
// 导入的数据
const importData = ref<Record<string, any>[]>([]);
// 导入数据二维数组形式
const importDataAoa = ref<(string | number)[][]>([]);
/* 导入本地 excel 文件 */
const importBatch = (file: File) => {
if (
![
'application/vnd.ms-excel',
'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
].includes(file.type)
) {
message.error('只能选择 excel 文件');
return false;
}
if (file.size / 1024 / 1024 > 20) {
message.error('大小不能超过 20MB');
return false;
}
const reader = new FileReader();
reader.onload = (e) => {
const data = new Uint8Array(e.target?.result as any);
const workbook = read(data, { type: 'array' });
const sheetNames = workbook.SheetNames;
const worksheet = workbook.Sheets[sheetNames[0]];
// 解析成二维数组
const aoa = utils.sheet_to_json<string[]>(worksheet, { header: 1 });
// 生成表格需要的数据
let list: Record<string, any>[] = [];
let maxCols = 0;
let title: string[] = [];
aoa.forEach((d) => {
if (d.length > maxCols) {
maxCols = d.length;
}
const row = {};
for (let i = 0; i < d.length; i++) {
const key = getCharByIndex(i);
row[key] = d[i];
row['__colspan__' + key] = 1;
row['__rowspan__' + key] = 1;
}
list.push(row);
});
for (let i = 0; i < maxCols; i++) {
title.push(getCharByIndex(i));
}
importTitle.value = title;
importData.value = list;
importDataAoa.value = aoa;
};
console.log(importData.value);
console.log(importDataAoa.value);
reader.readAsArrayBuffer(file);
return false;
};
/* 生成Excel列字母序号 */
const getCharByIndex = (index: number) => {
const chars = [
'A',
'B',
'C',
'D',
'E',
'F',
'G',
'H',
'I',
'J',
'K',
'L',
'M',
'N',
'O',
'P',
'Q',
'R',
'S',
'T',
'U',
'V',
'W',
'X',
'Y',
'Z'
];
if (index < chars.length) {
return chars[index];
}
const n = parseInt(String(index / chars.length));
const m = index % chars.length;
return chars[n] + chars[m];
};
// 转移
// const batchMove = () => {
// emit('batchMove');
// };
// 批量删除
const removeBatch = () => {
emit('remove');
};
const onClear = () => {
where.userId = undefined;
search();
};
watch(
() => props.selection,
() => {}
);
</script>

View File

@@ -0,0 +1,98 @@
<template>
<a-table ref="tableRef"
row-key="contractSettleId" :dataSource="dataList" :columns="columns">
<template #bodyCell="{ column, record, index }">
<template v-if="column.key === 'shareAmount'">
<a-input v-model:value="record.shareAmount" type="number">
<template #suffix></template>
</a-input>
</template>
<template v-if="column.key === 'action'">
<div class="flex justify-center items-center">
<close-circle-outlined style="font-size: 1.5rem; color: pink;cursor: pointer"
@click.native="del(index)" />
</div>
</template>
</template>
</a-table>
</template>
<script setup lang="ts">
import { onMounted, ref, watch } from "vue";
import { ColumnItem } from "ele-admin-pro/es/ele-pro-table/types";
import { assignObject, EleProTable } from "ele-admin-pro";
import {
CloseCircleOutlined
} from "@ant-design/icons-vue";
import { InvoicingSettle } from "@/api/tower/invoicingSettle/model";
import { IncomeEquipment } from "@/api/tower/incomeEquipment/model";
const props = defineProps<{
dataSource: InvoicingSettle[]
}>();
const tableRef = ref<InstanceType<typeof EleProTable> | null>(null);
const emits = defineEmits(["total"]);
const columns = ref<ColumnItem[]>([
{
title: "序号",
key: "index",
width: 48,
align: "center",
fixed: "left",
hideInSetting: true,
customRender: ({ index }) => index + (tableRef.value?.tableIndex ?? 1)
},
{
title: "设备名称",
dataIndex: "equipmentName"
},
{
title: "设备型号",
dataIndex: "equipmentModel"
},
{
title: "出场编号",
dataIndex: "factoryNo"
},
{
title: "自编号",
dataIndex: "equipmentNo"
},
{
title: "备案编号",
dataIndex: "filingNo"
},
{
title: "租金",
dataIndex: "rentAmount"
},
{
title: "分摊费用",
dataIndex: "shareAmount",
key: "shareAmount"
},
{
title: "操作",
dataIndex: "action",
key: "action"
}
]);
const dataList = ref<IncomeEquipment[]>([]);
const del = (index: number) => {
dataList.value.splice(index, 1);
};
watch(
() => props.dataSource,
(dataSource) => {
dataList.value = dataSource;
},
{ deep: true }
);
defineExpose({ dataList });
</script>

View File

@@ -0,0 +1,286 @@
<template>
<div class="page">
<div class="ele-body">
<a-card :bordered="false" :body-style="{ padding: '16px' }">
<ele-pro-table
ref="tableRef"
row-key="incomeId"
:columns="columns"
:datasource="datasource"
v-model:selection="selection"
tool-class="ele-toolbar-form"
:scroll="{ x: 800 }"
class="sys-org-table"
>
<template #toolbar>
<search
@search="reload"
:selection="selection"
@add="openEdit"
@remove="removeBatch"
@batchMove="openMove"
/>
</template>
<template #bodyCell="{ column, record }">
<template v-if="column.key === 'status'">
<span>{{ INCOME_STATUS_LIST[record.status] }}</span>
</template>
<template v-if="column.key === 'createTime'">
<a-tooltip :title="`${toDateString(record.createTime)}`">
{{ timeAgo(record.createTime) }}
</a-tooltip>
</template>
<template v-if="column.key === 'action'">
<a-space>
<a @click="openEdit(record)">修改</a>
<a-divider type="vertical" />
<a-popconfirm
title="确定要删除此记录吗?"
@confirm="remove(record)"
>
<a class="ele-text-danger">删除</a>
</a-popconfirm>
</a-space>
</template>
</template>
</ele-pro-table>
</a-card>
<!-- 编辑弹窗 -->
<Edit v-model:visible="showEdit" :data="current" @done="reload" />
<!-- 合同详情弹窗 -->
<Info v-model:visible="showInfo" :data="current" @done="reload" />
<!-- 批量转移弹窗 -->
<!-- <CustomerMove v-model:visible="showMove" :data="selection" @done="batchMove" />-->
</div>
</div>
</template>
<script lang="ts" setup>
import { computed, createVNode, ref } from "vue";
import { message, Modal } from "ant-design-vue";
import {
ExclamationCircleOutlined,
UserOutlined
} from "@ant-design/icons-vue";
import type { EleProTable } from "ele-admin-pro";
import type {
DatasourceFunction,
ColumnItem
} from "ele-admin-pro/es/ele-pro-table/types";
import { toDateString } from "ele-admin-pro";
import Search from "./components/search.vue";
import Edit from "./components/edit.vue";
import Info from "./components/info.vue";
import { timeAgo } from "ele-admin-pro";
import { useUserStore } from "@/store/modules/user";
import { Income, INCOME_STATUS_LIST } from "@/api/tower/income/model";
import { pageIncome } from "@/api/tower/income";
import { removeBatchIncome, removeIncome } from "@/api/tower/income";
import { IncomeParam } from "@/api/tower/income/model";
const userStore = useUserStore();
// 当前用户信息
const loginUser = computed(() => userStore.info ?? {});
// 表格实例
const tableRef = ref<InstanceType<typeof EleProTable> | null>(null);
// 表格选中数据
const selection = ref<Income[]>([]);
// 当前编辑数据
const current = ref<Income | null>(null);
// 是否显示资产详情
const showInfo = ref(false);
// 是否显示编辑弹窗
const showEdit = ref(false);
// 是否显示批量移动弹窗
const showMove = ref(false);
// 表格数据源
const datasource: DatasourceFunction = ({
page,
limit,
where,
orders,
filters
}) => {
if (filters) {
where.status = filters.status;
}
return pageIncome({
...where,
...orders,
page,
limit
});
};
// 表格列配置
const columns = ref<ColumnItem[]>([
{
key: "incomeId",
width: 48,
align: "center",
fixed: "left",
hideInSetting: true,
customRender: ({ index }) => index + (tableRef.value?.tableIndex ?? 0)
},
{
title: "收款单号",
dataIndex: "incomeNo"
},
{
title: "收款状态",
dataIndex: "status",
key: "status"
},
{
title: "收款日期",
dataIndex: "incomeDate"
},
{
title: "合同编号",
dataIndex: "contactNumber"
},
{
title: "项目名称",
dataIndex: "projectName"
},
{
title: "承租单位",
dataIndex: "customerName"
},
{
title: "收款单位",
dataIndex: "incomeCompanyName"
},
{
title: "预计收款金额",
dataIndex: "expectIncomeAmount"
},
{
title: "收款金额",
dataIndex: "amount"
},
{
title: "收款方式",
dataIndex: "incomeMethod"
},
{
title: "登记人员",
dataIndex: "signName"
},
{
title: "操作日期",
dataIndex: "createtime"
},
{
title: "操作",
key: "action",
width: 200,
align: "center",
hideInSetting: true
}
]);
/* 搜索 */
const reload = (where?: IncomeParam) => {
selection.value = [];
tableRef?.value?.reload({ where: where });
};
/* 打开编辑弹窗 */
const openEdit = (row?: Income) => {
current.value = row ?? null;
showEdit.value = true;
};
const showSettle = ref<Boolean>(false);
const openSettle = (row?: Income) => {
current.value = row ?? null;
showSettle.value = true;
};
/* 打开批量移动弹窗 */
const openMove = () => {
showMove.value = true;
};
/* 打开用户详情弹窗 */
const openInfo = (row?: Income) => {
current.value = row ?? null;
showInfo.value = true;
};
/* 删除单个 */
const remove = (row: Income) => {
const hide = message.loading("请求中..", 0);
removeIncome(row.incomeId)
.then((msg) => {
hide();
message.success(msg);
reload();
})
.catch((e) => {
hide();
message.error(e.message);
});
};
/* 批量转移 */
const batchMove = (userId) => {
console.log(userId, "批量转移0000");
console.log(selection.value);
};
/* 批量删除 */
const removeBatch = () => {
if (!selection.value.length) {
message.error("请至少选择一条数据");
return;
}
Modal.confirm({
title: "提示",
content: "确定要删除选中的记录吗?",
icon: createVNode(ExclamationCircleOutlined),
maskClosable: true,
onOk: () => {
const hide = message.loading("请求中..", 0);
removeBatchIncome(
selection.value.map((d) => {
return d.incomeId;
})
)
.then((msg) => {
hide();
message.success(msg);
reload();
})
.catch((e) => {
hide();
message.error(e.message);
});
}
});
};
</script>
<script lang="ts">
export default {
name: "Accessory"
};
</script>
<style lang="less" scoped>
.sys-org-table :deep(.ant-table-body) {
overflow: auto !important;
overflow: overlay !important;
}
.sys-org-table :deep(.ant-table-pagination.ant-pagination) {
padding: 0 4px;
margin-bottom: 0;
}
</style>

View File

@@ -0,0 +1,243 @@
<template>
<div class="page">
<div class="ele-body">
<a-card :bordered="false" :body-style="{ padding: '16px' }">
<ele-pro-table
ref="tableRef"
row-key="worksheetId"
:columns="columns"
:datasource="datasource"
v-model:selection="selection"
tool-class="ele-toolbar-form"
:scroll="{ x: 800 }"
class="sys-org-table"
>
<template #toolbar>
<search
@search="reload"
:selection="selection"
@add="openEdit"
@remove="removeBatch"
@batchMove="openMove"
/>
</template>
<template #bodyCell="{ column, record }">
<template v-if="column.key === 'status'">
<span>{{ WORKSHEET_STATUS_LIST[record.status] }}</span>
</template>
<template v-if="column.key === 'equipmentType'">
<span>{{ WORKSHEET_EQUIPMENT_TYPE[record.equipmentType] }}</span>
</template>
<template v-if="column.key === 'workType'">
<span>{{ WORKSHEET_WORK_TYPE[record.workType] }}</span>
</template>
<template v-if="column.key === 'startUser'">
<span>{{ record.startUser ?.nickname }}</span>
</template>
<template v-if="column.key === 'productionMangerUser'">
<span>{{ record.productionMangerUser ?.nickname }}</span>
</template>
<template v-if="column.key === 'documentUser'">
<span>{{ record.documentUser ?.nickname }}</span>
</template>
<template v-if="column.key === 'classManagerUser'">
<span>{{ record.classManagerUser?.nickname }}</span>
</template>
<template v-if="column.key === 'createTime'">
<a-tooltip :title="`${toDateString(record.createTime)}`">
{{ timeAgo(record.createTime) }}
</a-tooltip>
</template>
<template v-if="column.key === 'action'">
<a-space>
<a @click="openInfo(record, 0)">查看安装单派单详情</a>
<a @click="openInfo(record, 1)">查看加高单派单详情</a>
<a @click="openInfo(record, 2)">查看拆卸单派单详情</a>
</a-space>
</template>
</template>
</ele-pro-table>
</a-card>
</div>
<Info v-model:visible="showInfo" :data="current" :work-type="workType"/>
</div>
</template>
<script lang="ts" setup>
import { computed, createVNode, ref } from "vue";
import { message, Modal } from "ant-design-vue";
import {
ExclamationCircleOutlined,
UserOutlined
} from "@ant-design/icons-vue";
import type { EleProTable } from "ele-admin-pro";
import type {
DatasourceFunction,
ColumnItem
} from "ele-admin-pro/es/ele-pro-table/types";
import { toDateString } from "ele-admin-pro";
import Info from "./info.vue";
import { timeAgo } from "ele-admin-pro";
import { useUserStore } from "@/store/modules/user";
import {
Worksheet,
WORKSHEET_EQUIPMENT_TYPE,
WORKSHEET_STATUS_LIST, WORKSHEET_WORK_TYPE,
WorksheetParam
} from "@/api/tower/worksheet/model";
import { pageWorksheet, removeBatchWorksheet, removeWorksheet } from "@/api/tower/worksheet";
const userStore = useUserStore();
// 当前用户信息
const loginUser = computed(() => userStore.info ?? {});
// 表格实例
const tableRef = ref<InstanceType<typeof EleProTable> | null>(null);
// 表格选中数据
const selection = ref<Worksheet[]>([]);
// 当前编辑数据
const current = ref<Worksheet | null>(null);
// 是否显示资产详情
const showInfo = ref(false);
// 是否显示批量移动弹窗
const showMove = ref(false);
// 表格数据源
const datasource: DatasourceFunction = ({
page,
limit,
where,
orders,
filters
}) => {
if (filters) {
where.status = filters.status;
}
return pageWorksheet({
...where,
...orders,
page,
limit
});
};
// 表格列配置
const columns = ref<ColumnItem[]>([
{
key: "index",
width: 48,
align: "center",
fixed: "left",
hideInSetting: true,
customRender: ({ index }) => index + (tableRef.value?.tableIndex ?? 0)
},
{
title: "项目名称",
dataIndex: "projectName"
},
{
title: "操作",
key: "action",
width: 400,
align: "center",
hideInSetting: true
}
]);
/* 搜索 */
const reload = (where?: WorksheetParam) => {
selection.value = [];
tableRef?.value?.reload({ where: where });
};
const showSettle = ref<Boolean>(false);
const openSettle = (row?: Worksheet) => {
current.value = row ?? null;
showSettle.value = true;
};
/* 打开批量移动弹窗 */
const openMove = () => {
showMove.value = true;
};
const workType = ref<number>(0)
/* 打开用户详情弹窗 */
const openInfo = (row: Worksheet, workTypeValue: number) => {
current.value = row;
workType.value = workTypeValue;
showInfo.value = true;
};
/* 删除单个 */
const remove = (row: Worksheet) => {
const hide = message.loading("请求中..", 0);
removeWorksheet(row.worksheetId)
.then((msg) => {
hide();
message.success(msg);
reload();
})
.catch((e) => {
hide();
message.error(e.message);
});
};
/* 批量转移 */
const batchMove = (userId) => {
console.log(userId, "批量转移0000");
console.log(selection.value);
};
/* 批量删除 */
const removeBatch = () => {
if (!selection.value.length) {
message.error("请至少选择一条数据");
return;
}
Modal.confirm({
title: "提示",
content: "确定要删除选中的记录吗?",
icon: createVNode(ExclamationCircleOutlined),
maskClosable: true,
onOk: () => {
const hide = message.loading("请求中..", 0);
removeBatchWorksheet(
selection.value.map((d) => {
return d.worksheetId;
})
)
.then((msg) => {
hide();
message.success(msg);
reload();
})
.catch((e) => {
hide();
message.error(e.message);
});
}
});
};
</script>
<script lang="ts">
export default {
name: "Accessory"
};
</script>
<style lang="less" scoped>
.sys-org-table :deep(.ant-table-body) {
overflow: auto !important;
overflow: overlay !important;
}
.sys-org-table :deep(.ant-table-pagination.ant-pagination) {
padding: 0 4px;
margin-bottom: 0;
}
</style>

View File

@@ -0,0 +1,259 @@
<!-- 用户编辑弹窗 -->
<template>
<ele-modal
:width="`80%`"
:visible="visible"
:confirm-loading="loading"
:maxable="maxAble"
title="派单详情"
:body-style="{ paddingBottom: '8px', background: '#f3f3f3' }"
@update:visible="updateVisible"
:maskClosable="false"
:footer="null"
@ok="save"
>
<a-collapse v-model:activeKey="activeKey" accordion v-if="visible">
<a-collapse-panel
:header="`标地:${info.address}(审核状态:${WORKSHEET_AUDIT_STATUS_LIST[info.auditStatus]},当前状态:${WORKSHEET_STATUS_LIST[info.status]})`"
v-for="(info, index) in list" :key="index.toString()">
<a-card>
<a-descriptions title="人员信息">
<a-descriptions-item :label="`审核人${auditIndex + 1}`" v-for="(audit, auditIndex) in info.auditList"
:key="auditIndex">{{ audit.nickname }}({{ audit.auditStatus === 1 ? "审核通过" : (audit.auditStatus === 2 ? "审核不通过" : "未审核")
}})
</a-descriptions-item>
<a-descriptions-item label="资料员">{{ info.documentUser?.nickname }}({{ info.documentDoneTime ? `完成时间:${dayjs(info.documentDoneTime).format("YYYY-MM-DD HH:mm:ss")}` : "待完成"
}})
</a-descriptions-item>
<a-descriptions-item label="资产管理员">{{ info.assetUser?.nickname }}({{ info.assetDoneTime ? `完成时间:${dayjs(info.assetDoneTime).format('YYYY-MM-DD HH:mm:ss')}` : '待完成' }})
</a-descriptions-item>
<a-descriptions-item label="维保人员">{{ info.fixUser?.nickname }}({{ info.fixDoneTime ? `完成时间:${dayjs(info.fixDoneTime).format('YYYY-MM-DD HH:mm:ss')}` : "待完成"
}})
</a-descriptions-item>
<a-descriptions-item label="生产主管">{{ info.productionMangerUser?.nickname }}
</a-descriptions-item>
<a-descriptions-item label="班组组长">{{ info.classManagerUser?.nickname }}({{ info.status >= 4 ? '已到场' : '待完成' }})
</a-descriptions-item>
<a-descriptions-item label="车辆调度员">{{ info.carDispatchUser?.nickname }}
</a-descriptions-item>
</a-descriptions>
</a-card>
<a-card>
<a-descriptions title="项目信息">
<a-descriptions-item label="派单类型">{{ WORKSHEET_WORK_TYPE[info.detail.workType] }}
</a-descriptions-item>
<a-descriptions-item label="项目名称">{{ info.projectName }}</a-descriptions-item>
<!-- <a-descriptions-item label="项目地址">{{ info.projectRegion + info.projectAddress }}-->
<!-- </a-descriptions-item>-->
<a-descriptions-item label="计划进场时间">{{ info.planInDate }}</a-descriptions-item>
<a-descriptions-item label="到货时间">{{ info.receiveDate }}</a-descriptions-item>
<a-descriptions-item label="项目联系人电话"> {{ info.contactPhone }}</a-descriptions-item>
</a-descriptions>
</a-card>
<a-card>
<a-descriptions title="设备信息">
<a-descriptions-item label="设备名称">{{ info.detail?.equipmentName }}</a-descriptions-item>
<a-descriptions-item label="作业类型">{{ WORKSHEET_TYPE[info.detail?.workType] }}
</a-descriptions-item>
<a-descriptions-item label="设备型号">{{ info.detail?.model }}</a-descriptions-item>
<a-descriptions-item label="出厂编号">{{ info.detail?.factoryNo }}</a-descriptions-item>
<a-descriptions-item label="设备厂家">{{ info.detail.equipment.manufactor }}
</a-descriptions-item>
<a-descriptions-item label="安装臂长">{{ info.detail?.setupLength }}</a-descriptions-item>
<a-descriptions-item label="年份要求"> {{ info.detail?.yearRequest }}</a-descriptions-item>
<a-descriptions-item label="初始安装高度">{{ info.detail?.setupHeight }}</a-descriptions-item>
<a-descriptions-item label="最终安装高度">{{ info.detail?.finalSetupHeight }}
</a-descriptions-item>
<a-descriptions-item label="是否需要油漆">{{ TRUE_OR_FALSE[info.detail?.needPaint] }}
</a-descriptions-item>
<a-descriptions-item label="是否确认道路通畅">{{ TRUE_OR_FALSE[info.detail?.confirmRoad] }}
</a-descriptions-item>
<a-descriptions-item label="是否确认电箱到位">{{ TRUE_OR_FALSE[info.detail?.confirmElectric] }}
</a-descriptions-item>
<a-descriptions-item label="是否确认基础预埋时间满足">
{{ TRUE_OR_FALSE[info.detail?.confirmHasTime] }}
</a-descriptions-item>
<a-descriptions-item label="是否确认安装资料完善"> {{ TRUE_OR_FALSE[info.detail?.confirmProfile]
}}
</a-descriptions-item>
</a-descriptions>
</a-card>
<a-card>
<a-descriptions title="派单信息">
<a-descriptions-item label="作业人员">{{ info.detail?.sysWorkerList }}</a-descriptions-item>
<a-descriptions-item label="外调人员">{{ info.detail?.outComeWorkerList }}</a-descriptions-item>
<a-descriptions-item label="人员类型">
{{ (info.detail) ? WORKER_TYPE[info.detail?.workerType] : "" }}
</a-descriptions-item>
<a-descriptions-item label="班组负责人">{{ info.classManagerUser?.nickname }}
</a-descriptions-item>
<a-descriptions-item label="现场负责人">{{ info.detail?.localeManager }}</a-descriptions-item>
<!-- <a-descriptions-item label="司机"> {{ info.detail?.driver }}</a-descriptions-item>-->
<!-- <a-descriptions-item label="车牌">{{ info.detail?.carPlate }}</a-descriptions-item>-->
<a-descriptions-item label="派单说明">{{ info.detail?.intro }}</a-descriptions-item>
<a-descriptions-item label="备注信息">{{ info.detail?.remark }}</a-descriptions-item>
</a-descriptions>
<a-descriptions title="资料图片" v-if="info.detail && info.detail?.photos">
<a-descriptions-item>
<a-image-preview-group>
<a-image style="margin-right: 1rem"
:width="45"
v-for="(item, index) in info.detail?.photos.split(',')"
:key="index"
:src="item"
/>
</a-image-preview-group>
</a-descriptions-item>
</a-descriptions>
<!-- <a-card title="配件信息">-->
<!-- <a-descriptions v-for="(item, index) in parts" :key="index" :title="item.title">-->
<!-- <a-descriptions-item v-for="(part, partIndex) in item.children" :key="partIndex"-->
<!-- :label="part.partsTitle">-->
<!-- x{{ part.num }}-->
<!-- </a-descriptions-item>-->
<!-- </a-descriptions>-->
<!-- </a-card>-->
</a-card>
<a-card>
<a-descriptions title="安装信息">
<a-descriptions-item label="最高安装高度">{{ info.setUp?.maxSetUpHeight }}
</a-descriptions-item>
<a-descriptions-item label="安装高度">{{ info.setUp?.setUpHeight }}</a-descriptions-item>
<a-descriptions-item label="附着高度">{{ info.setUp?.clingHeight }}</a-descriptions-item>
<a-descriptions-item label="大臂长度">{{ info.setUp?.bigArmLength }}</a-descriptions-item>
<a-descriptions-item label="平衡长度">{{ info.setUp?.balanceLength }}</a-descriptions-item>
<a-descriptions-item label="计划安装附墙数"> {{ info.setUp?.planSetUpCling }}
</a-descriptions-item>
</a-descriptions>
</a-card>
<a-card>
<a-descriptions title="车辆信息">
<a-descriptions-item :label="item.carPlate" v-for="(item, index) in info.carDispatchList"
:key="index">{{ item.name }}({{ item.phone }})
</a-descriptions-item>
</a-descriptions>
</a-card>
<a-card title="到场核验信息">
<a-descriptions title="资料图片" v-if="info.check && info.check?.photos">
<a-descriptions-item>
<a-image-preview-group>
<a-image style="margin-right: 1rem"
:width="45"
v-for="(item, index) in info.check?.photos.split(',')"
:key="index"
:src="item"
/>
</a-image-preview-group>
</a-descriptions-item>
</a-descriptions>
<a-descriptions title="核验信息">
<a-descriptions-item label="现场定位">{{ info.check?.address }}</a-descriptions-item>
<a-descriptions-item label="实际到场时间">{{ info.check?.checkTime }}</a-descriptions-item>
<a-descriptions-item label="核验人">{{ info.check?.nickname }}</a-descriptions-item>
</a-descriptions>
</a-card>
</a-collapse-panel>
</a-collapse>
</ele-modal>
</template>
<script lang="ts" setup>
import { ref, reactive, watch } from "vue";
import { Form } from "ant-design-vue";
import { useThemeStore } from "@/store/modules/theme";
import { storeToRefs } from "pinia";
import { getWorksheet, getWorksheetByWordType } from "@/api/tower/worksheet";
import {
Worksheet,
WORKSHEET_AUDIT_STATUS_LIST,
WORKSHEET_STATUS_LIST,
WORKSHEET_WORK_TYPE
} from "@/api/tower/worksheet/model";
import dayjs from "dayjs";
const useForm = Form.useForm;
// 是否开启响应式布局
const themeStore = useThemeStore();
const { styleResponsive } = storeToRefs(themeStore);
const props = defineProps<{
// 弹窗是否打开
visible: boolean;
// 修改回显的数据
data?: Worksheet | null;
workType: number;
}>();
// 是否显示最大化切换按钮
const maxAble = ref(true);
const active = ref(2);
const emit = defineEmits<{
(e: "done"): void;
(e: "update:visible", visible: boolean): void;
}>();
// 请求状态
const loading = ref(true);
const activeKey = ref<string[]>();
/* 更新visible */
const updateVisible = (value: boolean) => {
emit("update:visible", value);
};
const WORKSHEET_TYPE = ["安装单", "加高单", "拆卸单"];
const TRUE_OR_FALSE = ["否", "是"];
const WORKER_TYPE = ["自有", "外派"];
const list = ref<Worksheet[]>([]);
const parts = ref<any>([]);
const getDetail = () => {
const projectId = props.data?.projectId;
list.value = [];
getWorksheetByWordType(projectId, props.workType).then((data) => {
list.value = data;
// for (let key in data) info[key] = data[key];
// parts.value = [];
// if (info.parts) {
// const parentIdIdList = [];
// info.parts.forEach((item: any) => {
// if (parentIdIdList.indexOf(item.parentId) === -1) {
// parentIdIdList.push(item.parentId);
// parts.value.push({
// title: item.parentPartsTitle,
// parentId: item.parentId,
// children: []
// });
// }
// });
// info.parts.forEach(item => {
// parts.value.forEach((parent, index) => {
// if (item.parentId === parent.parentId) parts.value[index].children.push(item);
// });
// });
// }
});
};
/* 保存编辑 */
const save = () => {
};
watch(
() => props.visible,
(visible) => {
if (visible) {
if (props.data) {
loading.value = false;
getDetail();
}
}
}
);
</script>

View File

@@ -0,0 +1,384 @@
<!-- 用户编辑弹窗 -->
<template>
<ele-modal
:width="'90%'"
:visible="visible"
:confirm-loading="loading"
:maskClosable="false"
:maxable="maxable"
:title="isUpdate ? '编辑开票' : '添加开票'"
:body-style="{ paddingBottom: '8px' }"
@update:visible="updateVisible"
@ok="save"
>
<a-form
:label-col="{ md: { span: 4 }, sm: { span: 4 }, xs: { span: 4 } }"
:label-align="'left'"
:wrapper-col="{ md: { span: 24 }, sm: { span: 20 }, xs: { span: 24 } }"
>
<a-card title="填报人信息" :bordered="false">
<a-row :gutter="16">
<a-col :md="12" :sm="24" :xs="24">
<a-form-item label="填报人">
<a-input disabled v-model:value="loginUser.username" />
</a-form-item>
</a-col>
<a-col :md="12" :sm="24" :xs="24">
<a-form-item label="填报时间">
<a-input disabled v-model:value="now" />
</a-form-item>
</a-col>
</a-row>
</a-card>
<a-card title="合同信息" :bordered="false">
<a-row :gutter="16">
<a-col :md="8" :sm="24" :xs="24">
<a-form-item label="合同编号" v-bind="validateInfos.contractId">
<TowerContractSelectModel
:placeholder="`请选择合同`"
v-model:value="form.contractNumber"
@done="chooseContract"
/>
</a-form-item>
<a-form-item label="承租单位">
<p style="margin: 0">{{ form.customerName }}</p>
</a-form-item>
</a-col>
<a-col :md="8" :sm="24" :xs="24">
<a-form-item label="签订日期">
<p style="margin: 0">{{ form.signDate }}</p>
</a-form-item>
<a-form-item label="租赁单位">
<p style="margin: 0">{{ form.companyName }}</p>
</a-form-item>
</a-col>
<a-col :md="8" :sm="24" :xs="24">
<a-form-item label="项目名称">
<p style="margin: 0">{{ form.projectName }}</p>
</a-form-item>
<a-form-item label="累计开票金额">
<p style="margin: 0">{{ form.totalInvoicingAmount }}</p>
</a-form-item>
</a-col>
</a-row>
</a-card>
<a-card title="开票信息" :bordered="false">
<a-row :gutter="16">
<a-col :md="8" :sm="24" :xs="24">
<a-form-item label="开票日期" v-bind="validateInfos.invoicingDate">
<a-date-picker
class="ele-fluid"
placeholder="请选择开票日期"
v-model:value="form.invoicingDate"
valueFormat="YYYY-MM-DD"
/>
</a-form-item>
<a-form-item label="开票金额" v-bind="validateInfos.invoicingAmount">
<a-input v-model:value="form.invoicingAmount" placeholder="请输入开票金额" type="number">
<template #addonAfter></template>
</a-input>
</a-form-item>
</a-col>
<a-col :md="8" :sm="24" :xs="24">
<a-form-item label="开票单位" v-bind="validateInfos.invoicingCompany">
<SelectCompany
:placeholder="`请选择开票单位`"
v-model:value="form.invoicingCompany"
@done="chooseCompany"
/>
</a-form-item>
<a-form-item label="发票编号">
<a-input v-model:value="form.invoicingNo" placeholder="请输入发票编号" />
</a-form-item>
</a-col>
<a-col :md="8" :sm="24" :xs="24">
<a-form-item label="申请人">
<a-input v-model:value="form.requestName" placeholder="请输入申请人" />
</a-form-item>
<a-form-item label="登记人" v-bind="validateInfos.signName">
<UserChoose @select="selectSignName" />
</a-form-item>
</a-col>
</a-row>
<a-form-item label="备注" :label-col="{ md: { span: 1 }, sm: { span: 1 }, xs: { span: 1 } }">
<a-input v-model:value="form.remark" placeholder="请输入备注说明" />
</a-form-item>
<a-form-item label="附件" name="parentId">
<a-upload
v-model:file-list="fileList"
name="file"
action="https://file.wsdns.cn/api/file/image"
:headers="{ Authorization: token }"
@change="onFile"
>
<a-button>
<upload-outlined />
上传
</a-button>
</a-upload>
</a-form-item>
</a-card>
<a-card title="结算单分摊">
<a-button @click.native="showSelectSettle = true" type="primary" :disabled="!form.contractId">新增
</a-button>
<Table :data-source="settleList" />
</a-card>
</a-form>
</ele-modal>
<ele-modal
:width="'80%'"
:visible="showSelectSettle"
:maskClosable="false"
title="选择结算单"
:body-style="{ paddingBottom: '8px' }"
@update:visible="showSelectSettle"
@cancel="showSelectSettle = false"
@ok="showSelectSettle = false"
>
<a-row :gutter="16">
<a-col :span="6">结算状态</a-col>
<a-col :span="6">结算单号</a-col>
<a-col :span="6">本期结算金额</a-col>
<a-col :span="6">操作</a-col>
</a-row>
<a-row :gutter="16" class="my-05" v-for="(item, index) in contractSettleList" :key="index">
<a-col :span="6">{{ SETTLE_STATUS_LIST[item.status] }}</a-col>
<a-col :span="6">{{ item.settleNo }}</a-col>
<a-col :span="6">{{ item.totalAmount }}</a-col>
<a-col :span="6">
<a-button type="link" @click.native="selectSettle(item)">选择</a-button>
</a-col>
</a-row>
</ele-modal>
</template>
<script lang="ts" setup>
import { ref, reactive, watch, computed } from "vue";
import { Form, message } from "ant-design-vue";
import { assignObject, EleProTable } from "ele-admin-pro";
import { useUserStore } from "@/store/modules/user";
import dayjs from "dayjs";
import { Contract } from "@/api/tower/contract/model";
import Table from "./table.vue";
import { Invoicing } from "@/api/tower/invoicing/model";
import { addInvoicing, updateInvoicing } from "@/api/tower/invoicing";
import { Company } from "@/api/system/company/model";
import { User } from "@/api/user/model";
import { TOKEN_STORE_NAME } from "@/config/setting";
import { UploadOutlined } from "@ant-design/icons-vue";
import { Settle, SETTLE_STATUS_LIST } from "@/api/tower/settle/model";
import { listSettle } from "@/api/tower/settle";
import { InvoicingSettle } from "@/api/tower/invoicingSettle/model";
import { addBatchInvoicingSettle } from "@/api/tower/invoicingSettle";
const userStore = useUserStore();
const token = localStorage.getItem(TOKEN_STORE_NAME);
// 当前用户信息
const loginUser = computed(() => userStore.info ?? {});
const now = dayjs().format("YYYY-MM-DD HH:mm:ss");
// 是否是修改
const isUpdate = ref(false);
const useForm = Form.useForm;
const props = defineProps<{
// 弹窗是否打开
visible: boolean;
// 修改回显的数据
data?: Invoicing | null;
}>();
const emit = defineEmits<{
(e: "done"): void;
(e: "update:visible", visible: boolean): void;
}>();
// 提交状态
const loading = ref(false);
// 是否显示最大化切换按钮
const maxable = ref(true);
const activeKey = ref(0);
const contractSettleList = ref<Settle[]>([]);
const getContractSettleList = async contractId => {
contractSettleList.value = await listSettle({ contractId });
};
const showSelectSettle = ref(false);
const selectSettle = (item: Settle) => {
settleList.value.push({
invoicingId: null,
settleNumber: item.settleNo,
startDate: item.startDate,
settleAmount: item.totalAmount
});
showSelectSettle.value = false;
};
const settleList = ref<InvoicingSettle[]>([]);
const chooseContract = (res: Contract) => {
form.contractNumber = res.contactNumber;
form.contractId = res.contractId;
form.companyName = res.companyName;
form.customerName = res.customerName;
form.signDate = res.signDate;
form.projectName = res.projectName;
getContractSettleList(res.contractId);
};
const chooseCompany = ({ companyName }: Company) => {
form.invoicingCompany = companyName;
};
const selectSignName = ({ nickname }: User) => {
form.signName = nickname;
};
const fileList = ref<FileItem[]>([]);
interface FileItem {
uid: string;
name?: string;
status?: string;
response?: Response;
thumbUrl?: string;
downloadUrl?: string;
url: string;
}
interface FileInfo {
file: FileItem;
fileList: FileItem[];
}
const onFile = (info: FileInfo) => {
let resFileList = [...info.fileList];
fileList.value = resFileList.map((file) => {
if (file.response) {
file.url = file.response.url;
}
return file;
});
form.fileList = JSON.stringify(fileList.value);
};
const form = reactive<Invoicing>({
invoicingId: "",
contractId: "",
contractNumber: "",
signDate: "",
projectName: "",
customerName: "",
companyName: "",
invoicingDate: "",
invoicingCompany: "",
invoicingAmount: "",
fileList: "[]",
remark: "",
userId: loginUser.value.userId,
totalInvoicingAmount: "",
signName: loginUser.value.username,
requestName: ""
});
/* 更新visible */
const updateVisible = (value: boolean) => {
emit("update:visible", value);
};
// 表单验证规则
const rules = reactive({
contractId: [
{
required: true,
message: "请选择合同",
trigger: "blur"
}
],
invoicingAmount: [
{
required: true,
message: "请输入开票金额",
trigger: "blur"
}
],
invoicingCompany: [
{
required: true,
message: "请选择开票单位",
trigger: "blur"
}
],
invoicingDate: [
{
required: true,
message: "请选择开票日期",
trigger: "blur"
}
],
signName: [
{
required: true,
message: "请选择登记人员",
trigger: "blur"
}
]
});
const { resetFields, validate, validateInfos } = useForm(form, rules);
/* 保存编辑 */
const save = () => {
validate()
.then(async () => {
loading.value = true;
const data = {
...form
};
const saveOrUpdate = isUpdate.value ? updateInvoicing : addInvoicing;
const res = await saveOrUpdate(data).catch((e) => {
loading.value = false;
message.error(e.message);
});
if (settleList.value.length > 0) {
const invoicingId = res?.data;
settleList.value.forEach((item, index) => {
settleList.value[index].invoicingId = invoicingId;
});
await addBatchInvoicingSettle(settleList.value);
}
message.success(res?.message);
updateVisible(false);
emit("done");
})
.catch(() => {
});
};
watch(
() => props.visible,
(visible) => {
if (visible) {
if (props.data) {
loading.value = false;
assignObject(form, props.data);
isUpdate.value = true;
} else {
isUpdate.value = false;
}
} else {
resetFields();
}
}
);
</script>
<style lang="less">
.title {
font-weight: bold;
font-size: 1.1rem;
padding-bottom: 10px;
border-bottom: 1px solid #dcdfe6;
color: #494949;
margin-bottom: 10px;
}
</style>

View File

@@ -0,0 +1,148 @@
<!-- 用户编辑弹窗 -->
<template>
<ele-modal
width="75%"
:visible="visible"
:confirm-loading="loading"
:title="'合同详情'"
:maxable="true"
:body-style="{ paddingBottom: '8px' }"
@update:visible="updateVisible"
:footer="null"
>
<a-form
:label-col="{ md: { span: 4 }, sm: { span: 24 } }"
:wrapper-col="{ md: { span: 19 }, sm: { span: 24 } }"
>
<div class="base-form" style="margin-bottom: 20px">
<a-descriptions bordered>
<a-descriptions-item label="合同名称">
{{ customer.customerName }}
</a-descriptions-item>
<a-descriptions-item label="社会统一信用代码">
{{ customer.customerCode }}
</a-descriptions-item>
<a-descriptions-item label="跟进状态">
<div color="blue" v-for="(d, index) in progress" :key="index">
<span v-if="d.value == customer.progress">{{ d.label }}</span>
</div>
</a-descriptions-item>
<a-descriptions-item label="联系人">
{{ customer.customerContacts }}
</a-descriptions-item>
<a-descriptions-item label="联系电话">
{{ customer.customerMobile }}
</a-descriptions-item>
<a-descriptions-item label="座机电话">
{{ customer.customerPhone }}
</a-descriptions-item>
<a-descriptions-item label="合同类型">
<div color="blue" v-for="(d, index) in customerType" :key="index">
<span v-if="d.value == customer.customerType">{{ d.value }}</span>
</div>
</a-descriptions-item>
<a-descriptions-item label="联系地址">
{{ customer.customerAddress }}
</a-descriptions-item>
<a-descriptions-item label="备注">
{{ customer.comments }}
</a-descriptions-item>
</a-descriptions>
<!-- <a-descriptions-->
<!-- title="其他信息"-->
<!-- :column="1"-->
<!-- bordered-->
<!-- style="margin-top: 30px"-->
<!-- >-->
<!-- <a-descriptions-item label="相关项目">-->
<!-- {{ customer.comments }}-->
<!-- </a-descriptions-item>-->
<!-- </a-descriptions>-->
</div>
</a-form>
</ele-modal>
</template>
<script lang="ts" setup>
import { ref, reactive, watch } from 'vue';
import { Form } from 'ant-design-vue';
import { assignObject } from 'ele-admin-pro';
import type { Customer } from '@/api/oa/customer/model';
import { FILE_SERVER } from '@/config/setting';
import { getDictionaryOptions } from '@/utils/common';
const useForm = Form.useForm;
const props = defineProps<{
// 弹窗是否打开
visible: boolean;
// 修改回显的数据
data?: Customer | null;
}>();
const emit = defineEmits<{
(e: 'done'): void;
(e: 'update:visible', visible: boolean): void;
}>();
// 用户信息
const customer = reactive<Customer>({
customerCode: '',
customerName: '',
customerType: undefined,
customerMobile: '',
customerAvatar: '',
customerPhone: '',
customerContacts: '',
customerAddress: '',
comments: '',
progress: '',
status: '0',
sortNumber: 100,
customerId: 0
});
// 请求状态
const loading = ref(true);
const { resetFields } = useForm(customer);
/* 更新visible */
const updateVisible = (value: boolean) => {
emit('update:visible', value);
};
/* 打开外部链接 */
// const openUrl = (record) => {
// window.open(record.panel);
// };
/* 获取字典数据 */
const customerType = getDictionaryOptions('customerType');
const progress = getDictionaryOptions('customerFollowStatus');
watch(
() => props.visible,
(visible) => {
if (visible) {
if (props.data) {
loading.value = false;
assignObject(customer, props.data);
}
} else {
resetFields();
}
}
);
</script>
<style lang="less">
.tab-pane {
min-height: 100px;
}
.card-head {
display: flex;
height: 40px;
align-items: center;
margin-bottom: 30px;
}
</style>

View File

@@ -0,0 +1,205 @@
<!-- 搜索表单 -->
<template>
<a-space :size="10" style="flex-wrap: wrap">
<a-button type="primary" class="ele-btn-icon" @click="add">
<template #icon>
<PlusOutlined />
</template>
<span>新增</span>
</a-button>
<a-button
danger
type="primary"
class="ele-btn-icon"
v-if="selection.length > 0"
@click="removeBatch"
>
<template #icon>
<DeleteOutlined />
</template>
<span>批量删除</span>
</a-button>
<!-- <a-button @click="batchMove" v-if="selection.length > 0">-->
<!-- <template #icon>-->
<!-- <UserSwitchOutlined />-->
<!-- </template>-->
<!-- 批量转移-->
<!-- </a-button>-->
<a-input-search
allow-clear
placeholder="请输入关键词"
v-model:value="searchText"
@pressEnter="search"
@search="search"
/>
</a-space>
</template>
<script lang="ts" setup>
import {
PlusOutlined,
DeleteOutlined,
UploadOutlined,
DownloadOutlined
} from '@ant-design/icons-vue';
import useSearch from '@/utils/use-search';
import type { CustomerParam } from '@/api/oa/customer/model';
import { ref, watch } from 'vue';
import { utils, read } from 'xlsx';
// import { assignObject } from 'ele-admin-pro';
import { message } from 'ant-design-vue/es';
const props = withDefaults(
defineProps<{
// 选中的角色
selection?: [];
}>(),
{}
);
const emit = defineEmits<{
(e: 'search', where?: CustomerParam): void;
(e: 'add'): void;
(e: 'remove'): void;
(e: 'batchMove'): void;
}>();
// 表单数据
const { where } = useSearch<CustomerParam>({
name: '',
creditCode: '',
keywords: '',
userId: undefined
});
// 下来选项
// 搜索内容
const searchText = ref('');
/* 搜索 */
const search = () => {
where.keywords = searchText.value;
emit('search', where);
};
// 新增
const add = () => {
emit('add');
};
// 导入数据的列
const importTitle = ref<string[]>(['A', 'B', 'C', 'D', 'E', 'F', 'G']);
// 导入的数据
const importData = ref<Record<string, any>[]>([]);
// 导入数据二维数组形式
const importDataAoa = ref<(string | number)[][]>([]);
/* 导入本地 excel 文件 */
const importBatch = (file: File) => {
if (
![
'application/vnd.ms-excel',
'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
].includes(file.type)
) {
message.error('只能选择 excel 文件');
return false;
}
if (file.size / 1024 / 1024 > 20) {
message.error('大小不能超过 20MB');
return false;
}
const reader = new FileReader();
reader.onload = (e) => {
const data = new Uint8Array(e.target?.result as any);
const workbook = read(data, { type: 'array' });
const sheetNames = workbook.SheetNames;
const worksheet = workbook.Sheets[sheetNames[0]];
// 解析成二维数组
const aoa = utils.sheet_to_json<string[]>(worksheet, { header: 1 });
// 生成表格需要的数据
let list: Record<string, any>[] = [];
let maxCols = 0;
let title: string[] = [];
aoa.forEach((d) => {
if (d.length > maxCols) {
maxCols = d.length;
}
const row = {};
for (let i = 0; i < d.length; i++) {
const key = getCharByIndex(i);
row[key] = d[i];
row['__colspan__' + key] = 1;
row['__rowspan__' + key] = 1;
}
list.push(row);
});
for (let i = 0; i < maxCols; i++) {
title.push(getCharByIndex(i));
}
importTitle.value = title;
importData.value = list;
importDataAoa.value = aoa;
};
console.log(importData.value);
console.log(importDataAoa.value);
reader.readAsArrayBuffer(file);
return false;
};
/* 生成Excel列字母序号 */
const getCharByIndex = (index: number) => {
const chars = [
'A',
'B',
'C',
'D',
'E',
'F',
'G',
'H',
'I',
'J',
'K',
'L',
'M',
'N',
'O',
'P',
'Q',
'R',
'S',
'T',
'U',
'V',
'W',
'X',
'Y',
'Z'
];
if (index < chars.length) {
return chars[index];
}
const n = parseInt(String(index / chars.length));
const m = index % chars.length;
return chars[n] + chars[m];
};
// 转移
// const batchMove = () => {
// emit('batchMove');
// };
// 批量删除
const removeBatch = () => {
emit('remove');
};
const onClear = () => {
where.userId = undefined;
search();
};
watch(
() => props.selection,
() => {}
);
</script>

View File

@@ -0,0 +1,85 @@
<template>
<a-table ref="tableRef"
row-key="contractSettleId" :dataSource="dataList" :columns="columns">
<template #bodyCell="{ column, record, index }">
<template v-if="column.key === 'shareAmount'">
<a-input v-model:value="record.shareAmount" type="number">
<template #suffix></template>
</a-input>
</template>
<template v-if="column.key === 'action'">
<div class="flex justify-center items-center">
<close-circle-outlined style="font-size: 1.5rem; color: pink;cursor: pointer"
@click.native="del(index)" />
</div>
</template>
</template>
</a-table>
</template>
<script setup lang="ts">
import { onMounted, ref, watch } from "vue";
import { ColumnItem } from "ele-admin-pro/es/ele-pro-table/types";
import { assignObject, EleProTable } from "ele-admin-pro";
import {
CloseCircleOutlined
} from "@ant-design/icons-vue";
import { InvoicingSettle } from "@/api/tower/invoicingSettle/model";
const props = defineProps<{
dataSource: InvoicingSettle[]
}>();
const tableRef = ref<InstanceType<typeof EleProTable> | null>(null);
const emits = defineEmits(["total"]);
const columns = ref<ColumnItem[]>([
{
title: "序号",
key: "index",
width: 48,
align: "center",
fixed: "left",
hideInSetting: true,
customRender: ({ index }) => index + (tableRef.value?.tableIndex ?? 1)
},
{
title: "结算编号",
dataIndex: "settleNumber"
},
{
title: "结算所属年月",
dataIndex: "startDate"
},
{
title: "结算金额",
dataIndex: "settleAmount"
},
{
title: "分摊开票金额",
dataIndex: "shareAmount",
key: "shareAmount"
},
{
title: "操作",
dataIndex: "action",
key: "action"
}
]);
const dataList = ref<InvoicingSettle[]>([]);
const del = (index: number) => {
dataList.value.splice(index, 1);
};
watch(
() => props.dataSource,
(dataSource) => {
dataList.value = dataSource;
},
{ deep: true }
);
defineExpose({ dataList });
</script>

View File

@@ -0,0 +1,282 @@
<template>
<div class="page">
<div class="ele-body">
<a-card :bordered="false" :body-style="{ padding: '16px' }">
<ele-pro-table
ref="tableRef"
row-key="invoicingId"
:columns="columns"
:datasource="datasource"
v-model:selection="selection"
tool-class="ele-toolbar-form"
:scroll="{ x: 800 }"
class="sys-org-table"
>
<template #toolbar>
<search
@search="reload"
:selection="selection"
@add="openEdit"
@remove="removeBatch"
@batchMove="openMove"
/>
</template>
<template #bodyCell="{ column, record }">
<template v-if="column.key === 'status'">
<span>{{ INVOICING_STATUS_LIST[record.status] }}</span>
</template>
<template v-if="column.key === 'createTime'">
<a-tooltip :title="`${toDateString(record.createTime)}`">
{{ timeAgo(record.createTime) }}
</a-tooltip>
</template>
<template v-if="column.key === 'action'">
<a-space>
<a @click="openEdit(record)">修改</a>
<a-divider type="vertical" />
<a-popconfirm
title="确定要删除此记录吗?"
@confirm="remove(record)"
>
<a class="ele-text-danger">删除</a>
</a-popconfirm>
</a-space>
</template>
</template>
</ele-pro-table>
</a-card>
<!-- 编辑弹窗 -->
<Edit v-model:visible="showEdit" :data="current" @done="reload" />
<!-- 合同详情弹窗 -->
<Info v-model:visible="showInfo" :data="current" @done="reload" />
<!-- 批量转移弹窗 -->
<!-- <CustomerMove v-model:visible="showMove" :data="selection" @done="batchMove" />-->
</div>
</div>
</template>
<script lang="ts" setup>
import { computed, createVNode, ref } from "vue";
import { message, Modal } from "ant-design-vue";
import {
ExclamationCircleOutlined,
UserOutlined
} from "@ant-design/icons-vue";
import type { EleProTable } from "ele-admin-pro";
import type {
DatasourceFunction,
ColumnItem
} from "ele-admin-pro/es/ele-pro-table/types";
import { toDateString } from "ele-admin-pro";
import Search from "./components/search.vue";
import Edit from "./components/edit.vue";
import Info from "./components/info.vue";
import { timeAgo } from "ele-admin-pro";
import { useUserStore } from "@/store/modules/user";
import { Invoicing, INVOICING_STATUS_LIST, InvoicingParam } from "@/api/tower/invoicing/model";
import { pageInvoicing, removeBatchInvoicing, removeInvoicing } from "@/api/tower/invoicing";
const userStore = useUserStore();
// 当前用户信息
const loginUser = computed(() => userStore.info ?? {});
// 表格实例
const tableRef = ref<InstanceType<typeof EleProTable> | null>(null);
// 表格选中数据
const selection = ref<Invoicing[]>([]);
// 当前编辑数据
const current = ref<Invoicing | null>(null);
// 是否显示资产详情
const showInfo = ref(false);
// 是否显示编辑弹窗
const showEdit = ref(false);
// 是否显示批量移动弹窗
const showMove = ref(false);
// 表格数据源
const datasource: DatasourceFunction = ({
page,
limit,
where,
orders,
filters
}) => {
if (filters) {
where.status = filters.status;
}
return pageInvoicing({
...where,
...orders,
page,
limit
});
};
// 表格列配置
const columns = ref<ColumnItem[]>([
{
key: "index",
width: 48,
align: "center",
fixed: "left",
hideInSetting: true,
customRender: ({ index }) => index + (tableRef.value?.tableIndex ?? 0)
},
{
title: "开票状态",
dataIndex: "status",
key: "status",
},
{
title: "开票日期",
dataIndex: "invoicingDate"
},
{
title: "合同编号",
dataIndex: "contactNumber"
},
{
title: "项目名称",
dataIndex: "projectName"
},
{
title: "承租单位",
dataIndex: "customerName"
},
{
title: "申请人",
dataIndex: "requestName"
},
{
title: "开票单位",
dataIndex: "invoicingCompany"
},
{
title: "开票金额",
dataIndex: "invoicingAmount"
},
{
title: "发票号",
dataIndex: "invoicingNo"
},
{
title: "申请人",
dataIndex: "requestName"
},
{
title: "备注",
dataIndex: "remark"
},
{
title: "操作",
key: "action",
width: 200,
align: "center",
hideInSetting: true
}
]);
/* 搜索 */
const reload = (where?: InvoicingParam) => {
selection.value = [];
tableRef?.value?.reload({ where: where });
};
/* 打开编辑弹窗 */
const openEdit = (row?: Invoicing) => {
current.value = row ?? null;
showEdit.value = true;
};
const showSettle = ref<Boolean>(false);
const openSettle = (row?: Invoicing) => {
current.value = row ?? null;
showSettle.value = true;
};
/* 打开批量移动弹窗 */
const openMove = () => {
showMove.value = true;
};
/* 打开用户详情弹窗 */
const openInfo = (row?: Invoicing) => {
current.value = row ?? null;
showInfo.value = true;
};
/* 删除单个 */
const remove = (row: Invoicing) => {
const hide = message.loading("请求中..", 0);
removeInvoicing(row.invoicingId)
.then((msg) => {
hide();
message.success(msg);
reload();
})
.catch((e) => {
hide();
message.error(e.message);
});
};
/* 批量转移 */
const batchMove = (userId) => {
console.log(userId, "批量转移0000");
console.log(selection.value);
};
/* 批量删除 */
const removeBatch = () => {
if (!selection.value.length) {
message.error("请至少选择一条数据");
return;
}
Modal.confirm({
title: "提示",
content: "确定要删除选中的记录吗?",
icon: createVNode(ExclamationCircleOutlined),
maskClosable: true,
onOk: () => {
const hide = message.loading("请求中..", 0);
removeBatchInvoicing(
selection.value.map((d) => {
if (loginUser.value.userId === d.userId) {
return d.invoicingId;
}
})
)
.then((msg) => {
hide();
message.success(msg);
reload();
})
.catch((e) => {
hide();
message.error(e.message);
});
}
});
};
</script>
<script lang="ts">
export default {
name: "Accessory"
};
</script>
<style lang="less" scoped>
.sys-org-table :deep(.ant-table-body) {
overflow: auto !important;
overflow: overlay !important;
}
.sys-org-table :deep(.ant-table-pagination.ant-pagination) {
padding: 0 4px;
margin-bottom: 0;
}
</style>

View File

@@ -0,0 +1,337 @@
<!-- 用户编辑弹窗 -->
<template>
<ele-modal
:width="'90%'"
:visible="visible"
:confirm-loading="loading"
:maskClosable="false"
:maxable="maxable"
:title="isUpdate ? '编辑转租结算' : '添加转租结算'"
:body-style="{ paddingBottom: '8px' }"
@update:visible="updateVisible"
@ok="save"
>
<a-form
:label-col="{ md: { span: 6 }, sm: { span: 20 }, xs: { span: 24 } }"
:wrapper-col="{ md: { span: 24 }, sm: { span: 20 }, xs: { span: 24 } }"
>
<a-card title="填报人信息" :bordered="false">
<a-row :gutter="16">
<a-col :md="12" :sm="24" :xs="24">
<a-form-item label="填报人">
<a-input disabled v-model:value="loginUser.username" />
</a-form-item>
</a-col>
<a-col :md="12" :sm="24" :xs="24">
<a-form-item label="填报时间">
<a-input disabled v-model:value="now" />
</a-form-item>
</a-col>
</a-row>
</a-card>
<a-card title="合同信息" :bordered="false">
<a-row :gutter="16">
<a-col :md="8" :sm="24" :xs="24">
<a-form-item label="合同编号" v-bind="validateInfos.contractId">
<TowerContractSelectModel
:placeholder="`请选择合同`"
v-model:value="form.contactNumber"
@done="chooseContract"
/>
</a-form-item>
<a-form-item label="承租单位">
<p style="margin: 0">{{ form.customerName }}</p>
</a-form-item>
</a-col>
<a-col :md="8" :sm="24" :xs="24">
<a-form-item label="签订日期">
<p style="margin: 0">{{ form.signDate }}</p>
</a-form-item>
<a-form-item label="租赁单位">
<p style="margin: 0">{{ form.companyName }}</p>
</a-form-item>
</a-col>
<a-col :md="8" :sm="24" :xs="24">
<a-form-item label="项目名称">
<p style="margin: 0">{{ form.projectName }}</p>
</a-form-item>
</a-col>
</a-row>
</a-card>
<a-card title="结算信息" :bordered="false">
<a-row :gutter="16">
<a-col :md="8" :sm="24" :xs="24">
<a-form-item label="产权单位" v-bind="validateInfos.amountWithTax">
<DictSelect
dict-code="PropertyCompany"
placeholder="请选择产权单位"
v-model:value="form.propertyCompany"
/>
</a-form-item>
</a-col>
<a-col :md="8" :sm="24" :xs="24">
<a-form-item label="结算日期">
<a-date-picker
class="ele-fluid"
placeholder="请选择结束日期"
v-model:value="form.settleDate"
valueFormat="YYYY-MM-DD"
/>
</a-form-item>
</a-col>
<a-col :md="8" :sm="24" :xs="24">
<a-form-item label="本期结算金额">
<a-input v-model:value="form.settleAmount" disabled placeholder="自动计算">
<template #suffix></template>
</a-input>
</a-form-item>
</a-col>
</a-row>
<a-form-item label="备注">
<a-input v-model:value="form.remark" placeholder="请输入备注说明" />
</a-form-item>
</a-card>
<a-card title="结算清单">
<a-button @click.native="showSelectEquipment = true" type="primary"
:disabled="!form.contractId || settleList.length === contractEquipmentList.length">新增
</a-button>
<Table :data-source="settleList" @total="setTotal" />
</a-card>
</a-form>
</ele-modal>
<ele-modal
:width="'80%'"
:visible="showSelectEquipment"
:maskClosable="false"
title="选择设备"
:body-style="{ paddingBottom: '8px' }"
@update:visible="showSelectEquipment"
@cancel="showSelectEquipment = false"
@ok="showSelectEquipment = false"
>
<a-row :gutter="16">
<a-col :span="8">设备名称</a-col>
<a-col :span="8">设备型号</a-col>
<a-col :span="8">操作</a-col>
</a-row>
<a-row :gutter="16" class="my-05" v-for="(item, index) in contractEquipmentList" :key="index">
<a-col :span="8">{{ item.equipmentName }}</a-col>
<a-col :span="8">{{ item.equipmentModel }}</a-col>
<a-col :span="8">
<a-button type="link" @click.native="selectEquipment(item)">选择</a-button>
</a-col>
</a-row>
</ele-modal>
</template>
<script lang="ts" setup>
import { ref, reactive, watch, computed } from "vue";
import { Form, message } from "ant-design-vue";
import { assignObject, EleProTable } from "ele-admin-pro";
import { useUserStore } from "@/store/modules/user";
import dayjs from "dayjs";
import { addLending, updateLending } from "@/api/tower/lending";
import { Lending } from "@/api/tower/lending/model";
import { Contract } from "@/api/tower/contract/model";
import { ContractSettleEquipment } from "@/api/tower/contractSettle/equipment/model";
import { listContractSettleEquipment } from "@/api/tower/contractSettle/equipment";
import Table from "@/views/tower/lending/components/table.vue";
import { LendingSettle } from "@/api/tower/lendingSettle/model";
import { addBatchLendingSettle, listLendingSettle } from "@/api/tower/lendingSettle";
const userStore = useUserStore();
// 当前用户信息
const loginUser = computed(() => userStore.info ?? {});
const now = dayjs().format("YYYY-MM-DD HH:mm:ss");
const showSelectEquipment = ref(false);
const contractEquipmentList = ref<ContractSettleEquipment[]>([]);
const settleList = ref<LendingSettle[]>([]);
const getSettleList = async () => {
settleList.value = await listLendingSettle({lendingId: form.lendingId})
}
const getContractEquipmentList = async () => {
const contractEquipmentParam = <ContractSettleEquipment>{
contractId: form.contractId
};
contractEquipmentList.value = await listContractSettleEquipment(contractEquipmentParam);
settleList.value = [];
contractEquipmentList.value.forEach(item => {
addSettleList(item);
});
};
const selectEquipment = item => {
addSettleList(item);
showSelectEquipment.value = false;
};
const addSettleList = item => {
settleList.value.push({
equipmentId: item.equipmentId,
lendingId: form.lendingId,
equipmentName: item.equipmentName,
equipmentModel: item.equipmentModel,
equipmentNo: item.equipmentNo,
lendingPath: null,
coopWay: null,
startDate: null,
stopDate: null,
calDay: null,
daysInMonth: null,
monthRentAmount: null,
shouldPayRentAmount: null,
dailyRentAmount: null,
shouldSupplementAmount: null,
shouldDeductionAmount: null,
paidAmount: null,
taxRate: null,
taxAmount: null,
totalAmountWithTax: null,
remark: "",
userId: loginUser.value.userId
});
};
// 是否是修改
const isUpdate = ref(false);
const useForm = Form.useForm;
const props = defineProps<{
// 弹窗是否打开
visible: boolean;
// 修改回显的数据
data?: Lending | null;
}>();
const emit = defineEmits<{
(e: "done"): void;
(e: "update:visible", visible: boolean): void;
}>();
// 提交状态
const loading = ref(false);
// 是否显示最大化切换按钮
const maxable = ref(true);
const activeKey = ref(0);
const chooseContract = (res: Contract) => {
form.contactNumber = res.contactNumber;
form.contractId = res.contractId;
form.companyName = res.companyName;
form.customerName = res.customerName;
form.signDate = res.signDate;
form.projectName = res.projectName;
getContractEquipmentList();
};
const form = reactive<Lending>({
lendingId: "",
contractId: "",
contactNumber: "",
signDate: "",
projectName: "",
customerName: "",
companyName: "",
propertyCompany: "",
settleDate: "",
settleAmount: "",
fileList: "",
remark: "",
userId: loginUser.value.userId
});
/* 更新visible */
const updateVisible = (value: boolean) => {
emit("update:visible", value);
};
// 表单验证规则
const rules = reactive({
contractId: [
{
required: true,
message: "请选择合同",
trigger: "blur"
}
],
propertyCompany: [
{
required: true,
message: "请选择产权单位",
trigger: "blur"
}
],
settleDate: [
{
required: true,
message: "请选择结算日期",
trigger: "blur"
}
]
});
const { resetFields, validate, validateInfos } = useForm(form, rules);
const setTotal = total => {
form.settleAmount = total;
};
/* 保存编辑 */
const save = () => {
validate()
.then(async () => {
loading.value = true;
const data = {
...form
};
if (settleList.value.length === 0) {
message.error("请选择结算设备");
return;
}
const saveOrUpdate = isUpdate.value ? updateLending : addLending;
const res = await saveOrUpdate(data).catch((e) => {
loading.value = false;
message.error(e.message);
});
const lendingId = res?.data;
settleList.value.forEach((item, index) => {
settleList.value[index].lendingId = lendingId;
});
await addBatchLendingSettle(settleList.value);
message.success(res?.message);
updateVisible(false);
emit("done");
})
.catch(() => {
});
};
watch(
() => props.visible,
(visible) => {
if (visible) {
if (props.data) {
loading.value = false;
assignObject(form, props.data);
isUpdate.value = true;
getSettleList()
} else {
isUpdate.value = false;
}
} else {
resetFields();
}
}
);
</script>
<style lang="less">
.title {
font-weight: bold;
font-size: 1.1rem;
padding-bottom: 10px;
border-bottom: 1px solid #dcdfe6;
color: #494949;
margin-bottom: 10px;
}
</style>

View File

@@ -0,0 +1,148 @@
<!-- 用户编辑弹窗 -->
<template>
<ele-modal
width="75%"
:visible="visible"
:confirm-loading="loading"
:title="'合同详情'"
:maxable="true"
:body-style="{ paddingBottom: '8px' }"
@update:visible="updateVisible"
:footer="null"
>
<a-form
:label-col="{ md: { span: 4 }, sm: { span: 24 } }"
:wrapper-col="{ md: { span: 19 }, sm: { span: 24 } }"
>
<div class="base-form" style="margin-bottom: 20px">
<a-descriptions bordered>
<a-descriptions-item label="合同名称">
{{ customer.customerName }}
</a-descriptions-item>
<a-descriptions-item label="社会统一信用代码">
{{ customer.customerCode }}
</a-descriptions-item>
<a-descriptions-item label="跟进状态">
<div color="blue" v-for="(d, index) in progress" :key="index">
<span v-if="d.value == customer.progress">{{ d.label }}</span>
</div>
</a-descriptions-item>
<a-descriptions-item label="联系人">
{{ customer.customerContacts }}
</a-descriptions-item>
<a-descriptions-item label="联系电话">
{{ customer.customerMobile }}
</a-descriptions-item>
<a-descriptions-item label="座机电话">
{{ customer.customerPhone }}
</a-descriptions-item>
<a-descriptions-item label="合同类型">
<div color="blue" v-for="(d, index) in customerType" :key="index">
<span v-if="d.value == customer.customerType">{{ d.value }}</span>
</div>
</a-descriptions-item>
<a-descriptions-item label="联系地址">
{{ customer.customerAddress }}
</a-descriptions-item>
<a-descriptions-item label="备注">
{{ customer.comments }}
</a-descriptions-item>
</a-descriptions>
<!-- <a-descriptions-->
<!-- title="其他信息"-->
<!-- :column="1"-->
<!-- bordered-->
<!-- style="margin-top: 30px"-->
<!-- >-->
<!-- <a-descriptions-item label="相关项目">-->
<!-- {{ customer.comments }}-->
<!-- </a-descriptions-item>-->
<!-- </a-descriptions>-->
</div>
</a-form>
</ele-modal>
</template>
<script lang="ts" setup>
import { ref, reactive, watch } from 'vue';
import { Form } from 'ant-design-vue';
import { assignObject } from 'ele-admin-pro';
import type { Customer } from '@/api/oa/customer/model';
import { FILE_SERVER } from '@/config/setting';
import { getDictionaryOptions } from '@/utils/common';
const useForm = Form.useForm;
const props = defineProps<{
// 弹窗是否打开
visible: boolean;
// 修改回显的数据
data?: Customer | null;
}>();
const emit = defineEmits<{
(e: 'done'): void;
(e: 'update:visible', visible: boolean): void;
}>();
// 用户信息
const customer = reactive<Customer>({
customerCode: '',
customerName: '',
customerType: undefined,
customerMobile: '',
customerAvatar: '',
customerPhone: '',
customerContacts: '',
customerAddress: '',
comments: '',
progress: '',
status: '0',
sortNumber: 100,
customerId: 0
});
// 请求状态
const loading = ref(true);
const { resetFields } = useForm(customer);
/* 更新visible */
const updateVisible = (value: boolean) => {
emit('update:visible', value);
};
/* 打开外部链接 */
// const openUrl = (record) => {
// window.open(record.panel);
// };
/* 获取字典数据 */
const customerType = getDictionaryOptions('customerType');
const progress = getDictionaryOptions('customerFollowStatus');
watch(
() => props.visible,
(visible) => {
if (visible) {
if (props.data) {
loading.value = false;
assignObject(customer, props.data);
}
} else {
resetFields();
}
}
);
</script>
<style lang="less">
.tab-pane {
min-height: 100px;
}
.card-head {
display: flex;
height: 40px;
align-items: center;
margin-bottom: 30px;
}
</style>

View File

@@ -0,0 +1,205 @@
<!-- 搜索表单 -->
<template>
<a-space :size="10" style="flex-wrap: wrap">
<a-button type="primary" class="ele-btn-icon" @click="add">
<template #icon>
<PlusOutlined />
</template>
<span>新增</span>
</a-button>
<a-button
danger
type="primary"
class="ele-btn-icon"
v-if="selection.length > 0"
@click="removeBatch"
>
<template #icon>
<DeleteOutlined />
</template>
<span>批量删除</span>
</a-button>
<!-- <a-button @click="batchMove" v-if="selection.length > 0">-->
<!-- <template #icon>-->
<!-- <UserSwitchOutlined />-->
<!-- </template>-->
<!-- 批量转移-->
<!-- </a-button>-->
<a-input-search
allow-clear
placeholder="请输入关键词"
v-model:value="searchText"
@pressEnter="search"
@search="search"
/>
</a-space>
</template>
<script lang="ts" setup>
import {
PlusOutlined,
DeleteOutlined,
UploadOutlined,
DownloadOutlined
} from '@ant-design/icons-vue';
import useSearch from '@/utils/use-search';
import type { CustomerParam } from '@/api/oa/customer/model';
import { ref, watch } from 'vue';
import { utils, read } from 'xlsx';
// import { assignObject } from 'ele-admin-pro';
import { message } from 'ant-design-vue/es';
const props = withDefaults(
defineProps<{
// 选中的角色
selection?: [];
}>(),
{}
);
const emit = defineEmits<{
(e: 'search', where?: CustomerParam): void;
(e: 'add'): void;
(e: 'remove'): void;
(e: 'batchMove'): void;
}>();
// 表单数据
const { where } = useSearch<CustomerParam>({
name: '',
creditCode: '',
keywords: '',
userId: undefined
});
// 下来选项
// 搜索内容
const searchText = ref('');
/* 搜索 */
const search = () => {
where.keywords = searchText.value;
emit('search', where);
};
// 新增
const add = () => {
emit('add');
};
// 导入数据的列
const importTitle = ref<string[]>(['A', 'B', 'C', 'D', 'E', 'F', 'G']);
// 导入的数据
const importData = ref<Record<string, any>[]>([]);
// 导入数据二维数组形式
const importDataAoa = ref<(string | number)[][]>([]);
/* 导入本地 excel 文件 */
const importBatch = (file: File) => {
if (
![
'application/vnd.ms-excel',
'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
].includes(file.type)
) {
message.error('只能选择 excel 文件');
return false;
}
if (file.size / 1024 / 1024 > 20) {
message.error('大小不能超过 20MB');
return false;
}
const reader = new FileReader();
reader.onload = (e) => {
const data = new Uint8Array(e.target?.result as any);
const workbook = read(data, { type: 'array' });
const sheetNames = workbook.SheetNames;
const worksheet = workbook.Sheets[sheetNames[0]];
// 解析成二维数组
const aoa = utils.sheet_to_json<string[]>(worksheet, { header: 1 });
// 生成表格需要的数据
let list: Record<string, any>[] = [];
let maxCols = 0;
let title: string[] = [];
aoa.forEach((d) => {
if (d.length > maxCols) {
maxCols = d.length;
}
const row = {};
for (let i = 0; i < d.length; i++) {
const key = getCharByIndex(i);
row[key] = d[i];
row['__colspan__' + key] = 1;
row['__rowspan__' + key] = 1;
}
list.push(row);
});
for (let i = 0; i < maxCols; i++) {
title.push(getCharByIndex(i));
}
importTitle.value = title;
importData.value = list;
importDataAoa.value = aoa;
};
console.log(importData.value);
console.log(importDataAoa.value);
reader.readAsArrayBuffer(file);
return false;
};
/* 生成Excel列字母序号 */
const getCharByIndex = (index: number) => {
const chars = [
'A',
'B',
'C',
'D',
'E',
'F',
'G',
'H',
'I',
'J',
'K',
'L',
'M',
'N',
'O',
'P',
'Q',
'R',
'S',
'T',
'U',
'V',
'W',
'X',
'Y',
'Z'
];
if (index < chars.length) {
return chars[index];
}
const n = parseInt(String(index / chars.length));
const m = index % chars.length;
return chars[n] + chars[m];
};
// 转移
// const batchMove = () => {
// emit('batchMove');
// };
// 批量删除
const removeBatch = () => {
emit('remove');
};
const onClear = () => {
where.userId = undefined;
search();
};
watch(
() => props.selection,
() => {}
);
</script>

View File

@@ -0,0 +1,258 @@
<template>
<a-table ref="tableRef"
row-key="contractSettleId" :dataSource="dataList" :columns="columns" :scroll="{ x: 4000, y: 300 }">
<template #bodyCell="{ column, record, index }">
<template v-if="column.key === 'startDate'">
<a-date-picker
class="ele-fluid"
placeholder="请选择开始日期"
v-model:value="record.startDate"
valueFormat="YYYY-MM-DD"
@change="changeDate($event, index)"
@ok="changeDate($event, index)"
/>
</template>
<template v-if="column.key === 'endDate'">
<a-date-picker
class="ele-fluid"
placeholder="请选择结束日期"
v-model:value="record.stopDate"
valueFormat="YYYY-MM-DD"
@change="changeDate($event, index)"
@ok="changeDate($event, index)"
/>
</template>
<template v-if="column.key === 'daysInMonth'">
<a-input v-model:value="record.daysInMonth" type="number" @change="changeDate($event, index)">
<template #suffix></template>
</a-input>
</template>
<template v-if="column.key === 'monthRentAmount'">
<a-input v-model:value="record.monthRentAmount" type="number" @change="changeDate($event, index)">
<template #suffix></template>
</a-input>
</template>
<template v-if="column.key === 'dailyRentAmount'">
<a-input v-model:value="record.dailyRentAmount" type="number" @change="changeDate($event, index)">
<template #suffix></template>
</a-input>
</template>
<template v-if="column.key === 'shouldPayRentAmount'">
<a-input v-model:value="record.shouldPayRentAmount" type="number">
<template #suffix></template>
</a-input>
</template>
<template v-if="column.key === 'shouldSupplementAmount'">
<a-input v-model:value="record.shouldSupplementAmount" type="number">
<template #suffix></template>
</a-input>
</template>
<template v-if="column.key === 'shouldDeductionAmount'">
<a-input v-model:value="record.shouldDeductionAmount" type="number">
<template #suffix></template>
</a-input>
</template>
<template v-if="column.key === 'paidAmount'">
<a-input v-model:value="record.paidAmount" type="number">
<template #suffix></template>
</a-input>
</template>
<template v-if="column.key === 'taxRate'">
<a-input v-model:value="record.taxRate" type="number">
<template #suffix></template>
</a-input>
</template>
<template v-if="column.key === 'taxAmount'">
<a-input v-model:value="record.taxAmount" type="number">
<template #suffix></template>
</a-input>
</template>
<template v-if="column.key === 'totalAmountWithTax'">
<a-input v-model:value="record.totalAmountWithTax" type="number" @change="changeTotalAmount">
<template #suffix></template>
</a-input>
</template>
<template v-if="column.key === 'remark'">
<a-input v-model:value="record.remark" />
</template>
<template v-if="column.key === 'action'">
<div class="flex justify-center items-center">
<close-circle-outlined style="font-size: 1.5rem; color: pink;cursor: pointer"
@click.native="del(index)" />
</div>
</template>
</template>
</a-table>
</template>
<script setup lang="ts">
import { onMounted, ref, watch } from "vue";
import { ColumnItem } from "ele-admin-pro/es/ele-pro-table/types";
import { assignObject, EleProTable } from "ele-admin-pro";
import {
CloseCircleOutlined
} from "@ant-design/icons-vue";
import dayjs from "dayjs";
import { LendingSettle } from "@/api/tower/lendingSettle/model";
const props = defineProps<{
dataSource: LendingSettle[]
}>();
const tableRef = ref<InstanceType<typeof EleProTable> | null>(null);
const emits = defineEmits(["total"]);
const columns = ref<ColumnItem[]>([
{
title: "序号",
key: "index",
width: 48,
align: "center",
fixed: "left",
hideInSetting: true,
customRender: ({ index }) => index + (tableRef.value?.tableIndex ?? 1)
},
{
title: "设备名",
dataIndex: "equipmentName",
width: 150
},
{
title: "出厂编号",
dataIndex: "factoryNo",
width: 150
},
{
title: "备案编号",
dataIndex: "filingNo",
width: 150
},
{
title: "设备自编号",
dataIndex: "equipmentNo",
width: 150
},
{
title: "结算开始日期",
dataIndex: "startDate",
key: "startDate",
width: 200
},
{
title: "结算结束日期",
dataIndex: "endDate",
key: "endDate",
width: 200
},
{
title: "计费天数",
dataIndex: "calDay",
key: "calDay",
width: 250
},
{
title: "月计费天数",
dataIndex: "daysInMonth",
key: "daysInMonth",
width: 150
},
{
title: "月租金(元)",
dataIndex: "monthRentAmount",
key: "monthRentAmount",
width: 250
},
{
title: "日租金(元)",
dataIndex: "dailyRentAmount",
key: "dailyRentAmount",
width: 250
},
{
title: "应付租金(元)",
dataIndex: "shouldPayRentAmount",
key: "shouldPayRentAmount",
width: 250
},
{
title: "应补租金(元)",
dataIndex: "shouldSupplementAmount",
key: "shouldSupplementAmount",
width: 250
},
{
title: "应扣租金(元)",
dataIndex: "shouldDeductionAmount",
key: "shouldDeductionAmount",
width: 250
},
{
title: "实付租金(元)",
dataIndex: "paidAmount",
key: "paidAmount",
width: 250
},
{
title: "税率(%)",
dataIndex: "taxRate",
key: "taxRate",
width: 250
},
{
title: "税金(元)",
dataIndex: "taxAmount",
key: "taxAmount",
width: 250
},
{
title: "税价合计(元)",
dataIndex: "totalAmountWithTax",
key: "totalAmountWithTax",
width: 250
},
{
title: "备注",
dataIndex: "remark"
},
{
title: "操作",
dataIndex: "action",
key: "action",
fixed: "right"
}
]);
const dataList = ref<LendingSettle[]>([]);
const changeDate = (data, index) => {
if (dataList.value[index].startDate && dataList.value[index].stopDate) {
dataList.value[index].calDay = dayjs(dataList.value[index].stopDate).diff(dayjs(dataList.value[index].startDate), "day");
if (dataList.value[index].daysInMonth && dataList.value[index].monthRentAmount) {
dataList.value[index].dailyRentAmount = (dataList.value[index].monthRentAmount / dataList.value[index].daysInMonth).toFixed(8);
dataList.value[index].shouldPayRentAmount = dataList.value[index].dailyRentAmount * dataList.value[index].calDay;
}
}
};
const changeTotalAmount = () => {
let total = 0;
dataList.value.forEach(item => {
total += parseFloat(item.totalAmountWithTax);
});
emits("total", total);
};
const del = (index: number) => {
dataList.value.splice(index, 1);
};
watch(
() => props.dataSource,
(dataSource) => {
dataList.value = dataSource;
},
{ deep: true }
);
defineExpose({ dataList });
</script>

View File

@@ -0,0 +1,258 @@
<template>
<div class="page">
<div class="ele-body">
<a-card :bordered="false" :body-style="{ padding: '16px' }">
<ele-pro-table
ref="tableRef"
row-key="invoicingId"
:columns="columns"
:datasource="datasource"
v-model:selection="selection"
tool-class="ele-toolbar-form"
:scroll="{ x: 800 }"
class="sys-org-table"
>
<template #toolbar>
<search
@search="reload"
:selection="selection"
@add="openEdit"
@remove="removeBatch"
@batchMove="openMove"
/>
</template>
<template #bodyCell="{ column, record }">
<template v-if="column.key === 'createTime'">
<a-tooltip :title="`${toDateString(record.createTime)}`">
{{ timeAgo(record.createTime) }}
</a-tooltip>
</template>
<template v-if="column.key === 'action'">
<a-space>
<a @click="openEdit(record)">修改</a>
<a-divider type="vertical" />
<a-popconfirm
title="确定要删除此记录吗?"
@confirm="remove(record)"
>
<a class="ele-text-danger">删除</a>
</a-popconfirm>
</a-space>
</template>
</template>
</ele-pro-table>
</a-card>
<!-- 编辑弹窗 -->
<Edit v-model:visible="showEdit" :data="current" @done="reload" />
<!-- 合同详情弹窗 -->
<Info v-model:visible="showInfo" :data="current" @done="reload" />
<!-- 批量转移弹窗 -->
<!-- <CustomerMove v-model:visible="showMove" :data="selection" @done="batchMove" />-->
</div>
</div>
</template>
<script lang="ts" setup>
import { computed, createVNode, ref } from 'vue';
import { message, Modal } from 'ant-design-vue';
import {
ExclamationCircleOutlined,
UserOutlined
} from '@ant-design/icons-vue';
import type { EleProTable } from 'ele-admin-pro';
import type {
DatasourceFunction,
ColumnItem
} from 'ele-admin-pro/es/ele-pro-table/types';
import { toDateString } from 'ele-admin-pro';
import Search from './components/search.vue';
import Edit from './components/edit.vue';
import Info from './components/info.vue';
import { timeAgo } from 'ele-admin-pro';
import { useUserStore } from '@/store/modules/user';
import { Lending, LendingParam } from "@/api/tower/lending/model";
import { pageLending, removeBatchLending, removeLending } from "@/api/tower/lending";
const userStore = useUserStore();
// 当前用户信息
const loginUser = computed(() => userStore.info ?? {});
// 表格实例
const tableRef = ref<InstanceType<typeof EleProTable> | null>(null);
// 表格选中数据
const selection = ref<Lending[]>([]);
// 当前编辑数据
const current = ref<Lending | null>(null);
// 是否显示资产详情
const showInfo = ref(false);
// 是否显示编辑弹窗
const showEdit = ref(false);
// 是否显示批量移动弹窗
const showMove = ref(false);
// 表格数据源
const datasource: DatasourceFunction = ({
page,
limit,
where,
orders,
filters
}) => {
if (filters) {
where.status = filters.status;
}
return pageLending({
...where,
...orders,
page,
limit
});
};
// 表格列配置
const columns = ref<ColumnItem[]>([
{
key: 'index',
width: 48,
align: 'center',
fixed: 'left',
hideInSetting: true,
customRender: ({ index }) => index + (tableRef.value?.tableIndex ?? 0)
},
{
title: '项目名称',
dataIndex: 'projectName',
},
{
title: '合同编号',
dataIndex: 'contactNumber'
},
{
title: '结算日期',
dataIndex: 'settleDate',
},
{
title: '产权单位',
dataIndex: 'propertyCompany'
},
{
title: '本期结算金额',
dataIndex: 'settleAmount'
},
{
title: '税金',
dataIndex: 'taxAmount'
},
{
title: '操作',
key: 'action',
width: 200,
align: 'center',
hideInSetting: true
}
]);
/* 搜索 */
const reload = (where?: LendingParam) => {
selection.value = [];
tableRef?.value?.reload({ where: where });
};
/* 打开编辑弹窗 */
const openEdit = (row?: Lending) => {
current.value = row ?? null;
showEdit.value = true;
};
const showSettle = ref<Boolean>(false)
const openSettle = (row?: Lending) => {
current.value = row ?? null;
showSettle.value = true;
};
/* 打开批量移动弹窗 */
const openMove = () => {
showMove.value = true;
};
/* 打开用户详情弹窗 */
const openInfo = (row?: Lending) => {
current.value = row ?? null;
showInfo.value = true;
};
/* 删除单个 */
const remove = (row: Lending) => {
const hide = message.loading('请求中..', 0);
removeLending(row.lendingId)
.then((msg) => {
hide();
message.success(msg);
reload();
})
.catch((e) => {
hide();
message.error(e.message);
});
};
/* 批量转移 */
const batchMove = (userId) => {
console.log(userId, '批量转移0000');
console.log(selection.value);
};
/* 批量删除 */
const removeBatch = () => {
if (!selection.value.length) {
message.error('请至少选择一条数据');
return;
}
Modal.confirm({
title: '提示',
content: '确定要删除选中的记录吗?',
icon: createVNode(ExclamationCircleOutlined),
maskClosable: true,
onOk: () => {
const hide = message.loading('请求中..', 0);
removeBatchLending(
selection.value.map((d) => {
if (loginUser.value.userId === d.userId) {
return d.lendingId;
}
})
)
.then((msg) => {
hide();
message.success(msg);
reload();
})
.catch((e) => {
hide();
message.error(e.message);
});
}
});
};
</script>
<script lang="ts">
export default {
name: 'Accessory'
};
</script>
<style lang="less" scoped>
.sys-org-table :deep(.ant-table-body) {
overflow: auto !important;
overflow: overlay !important;
}
.sys-org-table :deep(.ant-table-pagination.ant-pagination) {
padding: 0 4px;
margin-bottom: 0;
}
</style>

View File

@@ -96,7 +96,7 @@
title: '设备状态',
dataIndex: 'status',
key: 'status',
customRender: ({ text }) => ['闲置', '报废', '注销', '转卖'][text]
customRender: ({ text }) => ['闲置', '报废', '注销', '转卖', '在用', '场地'][text]
},
{
title: '设备名称',

View File

@@ -1,268 +1,302 @@
<template>
<a-spin :spinning="loading">
<a-button type="primary" style="margin-bottom: 10px" @click="add">
<span>添加</span>
</a-button>
<a-table
size="middle"
row-key="projectOrderId"
:pagination="false"
:data-source="list"
:columns="columns"
>
<template #bodyCell="{ column, record, index }">
<template v-if="column.key === 'equipmentName'">
<TowerSelectModel
v-if="record.isEdit"
:placeholder="`请选择设备名称`"
v-model:value="record.equipmentName"
:index="index"
@done="chooseEquipmentName"
/>
<div v-else>{{ record.equipmentName }}</div>
</template>
<template v-else-if="column.key === 'equipmentModel'">
<TowerSelectModel
v-if="record.isEdit"
:placeholder="`请选择设备型号`"
v-model:value="record.equipmentModel"
@done="chooseEquipmentModel"
/>
<div v-else>{{ record.equipmentModel }}</div>
</template>
<template v-else-if="column.key === 'equipmentNum'">
<a-input
v-if="record.isEdit"
v-model:value="record.equipmentNum"
placeholder="请输入预定数量"
/>
<div v-else>{{ record.equipmentNum }}</div>
</template>
<template v-else-if="column.key === 'unit'">
<a-input
v-if="record.isEdit"
v-model:value="record.unit"
placeholder="请输入单位"
/>
<div v-else>{{ record.unit }}</div>
</template>
<template v-else-if="column.key === 'startTime'">
<a-date-picker
v-if="record.isEdit"
placeholder="预计进场时间"
value-format="YYYY-MM-DD"
v-model:value="record.startTime"
/>
<div v-else>{{ record.startTime }}</div>
</template>
<template v-else-if="column.key === 'endTime'">
<a-date-picker
v-if="record.isEdit"
placeholder="预计退场时间"
value-format="YYYY-MM-DD"
v-model:value="record.endTime"
/>
<div v-else>{{ record.endTime }}</div>
</template>
<template v-else-if="column.key === 'year'">
<a-input-number
v-if="record.isEdit"
v-model:value="record.year"
placeholder="出厂年限"
/>
<div v-else>{{ record.year }}</div>
</template>
<template v-else-if="column.key === 'documenter'">
<SelectStaff
v-if="record.isEdit"
:placeholder="`对应资料员`"
:index="index"
v-model:value="record.documenter"
@done="chooseDocumenter"
/>
<div v-else>{{ record.documenter }}</div>
</template>
<template v-else-if="column.key === 'comments'">
<a-input
v-if="record.isEdit"
v-model:value="record.comments"
placeholder="备注"
/>
<div v-else>{{ record.comments }}</div>
</template>
<template v-else-if="column.key === 'action'">
<a-space>
<a v-if="record.isEdit" @click="done(record, index)">完成</a>
<a v-else @click="edit(record, index)">修改</a>
<a-divider type="vertical" />
<a-popconfirm
title="确定要删除此记录吗?"
@confirm="remove(record, index)"
>
<a class="ele-text-danger">删除</a>
</a-popconfirm>
</a-space>
</template>
</template>
</a-table>
</a-spin>
<a-spin :spinning="loading">
<a-button type="primary" style="margin-bottom: 10px" @click="add" :disabled="placeList?.length === 0">
<span>添加</span>
</a-button>
<p style="color: red" v-if="placeList?.length === 0">请先添加标地</p>
<a-table
size="middle"
row-key="projectOrderId"
:pagination="false"
:data-source="list"
:columns="columns"
>
<template #bodyCell="{ column, record, index }">
<template v-if="column.key === 'equipmentName'">
<TowerEquipmentModel
v-if="record.isEdit"
:placeholder="`请选择设备`"
v-model:value="record.equipmentName"
:index="index"
idle-only
@done="chooseEquipmentName($event, index)"
/>
<div v-else>{{ record.equipmentName }}</div>
</template>
<template v-else-if="column.key === 'equipmentModel'">
<a-input
v-if="record.isEdit"
v-model:value="record.equipmentModel"
placeholder="设备型号"
readonly
/>
<div v-else>{{ record.equipmentModel }}</div>
</template>
<template v-else-if="column.key === 'factoryNo'">
<a-input
v-if="record.isEdit"
v-model:value="record.factoryNo"
placeholder="出厂编号"
readonly
/>
<div v-else>{{ record.factoryNo }}</div>
</template>
<template v-else-if="column.key === 'filingNo'">
<a-input
v-if="record.isEdit"
v-model:value="record.filingNo"
placeholder="备案编号"
readonly
/>
<div v-else>{{ record.filingNo }}</div>
</template>
<template v-else-if="column.key === 'equipmentNum'">
<a-input
v-if="record.isEdit"
v-model:value="record.equipmentNum"
placeholder="请输入预定数量"
/>
<div v-else>{{ record.equipmentNum }}</div>
</template>
<template v-else-if="column.key === 'unit'">
<a-input
v-if="record.isEdit"
v-model:value="record.unit"
placeholder="请输入单位"
/>
<div v-else>{{ record.unit }}</div>
</template>
<template v-else-if="column.key === 'startTime'">
<a-date-picker
v-if="record.isEdit"
placeholder="开工时间"
value-format="YYYY-MM-DD"
v-model:value="record.startTime"
/>
<div v-else>{{ record.startTime }}</div>
</template>
<template v-else-if="column.key === 'endTime'">
<a-date-picker
v-if="record.isEdit"
placeholder="停工时间"
value-format="YYYY-MM-DD"
v-model:value="record.endTime"
/>
<div v-else>{{ record.endTime }}</div>
</template>
<template v-else-if="column.key === 'year'">
<a-input-number
v-if="record.isEdit"
v-model:value="record.year"
placeholder="出厂年限"
/>
<div v-else>{{ record.year }}</div>
</template>
<template v-else-if="column.key === 'documenter'">
<SelectStaff
v-if="record.isEdit"
:placeholder="`对应资料员`"
:index="index"
v-model:value="record.documenter"
@done="chooseDocumenter"
/>
<div v-else>{{ record.documenter }}</div>
</template>
<template v-else-if="column.key === 'comments'">
<a-select v-if="record.isEdit" v-model:value="record.comments" placeholder="请选择标地">
<a-select-option :value="item" v-for="(item, index) in placeList" :key="index">{{ item }}</a-select-option>
</a-select>
<div v-else>{{ record.comments }}</div>
</template>
<template v-else-if="column.key === 'action'">
<a-space>
<a v-if="record.isEdit" @click="done(record, index)">完成</a>
<a v-else @click="edit(record, index)">修改</a>
<a-divider type="vertical" />
<a-popconfirm
title="确定要删除此记录吗?"
@confirm="remove(record, index)"
>
<a class="ele-text-danger">删除</a>
</a-popconfirm>
</a-space>
</template>
</template>
</a-table>
</a-spin>
</template>
<script lang="ts" setup>
import { ref, reactive, watch } from 'vue';
import { uuid } from 'ele-admin-pro/es';
import type { ColumnsType } from 'ant-design-vue/es/table';
import { ProjectOrder } from '@/api/tower/project/order/model';
import { removeProjectOrder } from '@/api/tower/project/order';
import { message } from 'ant-design-vue';
import { ref, reactive, watch } from "vue";
import { uuid } from "ele-admin-pro/es";
import type { ColumnsType } from "ant-design-vue/es/table";
import { ProjectOrder } from "@/api/tower/project/order/model";
import { removeProjectOrder } from "@/api/tower/project/order";
import { message } from "ant-design-vue";
import { TowerEquipment } from "@/api/tower/equipment/model";
const props = withDefaults(
const props = withDefaults(
defineProps<{
value?: ProjectOrder[];
projectId?: number;
placeholder?: string;
value?: ProjectOrder[];
projectId?: number;
placeholder?: string;
placeList?: string[];
}>(),
{
placeholder: '请选择数据'
placeholder: "请选择数据"
}
);
);
// 已添加成员
const list = ref<ProjectOrder[]>([]);
// 请求状态
const loading = ref(false);
// 已添加成员
const list = ref<ProjectOrder[]>([]);
// 请求状态
const loading = ref(false);
// 列
const columns = reactive<ColumnsType>([
// 列
const columns = reactive<ColumnsType>([
{
key: 'index',
align: 'center',
width: 30,
customRender: ({ index }) => index + 1,
fixed: 'left'
key: "index",
align: "center",
width: 30,
customRender: ({ index }) => index + 1,
fixed: "left"
},
{
title: '设备名称',
align: 'center',
dataIndex: 'equipmentName',
key: 'equipmentName'
title: "具体标地",
align: "center",
dataIndex: "comments",
key: "comments"
},
{
title: '规格型号',
align: 'center',
dataIndex: 'equipmentModel',
key: 'equipmentModel'
title: "设备名称",
align: "center",
dataIndex: "equipmentName",
key: "equipmentName"
},
{
title: '签订数量',
align: 'center',
dataIndex: 'equipmentNum',
key: 'equipmentNum',
width: 80
title: "出厂编号",
align: "center",
dataIndex: "factoryNo",
key: "factoryNo"
},
{
title: '单位',
align: 'center',
dataIndex: 'unit',
key: 'unit',
width: 60
title: "规格型号",
align: "center",
dataIndex: "equipmentModel",
key: "equipmentModel",
width: 200
},
{
title: '预计进场时间',
align: 'center',
dataIndex: 'startTime',
key: 'startTime'
title: "备案编号",
align: "center",
dataIndex: "filingNo",
key: "filingNo",
width: 200
},
// {
// title: '签订数量',
// align: 'center',
// dataIndex: 'equipmentNum',
// key: 'equipmentNum',
// width: 80
// },
// {
// title: '单位',
// align: 'center',
// dataIndex: 'unit',
// key: 'unit',
// width: 100
// },
{
title: "开工时间",
align: "center",
dataIndex: "startTime",
key: "startTime"
},
{
title: '预计退场时间',
align: 'center',
dataIndex: 'endTime',
key: 'endTime'
title: "停工时间",
align: "center",
dataIndex: "endTime",
key: "endTime"
},
{
title: '出厂年限',
align: 'center',
dataIndex: 'year',
key: 'year',
width: 80
title: "出厂年限",
align: "center",
dataIndex: "year",
key: "year",
width: 80
},
// {
// title: '对应资料员',
// align: 'center',
// dataIndex: 'documenter',
// key: 'documenter'
// },
{
title: '对应资料员',
align: 'center',
dataIndex: 'documenter',
key: 'documenter'
},
{
title: '备注',
align: 'center',
dataIndex: 'comments',
key: 'comments'
},
{
title: '操作',
key: 'action',
align: 'center',
width: 100
title: "操作",
key: "action",
align: "center",
width: 100
}
]);
]);
/* 添加 */
const add = () => {
/* 添加 */
const add = () => {
list.value.push({
projectId: props.projectId,
key: uuid(8),
isEdit: true,
equipmentNum: 1,
unit: '台',
startTime: undefined,
endTime: undefined,
year: undefined,
documenter: undefined,
comments: undefined
projectId: props.projectId,
key: uuid(8),
isEdit: true,
equipmentNum: 1,
filingNo: undefined,
unit: "台",
startTime: undefined,
endTime: undefined,
year: undefined,
documenter: undefined,
comments: undefined
});
};
};
const chooseEquipmentName = (data) => {
list.value[data.index].equipmentName = data.name;
list.value[data.index].equipmentModel = data.model;
list.value[data.index].year = data.yearLife;
};
const chooseEquipmentName = (data: TowerEquipment, index: number) => {
if (list.value.find((row) => row.equipmentId === data.equipmentId && !row.endTime)) return message.error('该设备已存在')
list.value[index].equipmentId = data.equipmentId;
list.value[index].equipmentName = data.name;
list.value[index].equipmentModel = data.model;
list.value[index].year = data.lifeYear;
list.value[index].filingNo = data.filingNo;
list.value[index].factoryNo = data.factoryNo;
};
const chooseEquipmentModel = (data) => {
list.value[data.index].equipmentName = data.name;
list.value[data.index].equipmentModel = data.model;
list.value[data.index].year = data.yearLife;
};
const chooseDocumenter = (data) => {
const chooseDocumenter = (data) => {
list.value[data.index].documenter = data.nickname;
};
};
/* 编辑 */
const edit = (_row: any, index: number) => {
/* 编辑 */
const edit = (_row: any, index: number) => {
list.value[index].isEdit = true;
};
};
/* 完成编辑 */
const done = (_row: any, index: number) => {
/* 完成编辑 */
const done = (_row: any, index: number) => {
list.value[index].isEdit = false;
};
};
/* 删除 */
const remove = (_row: any, index: number) => {
/* 删除 */
const remove = (_row: any, index: number) => {
removeProjectOrder(_row.projectOrderId).then((msg) => {
message.success(msg);
message.success(msg);
});
list.value.splice(index, 1);
};
};
watch(
watch(
() => props.value,
(value) => {
if (value) {
list.value = value;
}
if (value) {
list.value = value;
}
},
{ immediate: true }
);
);
</script>

View File

@@ -0,0 +1,102 @@
<!-- 用户编辑弹窗 -->
<template>
<ele-modal
:width="600"
:visible="visible"
:maskClosable="false"
:title="`导入项目`"
:body-style="{ paddingBottom: '28px' }"
@update:visible="updateVisible"
:footer="null"
>
<a-upload-dragger
name="file"
:show-upload-list="false"
accept=".xls,.xlsx"
:before-upload="handleImport"
>
<p class="ant-upload-drag-icon">
<InboxOutlined />
</p>
<p class="ant-upload-text">单击或拖动文件到此区域进行上传</p>
<p class="ant-upload-hint" style="max-width: 550px">
提示附件上传中请不要做任何操作 支持的文件类型为*.xls, *.xlsx!
</p>
</a-upload-dragger>
<div style="margin: 20px auto; display: flex; justify-content: center">
<a
href="http://1.14.159.185:10042/template/project_template_0.xlsx"
target="_blank"
>下载项目导入模板</a>
</div>
</ele-modal>
</template>
<script lang="ts" setup>
import { InboxOutlined } from "@ant-design/icons-vue";
import { message } from "ant-design-vue";
import { addBatchTowerEquipment } from "@/api/tower/equipment";
import { TowerEquipment } from "@/api/tower/equipment/model";
import { read, utils } from "xlsx";
import { ref } from "vue";
import { Project } from "@/api/tower/project/model";
import { addBatchProject } from "@/api/tower/project";
const emit = defineEmits<{
(e: "done"): void;
(e: "update:visible", visible: boolean): void;
}>();
/* 更新visible */
const updateVisible = (value: boolean) => {
emit("update:visible", value);
};
// 导入的数据
const importData = ref<Project[]>([]);
const handleImport = (file: File) => {
if (
![
"application/vnd.ms-excel",
"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
].includes(file.type)
) {
message.error("只能选择 excel 文件");
return false;
}
if (file.size / 1024 / 1024 > 20) {
message.error("大小不能超过 20MB");
return false;
}
const reader = new FileReader();
importData.value = [];
reader.onload = (e) => {
const data = new Uint8Array(e.target?.result as any);
const workbook = read(data, { type: "array" });
const sheetNames = workbook.SheetNames;
const worksheet = workbook.Sheets[sheetNames[0]];
// 解析成二维数组
const aoa = utils.sheet_to_json<string[]>(worksheet, { header: 1 });
aoa.slice(1).map((d) => {
if (d[0]) {
importData.value.push({
projectName: d[0],
securityStatus: d[1],
projectCity: d[2],
competentDepartment: d[3],
companyName: d[4],
customerName: d[5],
projectStatus: "未开工"
});
}
});
addBatchProject(importData.value).then(() => {
message.success("导入成功");
updateVisible(false);
emit("done");
});
};
reader.readAsArrayBuffer(file);
return false;
};
</script>

File diff suppressed because it is too large Load Diff

View File

@@ -16,7 +16,7 @@
</template>
<span>批量删除</span>
</a-button>
<a-button class="ele-btn-icon">
<a-button class="ele-btn-icon" @click.native="openImport">
<span>导入项目</span>
</a-button>
<a-button class="ele-btn-icon">
@@ -36,6 +36,7 @@
@search="search"
/>
</a-space>
<Import v-model:visible="showImport" @done="search" />
</template>
<script lang="ts" setup>
@@ -43,6 +44,7 @@
import useSearch from '@/utils/use-search';
import { ref, watch } from 'vue';
import { OrderParam } from '@/api/order/model';
import Import from "@/views/tower/project/components/import.vue";
const props = withDefaults(
defineProps<{
@@ -97,6 +99,11 @@
emit('remove');
};
const showImport = ref<Boolean>(false)
const openImport = () => {
showImport.value = true;
};
watch(
() => props.selection,
() => {}

View File

@@ -15,9 +15,8 @@
:columns="columns"
>
<template #bodyCell="{ column, record, index }">
<template v-if="column.key === 'role'">
<a-tag color="green" v-if="record.role === 10">可见成员</a-tag>
<a-tag color="orange" v-if="record.role === 20">项目联系人</a-tag>
<template v-if="column.key === 'level'">
<a-tag color="orange" v-if="record.user && record.user.userLevel">{{ USER_LEVEL_LIST[record.user.userLevel] }}</a-tag>
</template>
<template v-if="column.key === 'action'">
<a-space>
@@ -34,7 +33,7 @@
import type { ColumnsType } from 'ant-design-vue/es/table';
import { ProjectUser } from '@/api/tower/project/user/model';
import { removeProjectUser } from '@/api/tower/project/user';
import { User } from '@/api/system/user/model';
import { User, USER_LEVEL_LIST } from "@/api/system/user/model";
import { message } from 'ant-design-vue';
const props = withDefaults(
@@ -65,8 +64,7 @@
{
title: '类型',
align: 'center',
dataIndex: 'role',
key: 'role'
key: 'level'
},
{
title: '所在部门',

View File

@@ -1,288 +1,328 @@
<template>
<div class="page">
<div class="ele-body">
<a-card :bordered="false">
<!-- 表格 -->
<ele-pro-table
ref="tableRef"
row-key="projectId"
:columns="columns"
:datasource="datasource"
v-model:selection="selection"
:customRow="customRow"
:height="tableHeight"
:full-height="fixedHeight ? 'calc(100vh - 100px)' : void 0"
tool-class="ele-toolbar-form"
:scroll="{ x: 1200 }"
class="sys-org-table"
:striped="true"
>
<template #toolbar>
<search
@search="reload"
:selection="selection"
@add="openEdit"
@remove="removeBatch"
/>
</template>
<template #bodyCell="{ column, record }">
<template v-if="column.key === 'nickname'">
{{ record.nickname }}
</template>
<template v-if="column.key === 'createTime'">
{{ record.createTime }}
</template>
<template v-if="column.key === 'action'">
<a-space>
<a @click="openEdit(record)">修改</a>
<a-divider type="vertical" />
<a @click="openEdit(record)">库存查看</a>
</a-space>
</template>
</template>
</ele-pro-table>
</a-card>
<div>
<a-card title="项目数据">
<a-row :gutter="10">
<a-col :span="4">
<span>项目总数:{{ projectData.totalNum }}</span>
</a-col>
<a-col :span="4">
<span>已开工总数:{{ projectData.startedNum }}</span>
</a-col>
<a-col :span="4">
<span>未开工:{{ projectData.notStartNum }}</span>
</a-col>
</a-row>
</a-card>
<div class="page">
<div class="ele-body">
<a-card :bordered="false">
<!-- 表格 -->
<ele-pro-table
ref="tableRef"
row-key="projectId"
:columns="columns"
:datasource="datasource"
v-model:selection="selection"
:customRow="customRow"
:height="tableHeight"
:full-height="fixedHeight ? 'calc(100vh - 100px)' : void 0"
tool-class="ele-toolbar-form"
:scroll="{ x: 1200 }"
class="sys-org-table"
:striped="true"
>
<template #toolbar>
<search
@search="reload"
:selection="selection"
@add="openEdit"
@remove="removeBatch"
/>
</template>
<template #bodyCell="{ column, record }">
<template v-if="column.key === 'nickname'">
{{ record.nickname }}
</template>
<template v-if="column.key === 'orders'">
{{ record.orders.length > 0 ? record.orders[0].comments : "" }}
</template>
<template v-if="column.key === 'createTime'">
{{ record.createTime }}
</template>
<template v-if="column.key === 'action'">
<a-space>
<a @click="openEdit(record)">修改</a>
<a-divider type="vertical" />
<a @click="openEdit(record)">库存查看</a>
</a-space>
</template>
</template>
</ele-pro-table>
</a-card>
</div>
<!-- 编辑弹窗 -->
<ProjectEdit v-model:visible="showEdit" :data="current" @done="reload" />
<!-- 订单详情 -->
<order-info v-model:visible="showInfo" :data="current" @done="reload" />
</div>
</div>
<!-- 编辑弹窗 -->
<ProjectEdit v-model:visible="showEdit" :data="current" @done="reload" />
<!-- 订单详情 -->
<order-info v-model:visible="showInfo" :data="current" @done="reload" />
</div>
</template>
<script lang="ts" setup>
import { createVNode, computed, ref } from 'vue';
import { message, Modal } from 'ant-design-vue';
import { ExclamationCircleOutlined } from '@ant-design/icons-vue';
import type { EleProTable } from 'ele-admin-pro';
import type {
import { createVNode, computed, ref, reactive } from "vue";
import { message, Modal } from "ant-design-vue";
import { ExclamationCircleOutlined } from "@ant-design/icons-vue";
import type { EleProTable } from "ele-admin-pro";
import type {
DatasourceFunction,
ColumnItem
} from 'ele-admin-pro/es/ele-pro-table/types';
import Search from './components/search.vue';
import ProjectEdit from './components/project-edit.vue';
import OrderInfo from './components/order-info.vue';
import {
} from "ele-admin-pro/es/ele-pro-table/types";
import Search from "./components/search.vue";
import ProjectEdit from "./components/project-edit.vue";
import OrderInfo from "./components/order-info.vue";
import {
pageProject,
removeBatchProject,
removeProject
} from '@/api/tower/project';
import { Project, ProjectParam } from '@/api/tower/project/model';
removeProject, towerProjectData
} from "@/api/tower/project";
import { Project, ProjectParam } from "@/api/tower/project/model";
import { towerEquipmentData } from "@/api/tower/equipment";
defineProps<{
defineProps<{
activeKey?: boolean;
data?: any;
}>();
}>();
// 表格实例
const tableRef = ref<InstanceType<typeof EleProTable> | null>(null);
// 表格实例
const tableRef = ref<InstanceType<typeof EleProTable> | null>(null);
// 表格列配置
const columns = ref<ColumnItem[]>([
// 表格列配置
const columns = ref<ColumnItem[]>([
{
key: 'index',
width: 48,
align: 'center',
fixed: 'left',
hideInSetting: true,
customRender: ({ index }) => index + (tableRef.value?.tableIndex ?? 0)
key: "index",
width: 48,
align: "center",
fixed: "left",
hideInSetting: true,
customRender: ({ index }) => index + (tableRef.value?.tableIndex ?? 0)
},
{
title: '项目状态',
dataIndex: 'projectStatus',
key: 'projectStatus'
title: "项目状态",
dataIndex: "projectStatus",
key: "projectStatus"
},
{
title: '项目名称',
dataIndex: 'projectName',
key: 'projectName'
title: "项目名称",
dataIndex: "projectName",
key: "projectName"
},
// {
// title: '具体标地',
// // dataIndex: 'projectCity',
// key: 'orders'
// },
{
title: "承租单位",
dataIndex: "customerName",
key: "customerName"
},
{
title: '项目地址',
dataIndex: 'projectAddress',
key: 'projectAddress'
title: "项目所属主管部门",
dataIndex: "competentDepartment"
},
{
title: '承租单位',
dataIndex: 'customerName',
key: 'customerName'
title: "关联设备数",
dataIndex: "equipmentNum"
},
{
title: '项目负责人',
dataIndex: 'director',
key: 'director'
title: "项目管理员",
dataIndex: "director"
},
// {
// title: '检查次数',
// dataIndex: 'companyId',
// key: 'companyId'
// },
// {
// title: '保养次数',
// dataIndex: 'companyId',
// key: 'companyId'
// },
{
title: "创建时间",
dataIndex: "createTime"
},
{
title: '是否关联',
dataIndex: 'companyId',
key: 'companyId'
},
{
title: '检查频率',
dataIndex: 'companyId',
key: 'companyId'
},
{
title: '保养频率',
dataIndex: 'companyId',
key: 'companyId'
},
{
title: '操作',
key: 'action',
width: 150,
align: 'center',
hideInSetting: true
title: "操作",
key: "action",
width: 150,
align: "center",
hideInSetting: true
}
]);
]);
// 表格选中数据
const selection = ref<Project[]>([]);
// 当前编辑数据
const current = ref<Project | null>(null);
// 是否显示资产详情
const showInfo = ref(false);
// 是否显示编辑弹窗
const showEdit = ref(false);
// 表格固定高度
const fixedHeight = ref(true);
// 表格高度
const tableHeight = computed(() => {
return fixedHeight.value ? 'calc(100vh - 308px)' : void 0;
});
// 表格选中数据
const selection = ref<Project[]>([]);
// 当前编辑数据
const current = ref<Project | null>(null);
// 是否显示资产详情
const showInfo = ref(false);
// 是否显示编辑弹窗
const showEdit = ref(false);
// 表格固定高度
const fixedHeight = ref(true);
// 表格高度
const tableHeight = computed(() => {
return fixedHeight.value ? "calc(100vh - 308px)" : void 0;
});
// 表格数据源
const datasource: DatasourceFunction = ({
page,
limit,
where,
orders,
filters
}) => {
// 表格数据源
const datasource: DatasourceFunction = ({
page,
limit,
where,
orders,
filters
}) => {
// 搜索条件
if (filters.payMethod) {
where.payMethod = filters.payMethod;
where.payMethod = filters.payMethod;
}
if (filters.deliveryType) {
where.deliveryType = filters.deliveryType;
where.deliveryType = filters.deliveryType;
}
if (filters.payStatus) {
where.payStatus = filters.payStatus;
where.payStatus = filters.payStatus;
}
if (filters.orderSource) {
where.orderSource = filters.orderSource;
where.orderSource = filters.orderSource;
}
where.tenantId = localStorage.getItem('tenantId');
where.tenantId = localStorage.getItem("tenantId");
where.payStatus = 20;
return pageProject({
...where,
...orders,
page,
limit
...where,
...orders,
page,
limit
});
};
};
/* 搜索 */
const reload = (where?: ProjectParam) => {
/* 搜索 */
const reload = (where?: ProjectParam) => {
selection.value = [];
tableRef?.value?.reload({ where: where });
};
getData();
};
/* 打开编辑弹窗 */
const openEdit = (row?: Project) => {
/* 打开编辑弹窗 */
const openEdit = (row?: Project) => {
current.value = row ?? null;
showEdit.value = true;
};
};
/* 打开用户详情弹窗 */
const openInfo = (row?: Project) => {
/* 打开用户详情弹窗 */
const openInfo = (row?: Project) => {
current.value = row ?? null;
showInfo.value = true;
};
};
/* 删除单个 */
const remove = (row: Project) => {
const hide = message.loading('请求中..', 0);
let projectData = reactive({
totalNum: 0,
startedNum: 0,
notStartNum: 0
});
const getData = async () => {
const res = await towerProjectData();
for (let key in projectData) projectData[key] = res[key];
};
/* 删除单个 */
const remove = (row: Project) => {
const hide = message.loading("请求中..", 0);
removeProject(row.projectId)
.then((msg) => {
hide();
message.success(msg);
reload();
})
.catch((e) => {
hide();
message.error(e.message);
});
};
/* 批量删除 */
const removeBatch = () => {
console.log(selection.value);
if (!selection.value.length) {
message.error('请至少选择一条数据');
return;
}
Modal.confirm({
title: '提示',
content: '确定要删除选中的记录吗?',
icon: createVNode(ExclamationCircleOutlined),
maskClosable: true,
onOk: () => {
const hide = message.loading('请求中..', 0);
removeBatchProject(selection.value.map((d) => d.projectId))
.then((msg) => {
.then((msg) => {
hide();
message.success(msg);
reload();
})
.catch((e) => {
})
.catch((e) => {
hide();
message.error(e.message);
});
}
});
};
/* 批量删除 */
const removeBatch = () => {
console.log(selection.value);
if (!selection.value.length) {
message.error("请至少选择一条数据");
return;
}
Modal.confirm({
title: "提示",
content: "确定要删除选中的记录吗?",
icon: createVNode(ExclamationCircleOutlined),
maskClosable: true,
onOk: () => {
const hide = message.loading("请求中..", 0);
removeBatchProject(selection.value.map((d) => d.projectId))
.then((msg) => {
hide();
message.success(msg);
reload();
})
.catch((e) => {
hide();
message.error(e.message);
});
}
});
};
};
/* 自定义行属性 */
const customRow = (record: Project) => {
/* 自定义行属性 */
const customRow = (record: Project) => {
return {
// 行点击事件
onClick: () => {
// console.log(record);
},
// 行双击事件
onDblclick: () => {
openEdit(record);
}
// 行点击事件
onClick: () => {
// console.log(record);
},
// 行双击事件
onDblclick: () => {
openEdit(record);
}
};
};
};
reload();
reload();
</script>
<script lang="ts">
export default {
name: 'ProjectIndex'
};
export default {
name: "ProjectIndex"
};
</script>
<style lang="less" scoped>
p {
p {
line-height: 0.8;
}
.sys-org-table :deep(.ant-table-body) {
}
.sys-org-table :deep(.ant-table-body) {
overflow: auto !important;
overflow: overlay !important;
}
}
.sys-org-table :deep(.ant-table-pagination.ant-pagination) {
.sys-org-table :deep(.ant-table-pagination.ant-pagination) {
padding: 0 4px;
margin-bottom: 0;
}
.price-edit {
}
.price-edit {
padding-right: 5px;
}
.comments {
}
.comments {
max-width: 200px;
}
}
</style>

View File

@@ -22,27 +22,60 @@
@ok="changeDate($event, index)"
/>
</template>
<template v-if="column.key === 'inDate'">
<a-date-picker
class="ele-fluid"
placeholder="请选择实际进场日期"
v-model:value="record.inDate"
valueFormat="YYYY-MM-DD"
/>
</template>
<template v-if="column.key === 'outDate'">
<a-date-picker
class="ele-fluid"
placeholder="请选择实际出场日期"
v-model:value="record.outDate"
valueFormat="YYYY-MM-DD"
/>
</template>
<template v-if="column.key === 'settleCycle'">
<span v-if="record.startDate && record.endDate">
{{ Math.floor(record.days / 30) }}
{{ record.days - (Math.floor(record.days / 30) * 30) }}
</span>
<a-row :gutter="16">
<a-col :span="12">
<a-input v-model:value="record.month" type="number">
<template #addonAfter></template>
</a-input>
</a-col>
<a-col :span="12">
<a-input v-model:value="record.day" type="number">
<template #addonAfter></template>
</a-input>
</a-col>
</a-row>
</template>
<template v-if="column.key === 'monthAmount'">
<a-input v-model:value="record.monthAmount" type="number" @change="changeDate($event, index)" />
</template>
<template v-if="column.key === 'dailyAmount'">
<span v-if="record.monthAmount">{{ record.dailyAmount }}</span>
<a-input v-model:value="record.dailyAmount" type="number" />
</template>
<template v-if="column.key === 'payRate'">
<a-input v-model:value="record.payRate" type="number">
<template #addonAfter>%</template>
</a-input>
</template>
<template v-if="column.key === 'amountWithTax'">
<span v-if="record.monthAmount">{{ (record.dailyAmount * record.days).toFixed(2) }}</span>
<span
v-if="record.monthAmount">{{ ((record.dailyAmount * record.day + record.monthAmount * record.month) * record.payRate / 100).toFixed(2)
}}</span>
</template>
<template v-if="column.key === 'tax'">
<span v-if="record.monthAmount">{{ (record.dailyAmount * record.days * (record.taxRate / 100)).toFixed(2) }}</span>
<span
v-if="record.monthAmount">{{ (((record.dailyAmount * record.day + record.monthAmount * record.month) * record.payRate / 100) * (record.taxRate / 100)).toFixed(2)
}}</span>
</template>
<template v-if="column.key === 'amountWithoutTax'">
<span
v-if="record.monthAmount">{{ ((record.dailyAmount * record.days) - (record.dailyAmount * record.days * (record.taxRate / 100))).toFixed(2)
v-if="record.monthAmount">{{ ((1 - (record.taxRate / 100)) * ((record.dailyAmount * record.day + record.monthAmount * record.month) * record.payRate / 100)).toFixed(2)
}}</span>
</template>
<template v-if="column.key === 'remark'">
@@ -55,11 +88,38 @@
</div>
</template>
</template>
<template #summary>
<a-table-summary-row>
<a-table-summary-cell>合计</a-table-summary-cell>
<a-table-summary-cell />
<a-table-summary-cell />
<a-table-summary-cell />
<a-table-summary-cell />
<a-table-summary-cell />
<a-table-summary-cell />
<a-table-summary-cell />
<a-table-summary-cell />
<a-table-summary-cell />
<a-table-summary-cell />
<a-table-summary-cell />
<a-table-summary-cell>
{{ totals.amountWithTax }}
</a-table-summary-cell>
<a-table-summary-cell>
{{ totals.tax }}
</a-table-summary-cell>
<a-table-summary-cell>
{{ totals.amountWithoutTax }}
</a-table-summary-cell>
<a-table-summary-cell />
<a-table-summary-cell />
</a-table-summary-row>
</template>
</a-table>
</template>
<script setup lang="ts">
import { onMounted, ref, watch } from "vue";
import { computed, onMounted, ref, watch } from "vue";
import { SettleDetail } from "@/api/tower/settleDetail/model";
import { ColumnItem } from "ele-admin-pro/es/ele-pro-table/types";
import { assignObject, EleProTable } from "ele-admin-pro";
@@ -108,6 +168,16 @@ const columns = ref<ColumnItem[]>([
dataIndex: "endDate",
key: "endDate"
},
// {
// title: "实际进场日期",
// dataIndex: "inDate",
// key: "inDate"
// },
// {
// title: "实际出场日期",
// dataIndex: "outDate",
// key: "outDate"
// },
{
title: "实际结算周期",
dataIndex: "settleCycle",
@@ -124,7 +194,12 @@ const columns = ref<ColumnItem[]>([
key: "dailyAmount"
},
{
title: "本期租金含税金额(元)",
title: "支付比例",
dataIndex: "payRate",
key: "payRate"
},
{
title: "含税应付(元)",
dataIndex: "amountWithTax",
key: "amountWithTax"
},
@@ -154,8 +229,12 @@ const dataList = ref<SettleDetail[]>([]);
const changeDate = (data, index) => {
if (dataList.value[index].startDate && dataList.value[index].endDate) {
dataList.value[index].days = dayjs(dataList.value[index].endDate).diff(dayjs(dataList.value[index].startDate), "day");
if (dataList.value[index].monthAmount) dataList.value[index].dailyAmount = (dataList.value[index].monthAmount / 30).toFixed(8);
dataList.value[index].days = dayjs(dataList.value[index].endDate).diff(dayjs(dataList.value[index].startDate), "day") + 1;
dataList.value[index].month = Math.floor(dataList.value[index].days / 30);
dataList.value[index].day = dataList.value[index].days - (Math.floor(dataList.value[index].days / 30) * 30);
if (dataList.value[index].monthAmount) {
dataList.value[index].dailyAmount = (dataList.value[index].monthAmount / 30).toFixed(8);
}
}
};
@@ -163,13 +242,38 @@ const del = (index: number) => {
dataList.value.splice(index, 1);
};
onMounted(() => {
dataList.value = props.dataSource;
calTotals();
});
watch(
() => props.dataSource,
(dataSource) => {
dataList.value = dataSource;
calTotals();
},
{ deep: true }
);
defineExpose({ dataList })
const totals = ref({ amountWithTax: 0, tax: 0, amountWithoutTax: 0 });
const calTotals = () => {
let amountWithTax: number = 0;
let tax = 0;
let amountWithoutTax = 0;
if (dataList.value && dataList.value.length > 0 && (dataList.value[0].taxRate !== undefined)) {
const taxRate = dataList.value[0].taxRate;
dataList.value.forEach(({ month, monthAmount, day, dailyAmount, payRate }) => {
amountWithTax += (month * monthAmount + day * dailyAmount) * payRate / 100;
});
amountWithTax = Number(amountWithTax.toFixed(2));
tax = amountWithTax * (taxRate / 100);
tax = Number(tax.toFixed(2));
amountWithoutTax = amountWithTax - tax;
amountWithoutTax = Number(amountWithoutTax.toFixed(2));
}
totals.value = { amountWithTax, tax, amountWithoutTax };
};
defineExpose({ dataList });
</script>

View File

@@ -5,24 +5,43 @@
<template v-if="column.key === 'singleAmount'">
<a-input v-model:value="record.singleAmount" type="number" />
</template>
<template v-if="column.key === 'inDate'">
<a-date-picker
class="ele-fluid"
placeholder="请选择实际进场日期"
v-model:value="record.inDate"
valueFormat="YYYY-MM-DD"
/>
</template>
<template v-if="column.key === 'outDate'">
<a-date-picker
class="ele-fluid"
placeholder="请选择实际出场日期"
v-model:value="record.outDate"
valueFormat="YYYY-MM-DD"
/>
</template>
<template v-if="column.key === 'num'">
<a-input v-model:value="record.num" type="number" />
</template>
<template v-if="column.key === 'sumAmount'">
<span v-if="record.singleAmount && record.num">
{{ (record.singleAmount * record.num).toFixed(2) }}
</span>
<template v-if="column.key === 'payRate'">
<a-input v-model:value="record.payRate" type="number">
<template #addonAfter>%</template>
</a-input>
</template>
<template v-if="column.key === 'amountWithTax'">
<span v-if="record.singleAmount && record.num">{{ (record.singleAmount * record.num).toFixed(2) }}</span>
<span
v-if="record.singleAmount && record.num">{{ ((record.singleAmount * record.num) * record.payRate / 100).toFixed(2)
}}</span>
</template>
<template v-if="column.key === 'tax'">
<span v-if="record.singleAmount && record.num">{{ (record.singleAmount * record.num * (record.taxRate / 100)).toFixed(2)
<span
v-if="record.singleAmount && record.num">{{ (((record.singleAmount * record.num) * record.payRate / 100) * (record.taxRate / 100)).toFixed(2)
}}</span>
</template>
<template v-if="column.key === 'amountWithoutTax'">
<span
v-if="record.singleAmount && record.num">{{ ((record.singleAmount * record.num) - (record.singleAmount * record.num * (record.taxRate / 100))).toFixed(2)
v-if="record.singleAmount && record.num">{{ (((record.singleAmount * record.num) * record.payRate / 100) - (record.singleAmount * record.num * (record.taxRate / 100))).toFixed(2)
}}</span>
</template>
<template v-if="column.key === 'remark'">
@@ -35,6 +54,30 @@
</div>
</template>
</template>
<template #summary>
<a-table-summary-row>
<a-table-summary-cell>合计</a-table-summary-cell>
<a-table-summary-cell />
<a-table-summary-cell />
<a-table-summary-cell />
<a-table-summary-cell />
<a-table-summary-cell />
<a-table-summary-cell />
<a-table-summary-cell />
<a-table-summary-cell />
<a-table-summary-cell>
{{ totals.amountWithTax }}
</a-table-summary-cell>
<a-table-summary-cell>
{{ totals.tax }}
</a-table-summary-cell>
<a-table-summary-cell>
{{ totals.amountWithoutTax }}
</a-table-summary-cell>
<a-table-summary-cell />
<a-table-summary-cell />
</a-table-summary-row>
</template>
</a-table>
</template>
@@ -78,6 +121,16 @@ const columns = ref<ColumnItem[]>([
dataIndex: "factoryNo",
key: "factoryNo"
},
{
title: "实际进场日期",
dataIndex: "inDate",
key: "inDate"
},
{
title: "实际出场日期",
dataIndex: "outDate",
key: "outDate"
},
{
title: "费用类型",
dataIndex: "settleCostType",
@@ -94,9 +147,9 @@ const columns = ref<ColumnItem[]>([
key: "num"
},
{
title: "进退场小计(元)",
dataIndex: "sumAmount",
key: "sumAmount"
title: "支付比例",
dataIndex: "payRate",
key: "payRate"
},
{
title: "含税金额(元)",
@@ -129,17 +182,42 @@ const dataList = ref<SettleDetail[]>([]);
const del = (index: number) => {
dataList.value.splice(index, 1);
calTotals();
};
const totals = ref({ amountWithTax: 0, tax: 0, amountWithoutTax: 0 });
const calTotals = () => {
let amountWithTax = 0;
let tax = 0;
let amountWithoutTax = 0;
if (dataList.value && dataList.value.length > 0 && (dataList.value[0].taxRate !== undefined)) {
const taxRate = dataList.value[0].taxRate;
dataList.value.forEach(({ singleAmount, num, payRate }) => {
amountWithTax += singleAmount * num * payRate / 100;
});
amountWithTax = Number(amountWithTax.toFixed(2));
tax = amountWithTax * (taxRate / 100);
tax = Number(tax.toFixed(2));
amountWithoutTax = amountWithTax - tax;
amountWithoutTax = Number(amountWithoutTax.toFixed(2));
}
totals.value = { amountWithTax, tax, amountWithoutTax };
};
onMounted(() => {
dataList.value = props.dataSource;
calTotals();
});
watch(
() => props.dataSource,
(dataSource) => {
dataList.value = dataSource;
console.log(dataList.value)
console.log(dataList.value);
},
{ deep: true }
);
defineExpose({ dataList })
defineExpose({ dataList });
</script>

View File

@@ -23,26 +23,41 @@
/>
</template>
<template v-if="column.key === 'settleCycle'">
<span v-if="record.startDate && record.endDate">
{{ Math.floor(record.days / 30) }}
{{ record.days - (Math.floor(record.days / 30) * 30) }}
</span>
<a-row :gutter="16">
<a-col :span="12">
<a-input v-model:value="record.month">
<template #addonAfter></template>
</a-input>
</a-col>
<a-col :span="12">
<a-input v-model:value="record.day">
<template #addonAfter></template>
</a-input>
</a-col>
</a-row>
</template>
<template v-if="column.key === 'monthAmount'">
<a-input v-model:value="record.monthAmount" type="number" @change="changeDate($event, index)" />
</template>
<template v-if="column.key === 'dailyAmount'">
<span v-if="record.monthAmount">{{ record.dailyAmount }}</span>
<a-input v-model:value="record.dailyAmount" type="number" />
</template>
<template v-if="column.key === 'payRate'">
<a-input v-model:value="record.payRate" type="number">
<template #addonAfter>%</template>
</a-input>
</template>
<template v-if="column.key === 'amountWithTax'">
<span v-if="record.monthAmount">{{ (record.dailyAmount * record.days).toFixed(2) }}</span>
<span v-if="record.monthAmount">{{ ((record.dailyAmount * record.days + record.monthAmount * record.month) * record.payRate / 100).toFixed(2)
}}</span>
</template>
<template v-if="column.key === 'tax'">
<span v-if="record.monthAmount">{{ (record.dailyAmount * record.days * (record.taxRate / 100)).toFixed(2) }}</span>
<span v-if="record.monthAmount">{{ (((record.dailyAmount * record.days + record.monthAmount * record.month) * record.payRate / 100) * (record.taxRate / 100)).toFixed(2)
}}</span>
</template>
<template v-if="column.key === 'amountWithoutTax'">
<span
v-if="record.monthAmount">{{ ((record.dailyAmount * record.days) - (record.dailyAmount * record.days * (record.taxRate / 100))).toFixed(2)
v-if="record.monthAmount">{{ (((record.dailyAmount * record.days + record.monthAmount * record.month) * record.payRate / 100) - (record.dailyAmount * record.days * (record.taxRate / 100))).toFixed(2)
}}</span>
</template>
<template v-if="column.key === 'remark'">
@@ -55,6 +70,30 @@
</div>
</template>
</template>
<template #summary>
<a-table-summary-row>
<a-table-summary-cell>合计</a-table-summary-cell>
<a-table-summary-cell />
<a-table-summary-cell />
<a-table-summary-cell />
<a-table-summary-cell />
<a-table-summary-cell />
<a-table-summary-cell />
<a-table-summary-cell />
<a-table-summary-cell />
<a-table-summary-cell>
{{ totals.amountWithTax }}
</a-table-summary-cell>
<a-table-summary-cell>
{{ totals.tax }}
</a-table-summary-cell>
<a-table-summary-cell>
{{ totals.amountWithoutTax }}
</a-table-summary-cell>
<a-table-summary-cell />
<a-table-summary-cell />
</a-table-summary-row>
</template>
</a-table>
</template>
@@ -113,6 +152,16 @@ const columns = ref<ColumnItem[]>([
dataIndex: "settleCycle",
key: "settleCycle"
},
{
title: "实际进场日期",
dataIndex: "inDate",
key: "inDate"
},
{
title: "实际出场日期",
dataIndex: "outDate",
key: "outDate"
},
{
title: "月工资(元)",
dataIndex: "monthAmount",
@@ -123,6 +172,11 @@ const columns = ref<ColumnItem[]>([
dataIndex: "dailyAmount",
key: "dailyAmount"
},
{
title: "支付比例",
dataIndex: "payRate",
key: "payRate"
},
{
title: "含税金额(元)",
dataIndex: "amountWithTax",
@@ -154,8 +208,9 @@ const dataList = ref<SettleDetail[]>([]);
const changeDate = (data, index) => {
if (dataList.value[index].startDate && dataList.value[index].endDate) {
dataList.value[index].days = dayjs(dataList.value[index].endDate).diff(dayjs(dataList.value[index].startDate), "day");
console.log(dataList.value[index].days)
dataList.value[index].days = dayjs(dataList.value[index].endDate).diff(dayjs(dataList.value[index].startDate), "day") + 1;
dataList.value[index].month = Math.floor(dataList.value[index].days / 30);
dataList.value[index].day = dataList.value[index].days - (Math.floor(dataList.value[index].days / 30) * 30);
if (dataList.value[index].monthAmount) dataList.value[index].dailyAmount = (dataList.value[index].monthAmount / 30).toFixed(8);
}
};
@@ -164,15 +219,39 @@ const del = (index: number) => {
dataList.value.splice(index, 1);
};
const totals = ref({ amountWithTax: 0, tax: 0, amountWithoutTax: 0 });
const calTotals = () => {
let amountWithTax = 0;
let tax = 0;
let amountWithoutTax = 0;
if (dataList.value && dataList.value.length > 0 && (dataList.value[0].taxRate !== undefined)) {
const taxRate = dataList.value[0].taxRate;
dataList.value.forEach(({ month, monthAmount, day, dailyAmount, payRate }) => {
amountWithTax += (month * monthAmount + day * dailyAmount) * payRate / 100;
});
amountWithTax = Number(amountWithTax.toFixed(2));
tax = amountWithTax * (taxRate / 100);
tax = Number(tax.toFixed(2));
amountWithoutTax = amountWithTax - tax;
amountWithoutTax = Number(amountWithoutTax.toFixed(2));
}
totals.value = { amountWithTax, tax, amountWithoutTax };
};
onMounted(() => {
dataList.value = props.dataSource;
calTotals();
});
watch(
() => props.dataSource,
(dataSource) => {
dataList.value = dataSource;
calTotals();
},
{ deep: true }
);
defineExpose({ dataList })
defineExpose({ dataList });
</script>

View File

@@ -10,6 +10,22 @@
</a-select-option>
</a-select>
</template>
<template v-if="column.key === 'inDate'">
<a-date-picker
class="ele-fluid"
placeholder="请选择实际进场日期"
v-model:value="record.inDate"
valueFormat="YYYY-MM-DD"
/>
</template>
<template v-if="column.key === 'outDate'">
<a-date-picker
class="ele-fluid"
placeholder="请选择实际出场日期"
v-model:value="record.outDate"
valueFormat="YYYY-MM-DD"
/>
</template>
<template v-if="column.key === 'singleAmount'">
<a-input v-model:value="record.singleAmount" type="number" />
</template>
@@ -19,22 +35,24 @@
<template v-if="column.key === 'unit'">
<a-input v-model:value="record.unit" />
</template>
<template v-if="column.key === 'sumAmount'">
<span v-if="record.singleAmount && record.num">
{{ (record.singleAmount * record.num).toFixed(2) }}
</span>
<template v-if="column.key === 'payRate'">
<a-input v-model:value="record.payRate" type="number">
<template #addonAfter>%</template>
</a-input>
</template>
<template v-if="column.key === 'amountWithTax'">
<span v-if="record.singleAmount && record.num">{{ (record.singleAmount * record.num).toFixed(2) }}</span>
<span
v-if="record.singleAmount && record.num">{{ ((record.singleAmount * record.num) * record.payRate / 100).toFixed(2)
}}</span>
</template>
<template v-if="column.key === 'tax'">
<span
v-if="record.singleAmount && record.num">{{ (record.singleAmount * record.num * (record.taxRate / 100)).toFixed(2)
v-if="record.singleAmount && record.num">{{ ((record.singleAmount * record.num) * record.payRate / 100 * (record.taxRate / 100)).toFixed(2)
}}</span>
</template>
<template v-if="column.key === 'amountWithoutTax'">
<span
v-if="record.singleAmount && record.num">{{ ((record.singleAmount * record.num) - (record.singleAmount * record.num * (record.taxRate / 100))).toFixed(2)
v-if="record.singleAmount && record.num">{{ (((record.singleAmount * record.num) * record.payRate / 100) - (record.singleAmount * record.num * (record.taxRate / 100))).toFixed(2)
}}</span>
</template>
<template v-if="column.key === 'remark'">
@@ -47,6 +65,29 @@
</div>
</template>
</template>
<template #summary>
<a-table-summary-row>
<a-table-summary-cell>合计</a-table-summary-cell>
<a-table-summary-cell />
<a-table-summary-cell />
<a-table-summary-cell />
<a-table-summary-cell />
<a-table-summary-cell />
<a-table-summary-cell />
<a-table-summary-cell />
<a-table-summary-cell>
{{ totals.amountWithTax }}
</a-table-summary-cell>
<a-table-summary-cell>
{{ totals.tax }}
</a-table-summary-cell>
<a-table-summary-cell>
{{ totals.amountWithoutTax }}
</a-table-summary-cell>
<a-table-summary-cell />
<a-table-summary-cell />
</a-table-summary-row>
</template>
</a-table>
</template>
@@ -59,7 +100,7 @@ import {
CloseCircleOutlined
} from "@ant-design/icons-vue";
import dayjs from "dayjs";
import { DictDataParam } from "@/api/system/dict-data/model";
import { DictData, DictDataParam } from "@/api/system/dict-data/model";
import { listDictData } from "@/api/system/dict-data";
const props = defineProps<{
@@ -67,7 +108,7 @@ const props = defineProps<{
}>();
const tableRef0 = ref<InstanceType<typeof EleProTable> | null>(null);
const dictList = ref<DictDataParam[]>([]);
const dictList = ref<DictData[]>([]);
const getDictList = async () => {
dictList.value = await listDictData({ dictId: 146 });
};
@@ -97,6 +138,16 @@ const columns = ref<ColumnItem[]>([
dataIndex: "factoryNo",
key: "factoryNo"
},
{
title: "实际进场日期",
dataIndex: "inDate",
key: "inDate"
},
{
title: "实际出场日期",
dataIndex: "outDate",
key: "outDate"
},
{
title: "费用类型",
dataIndex: "settleCostType",
@@ -117,6 +168,11 @@ const columns = ref<ColumnItem[]>([
dataIndex: "unit",
key: "unit"
},
{
title: "支付比例",
dataIndex: "payRate",
key: "payRate"
},
{
title: "含税金额(元)",
dataIndex: "amountWithTax",
@@ -148,21 +204,42 @@ const dataList = ref<SettleDetail[]>([]);
const del = (index: number) => {
dataList.value.splice(index, 1);
calTotals();
};
const totals = ref({ amountWithTax: 0, tax: 0, amountWithoutTax: 0 });
const calTotals = () => {
let amountWithTax = 0;
let tax = 0;
let amountWithoutTax = 0;
if (dataList.value && dataList.value.length > 0 && (dataList.value[0].taxRate !== undefined)) {
const taxRate = dataList.value[0].taxRate;
dataList.value.forEach(({ singleAmount, num, payRate }) => {
amountWithTax += singleAmount * num * payRate / 100;
});
amountWithTax = Number(amountWithTax.toFixed(2));
tax = amountWithTax * (taxRate / 100);
tax = Number(tax.toFixed(2));
amountWithoutTax = amountWithTax - tax;
amountWithoutTax = Number(amountWithoutTax.toFixed(2));
}
totals.value = { amountWithTax, tax, amountWithoutTax };
};
watch(
() => props.dataSource,
(dataSource) => {
dataList.value = dataSource;
console.log(dataList.value);
calTotals();
},
{ deep: true }
);
onMounted(() => {
getDictList();
dataList.value = props.dataSource;
});
defineExpose({ dataList })
defineExpose({ dataList });
</script>

View File

@@ -10,6 +10,22 @@
</a-select-option>
</a-select>
</template>
<template v-if="column.key === 'inDate'">
<a-date-picker
class="ele-fluid"
placeholder="请选择实际进场日期"
v-model:value="record.inDate"
valueFormat="YYYY-MM-DD"
/>
</template>
<template v-if="column.key === 'outDate'">
<a-date-picker
class="ele-fluid"
placeholder="请选择实际出场日期"
v-model:value="record.outDate"
valueFormat="YYYY-MM-DD"
/>
</template>
<template v-if="column.key === 'singleAmount'">
<a-input v-model:value="record.singleAmount" type="number" />
</template>
@@ -19,22 +35,24 @@
<template v-if="column.key === 'unit'">
<a-input v-model:value="record.unit" />
</template>
<template v-if="column.key === 'sumAmount'">
<span v-if="record.singleAmount && record.num">
{{ (record.singleAmount * record.num).toFixed(2) }}
</span>
<template v-if="column.key === 'payRate'">
<a-input v-model:value="record.payRate" type="number">
<template #addonAfter>%</template>
</a-input>
</template>
<template v-if="column.key === 'amountWithTax'">
<span v-if="record.singleAmount && record.num">{{ (record.singleAmount * record.num).toFixed(2) }}</span>
<span
v-if="record.singleAmount && record.num">{{ ((record.singleAmount * record.num) * record.payRate / 100).toFixed(2)
}}</span>
</template>
<template v-if="column.key === 'tax'">
<span
v-if="record.singleAmount && record.num">{{ (record.singleAmount * record.num * (record.taxRate / 100)).toFixed(2)
v-if="record.singleAmount && record.num">{{ ((record.singleAmount * record.num) * record.payRate / 100 * (record.taxRate / 100)).toFixed(2)
}}</span>
</template>
<template v-if="column.key === 'amountWithoutTax'">
<span
v-if="record.singleAmount && record.num">{{ ((record.singleAmount * record.num) - (record.singleAmount * record.num * (record.taxRate / 100))).toFixed(2)
v-if="record.singleAmount && record.num">{{ (((record.singleAmount * record.num) * record.payRate / 100) - (record.singleAmount * record.num * (record.taxRate / 100))).toFixed(2)
}}</span>
</template>
<template v-if="column.key === 'remark'">
@@ -47,6 +65,29 @@
</div>
</template>
</template>
<template #summary>
<a-table-summary-row>
<a-table-summary-cell>合计</a-table-summary-cell>
<a-table-summary-cell />
<a-table-summary-cell />
<a-table-summary-cell />
<a-table-summary-cell />
<a-table-summary-cell />
<a-table-summary-cell />
<a-table-summary-cell />
<a-table-summary-cell>
{{ totals.amountWithTax }}
</a-table-summary-cell>
<a-table-summary-cell>
{{ totals.tax }}
</a-table-summary-cell>
<a-table-summary-cell>
{{ totals.amountWithoutTax }}
</a-table-summary-cell>
<a-table-summary-cell />
<a-table-summary-cell />
</a-table-summary-row>
</template>
</a-table>
</template>
@@ -59,7 +100,7 @@ import {
CloseCircleOutlined
} from "@ant-design/icons-vue";
import dayjs from "dayjs";
import { DictDataParam } from "@/api/system/dict-data/model";
import { DictData, DictDataParam } from "@/api/system/dict-data/model";
import { listDictData } from "@/api/system/dict-data";
const props = defineProps<{
@@ -67,7 +108,7 @@ const props = defineProps<{
}>();
const tableRef0 = ref<InstanceType<typeof EleProTable> | null>(null);
const dictList = ref<DictDataParam[]>([]);
const dictList = ref<DictData[]>([]);
const getDictList = async () => {
dictList.value = await listDictData({ dictId: 147 });
};
@@ -97,6 +138,16 @@ const columns = ref<ColumnItem[]>([
dataIndex: "factoryNo",
key: "factoryNo"
},
{
title: "实际进场日期",
dataIndex: "inDate",
key: "inDate"
},
{
title: "实际出场日期",
dataIndex: "outDate",
key: "outDate"
},
{
title: "费用类型",
dataIndex: "settleCostType",
@@ -117,6 +168,11 @@ const columns = ref<ColumnItem[]>([
dataIndex: "unit",
key: "unit"
},
{
title: "支付比例",
dataIndex: "payRate",
key: "payRate"
},
{
title: "含税金额(元)",
dataIndex: "amountWithTax",
@@ -148,21 +204,42 @@ const dataList = ref<SettleDetail[]>([]);
const del = (index: number) => {
dataList.value.splice(index, 1);
calTotals();
};
const totals = ref({ amountWithTax: 0, tax: 0, amountWithoutTax: 0 });
const calTotals = () => {
let amountWithTax = 0;
let tax = 0;
let amountWithoutTax = 0;
if (dataList.value && dataList.value.length > 0 && (dataList.value[0].taxRate !== undefined)) {
const taxRate = dataList.value[0].taxRate;
dataList.value.forEach(({ singleAmount, num, payRate }) => {
amountWithTax += singleAmount * num * payRate / 100;
});
amountWithTax = Number(amountWithTax.toFixed(2));
tax = amountWithTax * (taxRate / 100);
tax = Number(tax.toFixed(2));
amountWithoutTax = amountWithTax - tax;
amountWithoutTax = Number(amountWithoutTax.toFixed(2));
}
totals.value = { amountWithTax, tax, amountWithoutTax };
};
watch(
() => props.dataSource,
(dataSource) => {
dataList.value = dataSource;
console.log(dataList.value);
calTotals();
},
{ deep: true }
);
onMounted(() => {
getDictList();
dataList.value = props.dataSource;
});
defineExpose({ dataList })
defineExpose({ dataList });
</script>

View File

@@ -35,7 +35,7 @@
<a-form-item label="结算项目" v-bind="validateInfos.contractId">
<TowerContractSelectModel
:placeholder="`请选择结算项目`"
v-model:value="contactNumber"
v-model:value="projectName"
@done="chooseContract"
/>
</a-form-item>
@@ -44,167 +44,168 @@
</a-form-item>
</a-col>
<a-col :md="8" :sm="24" :xs="24">
<a-form-item label="本期开始日期" v-bind="validateInfos.startDate">
<a-date-picker
class="ele-fluid"
placeholder="请选择开始日期"
v-model:value="form.startDate"
valueFormat="YYYY-MM-DD"
/>
</a-form-item>
<a-form-item label="结算方式">
<a-select placeholder="请先选择项目" style="width: 250px" size="small" :disabled="!form.contractId"
v-model:value="form.settleMethod">
<a-select-option v-for="(item, index) in ContractSettleMethod" :key="index" :value="index">
{{ item }}
</a-select-option>
</a-select>
<a-form-item label="本期开始日期" v-bind="validateInfos.dateRange">
<a-range-picker v-model:value="dateRange" picker="month" />
</a-form-item>
<!-- <a-form-item label="本期开始日期" v-bind="validateInfos.startDate">-->
<!-- <a-date-picker-->
<!-- class="ele-fluid"-->
<!-- placeholder="请选择开始日期"-->
<!-- v-model:value="form.startDate"-->
<!-- valueFormat="YYYY-MM-DD"-->
<!-- />-->
<!-- </a-form-item>-->
<!-- <a-form-item label="结算方式">-->
<!-- <a-select placeholder="请先选择项目" style="width: 250px" size="small" :disabled="!form.contractId"-->
<!-- v-model:value="form.settleMethod">-->
<!-- <a-select-option v-for="(item, index) in ContractSettleMethod" :key="index" :value="index">-->
<!-- {{ item }}-->
<!-- </a-select-option>-->
<!-- </a-select>-->
<!-- </a-form-item>-->
</a-col>
<a-col :md="8" :sm="24" :xs="24">
<a-form-item label="本期结束日期" v-bind="validateInfos.endDate">
<a-date-picker
class="ele-fluid"
placeholder="请选择开始日期"
v-model:value="form.endDate"
valueFormat="YYYY-MM-DD"
/>
</a-form-item>
<div v-if="[0, 3].indexOf(form.settleMethod) > -1">
<span>每月</span>
<a-select placeholder="必选项" style="width: 250px" size="small"
v-model:value="form.extendMonthDate">
<a-select-option v-for="item in dateList" :key="item" :value="item">
{{ item }}
</a-select-option>
</a-select>
<span></span>
<span class="ml-05">至下月</span>
<span class="ml-05" v-if="form.extendMonthDate">{{ form.extendMonthDate - 1 }}</span>
</div>
</a-col>
<!-- <a-col :md="8" :sm="24" :xs="24">-->
<!-- <a-form-item label="本期结束日期" v-bind="validateInfos.endDate">-->
<!-- <a-date-picker-->
<!-- class="ele-fluid"-->
<!-- placeholder="请选择开始日期"-->
<!-- v-model:value="form.endDate"-->
<!-- valueFormat="YYYY-MM-DD"-->
<!-- />-->
<!-- </a-form-item>-->
<!-- <div v-if="[0, 3].indexOf(form.settleMethod) > -1">-->
<!-- <span>每月</span>-->
<!-- <a-select placeholder="必选项" style="width: 250px" size="small"-->
<!-- v-model:value="form.extendMonthDate">-->
<!-- <a-select-option v-for="item in dateList" :key="item" :value="item">-->
<!-- {{ item }}-->
<!-- </a-select-option>-->
<!-- </a-select>-->
<!-- <span></span>-->
<!-- <span class="ml-05">至下月</span>-->
<!-- <span class="ml-05" v-if="form.extendMonthDate">{{ form.extendMonthDate - 1 }}</span>-->
<!-- </div>-->
<!-- </a-col>-->
</a-row>
</a-card>
</a-form>
<a-card>
<a-tabs v-model:activeKey="activeKey">
<a-tab-pane :key="0" tab="租金结算">
<template #default>
<div class="flex justify-between items-center">
<div class="flex-1">
<a-button :disabled="!form.contractId || contractEquipmentList.length === 0" type="primary"
@click.native="doShowSelectEquipment(0)">
选择结算设备
</a-button>
<a-button class="mx-05" :disabled="!form.contractId || contractEquipmentList.length === 0"
type="primary" @click.native="oneKetAddEquipment(0)">一键加载结算设备
</a-button>
<a-button :disabled="!form.startDate || !form.startDate" type="primary"
@click.native="onyKeyAsyncDate(0)">同步结算起止日期
</a-button>
</div>
<a-input style="width: 300px" v-model:value="taxRate[0]" @change="changeTaxRate($event, 0)">
<template #prefix>税率</template>
<template #addonAfter>%</template>
</a-input>
<a-tabs v-model:activeKey="activeKey">
<a-tab-pane :key="0" tab="租金结算">
<template #default v-if="activeKey === 0">
<div class="flex justify-between items-center">
<div class="flex-1">
<a-button :disabled="!form.contractId || contractEquipmentList.length === 0" type="primary"
@click.native="doShowSelectEquipment(0)">
新增
</a-button>
<!-- <a-button class="mx-05" :disabled="!form.contractId || contractEquipmentList.length === 0"-->
<!-- type="primary" @click.native="oneKetAddEquipment(0)">一键加载结算设备-->
<!-- </a-button>-->
<!-- <a-button :disabled="!form.startDate || !form.startDate" type="primary"-->
<!-- @click.native="onyKeyAsyncDate(0)">同步结算起止日期-->
<!-- </a-button>-->
</div>
<table0 :data-source="dataSource[0]" />
</template>
</a-tab-pane>
<a-tab-pane :key="1" tab="进退场费">
<template #default>
<div class="flex justify-between items-center">
<div class="flex-1">
<a-button :disabled="!form.contractId || contractEquipmentList.length === 0" type="primary"
@click.native="doShowSelectEquipment(1)">
选择结算设备
</a-button>
<a-button class="mx-05" :disabled="!form.contractId || contractEquipmentList.length === 0"
type="primary" @click.native="oneKetAddEquipment(1)">一键加载结算设备
</a-button>
<a-button :disabled="!form.startDate || !form.startDate" type="primary"
@click.native="onyKeyAsyncDate(1)">同步结算起止日期
</a-button>
</div>
<a-input style="width: 300px" v-model:value="taxRate[1]" @change="changeTaxRate($event, 1)">
<template #prefix>税率</template>
<template #addonAfter>%</template>
</a-input>
<a-input style="width: 300px" v-model:value="taxRate[0]" @change="changeTaxRate($event, 0)">
<template #prefix>税率</template>
<template #addonAfter>%</template>
</a-input>
</div>
<table0 :data-source="dataSource[0]" />
</template>
</a-tab-pane>
<a-tab-pane :key="1" tab="进退场费">
<template #default v-if="activeKey === 1">
<div class="flex justify-between items-center">
<div class="flex-1">
<a-button :disabled="!form.contractId || contractEquipmentList.length === 0" type="primary"
@click.native="doShowSelectEquipment(1)">
选择结算设备
</a-button>
<a-button class="mx-05" :disabled="!form.contractId || contractEquipmentList.length === 0"
type="primary" @click.native="oneKetAddEquipment(1)">一键加载结算设备
</a-button>
<a-button :disabled="!form.startDate || !form.startDate" type="primary"
@click.native="onyKeyAsyncDate(1)">同步结算起止日期
</a-button>
</div>
<table1 :data-source="dataSource[1]" />
</template>
</a-tab-pane>
<a-tab-pane :key="2" tab="操作人员工资结算">
<template #default>
<div class="flex justify-between items-center">
<div class="flex-1">
<a-button :disabled="!form.contractId || contractEquipmentList.length === 0" type="primary"
@click.native="doShowSelectEquipment(2)">
选择结算设备
</a-button>
<a-button class="mx-05" :disabled="!form.contractId || contractEquipmentList.length === 0"
type="primary" @click.native="oneKetAddEquipment(2)">一键加载结算设备
</a-button>
<a-button :disabled="!form.startDate || !form.startDate" type="primary"
@click.native="onyKeyAsyncDate(2)">同步结算起止日期
</a-button>
</div>
<a-input style="width: 300px" v-model:value="taxRate[2]" @change="changeTaxRate($event, 2)">
<template #prefix>税率</template>
<template #addonAfter>%</template>
</a-input>
<a-input style="width: 300px" v-model:value="taxRate[1]" @change="changeTaxRate($event, 1)">
<template #prefix>税率</template>
<template #addonAfter>%</template>
</a-input>
</div>
<table1 :data-source="dataSource[1]" />
</template>
</a-tab-pane>
<a-tab-pane :key="2" tab="操作人员工资结算">
<template #default>
<div class="flex justify-between items-center">
<div class="flex-1">
<a-button :disabled="!form.contractId || contractEquipmentList.length === 0" type="primary"
@click.native="doShowSelectEquipment(2)">
选择结算设备
</a-button>
<a-button class="mx-05" :disabled="!form.contractId || contractEquipmentList.length === 0"
type="primary" @click.native="oneKetAddEquipment(2)">一键加载结算设备
</a-button>
<!-- <a-button :disabled="!form.startDate || !form.startDate" type="primary"-->
<!-- @click.native="onyKeyAsyncDate(2)">同步结算起止日期-->
<!-- </a-button>-->
</div>
<table2 :data-source="dataSource[2]" />
</template>
</a-tab-pane>
<a-tab-pane :key="3" tab="其他费用清单">
<template #default>
<div class="flex justify-between items-center">
<div class="flex-1">
<a-button :disabled="!form.contractId || contractEquipmentList.length === 0" type="primary"
@click.native="doShowSelectEquipment(3)">
选择结算设备
</a-button>
<a-button class="mx-05" :disabled="!form.contractId || contractEquipmentList.length === 0"
type="primary" @click.native="oneKetAddEquipment(3)">一键加载结算设备
</a-button>
<a-button :disabled="!form.startDate || !form.startDate" type="primary"
@click.native="onyKeyAsyncDate(3)">同步结算起止日期
</a-button>
</div>
<a-input style="width: 300px" v-model:value="taxRate[3]" @change="changeTaxRate($event, 3)">
<template #prefix>税率</template>
<template #addonAfter>%</template>
</a-input>
<a-input style="width: 300px" v-model:value="taxRate[2]" @change="changeTaxRate($event, 2)">
<template #prefix>税率</template>
<template #addonAfter>%</template>
</a-input>
</div>
<table2 :data-source="dataSource[2]" v-if="activeKey === 2" />
</template>
</a-tab-pane>
<a-tab-pane :key="3" tab="其他费用清单">
<template #default v-if="activeKey === 3">
<div class="flex justify-between items-center">
<div class="flex-1">
<a-button :disabled="!form.contractId || contractEquipmentList.length === 0" type="primary"
@click.native="doShowSelectEquipment(3)">
选择结算设备
</a-button>
<a-button class="mx-05" :disabled="!form.contractId || contractEquipmentList.length === 0"
type="primary" @click.native="oneKetAddEquipment(3)">一键加载结算设备
</a-button>
<!-- <a-button :disabled="!form.startDate || !form.startDate" type="primary"-->
<!-- @click.native="onyKeyAsyncDate(3)">同步结算起止日期-->
<!-- </a-button>-->
</div>
<table3 :data-source="dataSource[3]" />
</template>
</a-tab-pane>
<a-tab-pane :key="4" tab="扣除项">
<template #default>
<div class="flex justify-between items-center">
<div class="flex-1">
<a-button :disabled="!form.contractId || contractEquipmentList.length === 0" type="primary"
@click.native="doShowSelectEquipment(4)">
选择结算设备
</a-button>
<a-button class="mx-05" :disabled="!form.contractId || contractEquipmentList.length === 0"
type="primary" @click.native="oneKetAddEquipment(4)">一键加载结算设备
</a-button>
<a-button :disabled="!form.startDate || !form.startDate" type="primary"
@click.native="onyKeyAsyncDate(4)">同步结算起止日期
</a-button>
</div>
<a-input style="width: 300px" v-model:value="taxRate[4]" @change="changeTaxRate($event, 4)">
<template #prefix>税率</template>
<template #addonAfter>%</template>
</a-input>
<a-input style="width: 300px" v-model:value="taxRate[3]" @change="changeTaxRate($event, 3)">
<template #prefix>税率</template>
<template #addonAfter>%</template>
</a-input>
</div>
<table3 :data-source="dataSource[3]" />
</template>
</a-tab-pane>
<a-tab-pane :key="4" tab="扣除项">
<template #default v-if="activeKey === 4">
<div class="flex justify-between items-center">
<div class="flex-1">
<a-button :disabled="!form.contractId || contractEquipmentList.length === 0" type="primary"
@click.native="doShowSelectEquipment(4)">
选择结算设备
</a-button>
<a-button class="mx-05" :disabled="!form.contractId || contractEquipmentList.length === 0"
type="primary" @click.native="oneKetAddEquipment(4)">一键加载结算设备
</a-button>
<!-- <a-button :disabled="!form.startDate || !form.startDate" type="primary"-->
<!-- @click.native="onyKeyAsyncDate(4)">同步结算起止日期-->
<!-- </a-button>-->
</div>
<table4 :data-source="dataSource[4]" />
</template>
</a-tab-pane>
</a-tabs>
</a-card>
<a-input style="width: 300px" v-model:value="taxRate[4]" @change="changeTaxRate($event, 4)">
<template #prefix>税率</template>
<template #addonAfter>%</template>
</a-input>
</div>
<table4 :data-source="dataSource[4]" />
</template>
</a-tab-pane>
</a-tabs>
</ele-modal>
<ele-modal
:width="'80%'"
@@ -237,7 +238,7 @@ import { Form, message } from "ant-design-vue";
import { assignObject, EleProTable } from "ele-admin-pro";
import { useUserStore } from "@/store/modules/user";
import { Contract, ContractSettleMethod } from "@/api/tower/contract/model";
import dayjs from "dayjs";
import dayjs, { Dayjs } from "dayjs";
import { Settle } from "@/api/tower/settle/model";
import { addSettle, updateSettle } from "@/api/tower/settle";
@@ -310,7 +311,6 @@ const getDataSource = async () => {
res.forEach(item => {
if ((item.type === 0 || item.type === 2)) {
const days = dayjs(item.endDate).diff(dayjs(item.startDate), "day");
item.dailyAmount = (item.monthAmount / 30).toFixed(2);
item = { ...item, ...{ days } };
}
dataSource.value[item.type].push(item);
@@ -339,32 +339,40 @@ const rules = reactive({
trigger: "blur"
}
],
startDate: [
{
required: true,
message: "请选择开始日期",
trigger: "blur"
}
],
endDate: [
{
required: true,
message: "请选择结束日期",
trigger: "blur"
}
],
// startDate: [
// {
// required: true,
// message: "请选择开始日期",
// trigger: "blur"
// }
// ],
// endDate: [
// {
// required: true,
// message: "请选择结束日期",
// trigger: "blur"
// }
// ],
settleNo: [
{
required: true,
message: "请输入结算单号",
trigger: "blur"
}
]
],
dateRange: [
{
required: true,
message: "请选择所属期间",
trigger: "blur"
}
],
});
const contactNumber = ref<string | undefined>("");
const projectName = ref<string | undefined>("");
const chooseContract = (res: Contract) => {
contactNumber.value = res.contactNumber;
projectName.value = res.projectName;
form.contractId = res.contractId;
form.settleMethod = res.settleMethod;
form.startDate = res.startDate;
@@ -374,6 +382,8 @@ const chooseContract = (res: Contract) => {
const { resetFields, validate, validateInfos } = useForm(form, rules);
const dateRange = ref<[Dayjs, Dayjs] | [string, string]>()
/* 保存编辑 */
const save = () => {
validate()
@@ -385,9 +395,12 @@ const save = () => {
let totalAmount = 0;
dataSource.value.forEach(data => {
data.forEach(item => {
if ((item.type === 0 || item.type === 2) && item.dailyAmount && item.days) totalAmount += item.dailyAmount * item.days;
else if ((item.type === 1 || item.type === 3) && item.singleAmount && item.num) totalAmount += item.singleAmount * item.num;
else if (item.type === 4 && item.singleAmount && item.num) totalAmount -= item.singleAmount * item.num;
if ((item.type === 0 || item.type === 2) && item.dailyAmount && item.days)
totalAmount += (item.dailyAmount * item.day) + (item.monthAmount * item.month);
else if ((item.type === 1 || item.type === 3) && item.singleAmount && item.num)
totalAmount += item.singleAmount * item.num;
else if (item.type === 4 && item.singleAmount && item.num)
totalAmount -= item.singleAmount * item.num;
});
});
data.totalAmount = totalAmount;
@@ -446,7 +459,7 @@ const addDataSource = (data: ContractSettleEquipment, index) => {
// factoryNo: data.factoryNo,
startDate: form.startDate ?? "",
endDate: form.endDate ?? "",
monthAmount: 0,
monthAmount: data.rentAmount ?? 0,
taxRate: taxRate.value[index],
singleAmount: 0,
num: 0,
@@ -454,7 +467,10 @@ const addDataSource = (data: ContractSettleEquipment, index) => {
remark: "",
userId: loginUser.value.userId,
days,
dailyAmount: 0
dailyAmount: 0,
inDate: "",
outDate: "",
payRate: 100
});
};
@@ -480,13 +496,15 @@ watch(
loading.value = false;
assignObject(form, props.data);
isUpdate.value = true;
contactNumber.value = props.data.contactNumber;
projectName.value = props.data.projectName;
getDataSource();
getContractEquipmentList();
} else {
isUpdate.value = false;
}
} else {
contactNumber.value = "";
projectName.value = "";
dataSource.value = [[], [], [], [], []];
resetFields();
}
}

View File

@@ -27,6 +27,9 @@
{{ timeAgo(record.createTime) }}
</a-tooltip>
</template>
<template v-if="column.key === 'date'">
{{ dayjs(record.startDate).format('YYYY-MM') }} ~ {{ dayjs(record.endDate).format('YYYY-MM') }}
</template>
<template v-if="column.key === 'action'">
<a-space>
<a @click="openEdit(record)">修改</a>
@@ -73,6 +76,7 @@
import { useUserStore } from '@/store/modules/user';
import { pageSettle, removeBatchSettle, removeSettle } from "@/api/tower/settle";
import { Settle, SettleParam } from "@/api/tower/settle/model";
import dayjs from "dayjs";
const userStore = useUserStore();
// 当前用户信息
@@ -122,11 +126,6 @@
hideInSetting: true,
customRender: ({ index }) => index + (tableRef.value?.tableIndex ?? 0)
},
{
title: '结算状态',
dataIndex: 'status',
key: 'status',
},
{
title: '项目名称',
dataIndex: 'projectName'
@@ -135,13 +134,17 @@
title: '合同编号',
dataIndex: 'contactNumber'
},
// {
// title: '结算开始日期',
// dataIndex: 'endDate'
// },
// {
// title: '结算结束日期',
// dataIndex: 'endDate'
// },
{
title: '结算开始日期',
dataIndex: 'endDate'
},
{
title: '结算结束日期',
dataIndex: 'endDate'
title: '所属期间',
key: 'date'
},
{
title: '本次结算总额',