0905
This commit is contained in:
@ -27,9 +27,9 @@
|
||||
<el-col :span="1.5">
|
||||
<el-button type="primary" plain icon="Plus" @click="handleAdd" v-hasPermi="['land:enterRoad:add']">新增</el-button>
|
||||
</el-col>
|
||||
<el-col :span="1.5">
|
||||
<!-- <el-col :span="1.5">
|
||||
<el-button type="success" plain icon="Plus" @click="downloadTemplate" v-hasPermi="['land:enterRoad:import']">模板下载</el-button>
|
||||
</el-col>
|
||||
</el-col> -->
|
||||
<el-col :span="1.5">
|
||||
<el-upload
|
||||
ref="uploadRef"
|
||||
|
||||
@ -36,9 +36,9 @@
|
||||
<el-col :span="1.5">
|
||||
<el-button type="primary" plain icon="Plus" @click="handleAdd" v-hasPermi="['land:landBlock:add']">新增</el-button>
|
||||
</el-col>
|
||||
<el-col :span="1.5">
|
||||
<!-- <el-col :span="1.5">
|
||||
<el-button type="success" plain icon="Plus" @click="downloadTemplate" v-hasPermi="['land:enterRoad:import']">模板下载</el-button>
|
||||
</el-col>
|
||||
</el-col> -->
|
||||
<el-col :span="1.5">
|
||||
<el-upload ref="uploadRef" class="upload-demo" :http-request="handleImport" :show-file-list="false">
|
||||
<template #trigger>
|
||||
@ -78,6 +78,7 @@
|
||||
</el-table>
|
||||
<pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" @pagination="getList" />
|
||||
</el-card>
|
||||
|
||||
<!-- 地块表单弹窗 -->
|
||||
<el-dialog draggable :title="dialog.title" v-model="dialog.visible" width="500px" append-to-body>
|
||||
<el-form ref="landBlockFormRef" :model="form" :rules="rules" label-width="100px">
|
||||
@ -107,20 +108,22 @@
|
||||
</div>
|
||||
</template>
|
||||
</el-dialog>
|
||||
<!-- 关联方阵弹窗(核心修改区域) -->
|
||||
|
||||
<!-- 关联方阵弹窗(核心修复区域) -->
|
||||
<el-dialog draggable :title="dialogMatrix.title" v-model="dialogMatrix.visible" width="900px" append-to-body>
|
||||
<el-button type="primary" plain icon="Plus" @click="addUnitBoItem" style="margin-bottom: 15px">添加</el-button>
|
||||
<!-- 方阵表单:绑定unitBoList的索引,实现动态校验 -->
|
||||
<!-- 修复1:表单模型绑定formM(根模型),确保嵌套字段校验生效 -->
|
||||
<el-form ref="landBlockFormMatrixRef" :model="formM" label-width="100px">
|
||||
<el-row v-for="(item, i) of unitBoList" :key="i" class="mb-4">
|
||||
<!-- 方阵选择:必填校验 -->
|
||||
<!-- 修复2:循环formM.unitBoList(而非独立ref),保证数据双向绑定 -->
|
||||
<el-row v-for="(item, i) of formM.unitBoList" :key="i" class="mb-4">
|
||||
<!-- 方阵选择:修复校验规则(移除min:2,改为min:1,适配单层级选择) -->
|
||||
<el-col :span="8">
|
||||
<el-form-item
|
||||
label="方阵"
|
||||
:prop="`unitBoList[${i}].unitProjectId`"
|
||||
:rules="[
|
||||
{ required: true, message: '请选择方阵', trigger: 'change' },
|
||||
{ type: 'array', min: 2, message: '请选择完整的方阵层级', trigger: 'change' }
|
||||
{ type: 'array', min: 1, message: '请选择完整的方阵', trigger: 'change' }
|
||||
]"
|
||||
>
|
||||
<el-cascader
|
||||
@ -133,7 +136,7 @@
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<!-- 所属工区:必填校验 -->
|
||||
<!-- 所属工区:保留原有规则 -->
|
||||
<el-col :span="8">
|
||||
<el-form-item
|
||||
label="所属工区"
|
||||
@ -143,7 +146,7 @@
|
||||
<el-input v-model="item.unitProjectArea" placeholder="请输入所属工区" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<!-- 方阵状态:必填校验 -->
|
||||
<!-- 方阵状态:保留原有规则 -->
|
||||
<el-col :span="6">
|
||||
<el-form-item
|
||||
label="方阵状态"
|
||||
@ -153,8 +156,15 @@
|
||||
<el-input v-model="item.unitProjectStatus" placeholder="请输入方阵状态" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<!-- 删除按钮:禁用逻辑优化(至少保留1项) -->
|
||||
<el-col :span="1" style="margin-left: 15px; display: flex; align-items: flex-end">
|
||||
<el-button style="margin-bottom: 18px" type="danger" icon="Delete" @click="removeUnitBoItem(i)"></el-button>
|
||||
<el-button
|
||||
style="margin-bottom: 18px"
|
||||
type="danger"
|
||||
icon="Delete"
|
||||
@click="removeUnitBoItem(i)"
|
||||
:disabled="formM.unitBoList.length <= 1"
|
||||
></el-button>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-form>
|
||||
@ -181,21 +191,35 @@ import {
|
||||
} from '@/api/system/landTransfer/landBlock';
|
||||
import { LandBlockVO, LandBlockQuery, LandBlockForm } from '@/api/system/landTransfer/landBlock/types';
|
||||
import { useUserStoreHook } from '@/store/modules/user';
|
||||
import { getCurrentInstance, ComponentInternalInstance, onMounted, onUnmounted, watch } from 'vue';
|
||||
import { ElFormInstance, ElMessage } from 'element-plus';
|
||||
import { getCurrentInstance, ComponentInternalInstance, onMounted, onUnmounted, watch, reactive, ref, toRefs, computed } from 'vue';
|
||||
import { ElFormInstance } from 'element-plus';
|
||||
|
||||
// 类型定义补充(避免any)
|
||||
// 类型定义补充
|
||||
interface DialogOption {
|
||||
visible: boolean;
|
||||
title: string;
|
||||
}
|
||||
|
||||
// 方阵级联选择器选项类型
|
||||
interface FangzhenOption {
|
||||
matrixId: string | number;
|
||||
name: string;
|
||||
children?: FangzhenOption[];
|
||||
}
|
||||
|
||||
// 方阵表单项类型
|
||||
interface UnitBoItem {
|
||||
unitProjectArea: string;
|
||||
unitProjectStatus: string;
|
||||
unitProjectId: (string | number)[]; // 级联选择值(数组)
|
||||
}
|
||||
|
||||
// 方阵表单根模型类型(关键:显式声明unitBoList)
|
||||
interface MatrixForm {
|
||||
landId?: string | number; // 关联的地块ID
|
||||
unitBoList: UnitBoItem[]; // 方阵列表
|
||||
}
|
||||
|
||||
// 基础实例与Store
|
||||
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
||||
const userStore = useUserStoreHook();
|
||||
@ -203,14 +227,17 @@ const currentProject = computed(() => userStore.selectedProject);
|
||||
|
||||
// 响应式数据
|
||||
const landBlockList = ref<LandBlockVO[]>([]);
|
||||
const fangzhenList = ref<any[]>([]); // 方阵列表(实际项目建议定义具体类型)
|
||||
const fangzhenList = ref<FangzhenOption[]>([]);
|
||||
const buttonLoading = ref(false);
|
||||
const loading = ref(true);
|
||||
const showSearch = ref(true);
|
||||
const uploadRef = ref<any>(null); // upload组件ref
|
||||
const uploadRef = ref<any>(null);
|
||||
|
||||
// 方阵表单数据(核心修改:初始值为空,避免默认填充无效数据)
|
||||
const unitBoList = ref<UnitBoItem[]>([{ unitProjectArea: '', unitProjectStatus: '', unitProjectId: [] }]);
|
||||
// 方阵表单模型(核心修复:使用reactive并显式声明结构)
|
||||
const formM = ref<MatrixForm>({
|
||||
landId: undefined,
|
||||
unitBoList: [{ unitProjectArea: '', unitProjectStatus: '', unitProjectId: [] }]
|
||||
});
|
||||
|
||||
// 表格选择相关
|
||||
const ids = ref<Array<string | number>>([]);
|
||||
@ -243,7 +270,6 @@ const initFormData: LandBlockForm = {
|
||||
// 核心数据(含表单规则)
|
||||
const data = reactive({
|
||||
form: { ...initFormData },
|
||||
formM: { landId: undefined }, // 方阵关联表单(仅存地块ID)
|
||||
queryParams: {
|
||||
pageNum: 1,
|
||||
pageSize: 10,
|
||||
@ -256,7 +282,7 @@ const data = reactive({
|
||||
farmerCount: undefined,
|
||||
params: {}
|
||||
},
|
||||
// 地块表单规则(原有规则保留)
|
||||
// 地块表单规则
|
||||
rules: {
|
||||
id: [{ required: true, message: '主键ID不能为空', trigger: 'blur' }],
|
||||
projectId: [{ required: true, message: '项目ID不能为空', trigger: 'blur' }],
|
||||
@ -265,7 +291,7 @@ const data = reactive({
|
||||
}
|
||||
});
|
||||
|
||||
const { queryParams, form, rules, formM } = toRefs(data);
|
||||
const { queryParams, form, rules } = toRefs(data);
|
||||
|
||||
/** 查询地块列表 */
|
||||
const getList = async () => {
|
||||
@ -381,10 +407,10 @@ const getfangzhenList = async () => {
|
||||
loading.value = true;
|
||||
try {
|
||||
const res = await subMatrix(currentProject.value.id);
|
||||
// 处理方阵数据(级联选择需父子结构,此处保留原有逻辑)
|
||||
// 处理方阵数据(级联选择需父子结构)
|
||||
res.data.forEach((item: any) => {
|
||||
item.children?.forEach((item2: any) => {
|
||||
item2.matrixId = `${item2.name}_${item2.matrixId}`; // 拼接名称+ID,便于后续拆分
|
||||
item2.matrixId = `${item2.name}_${item2.matrixId}`;
|
||||
});
|
||||
});
|
||||
fangzhenList.value = res.data;
|
||||
@ -395,55 +421,62 @@ const getfangzhenList = async () => {
|
||||
}
|
||||
};
|
||||
|
||||
/** 关联方阵(核心修改:打开弹窗前强制重置表单) */
|
||||
/** 关联方阵 */
|
||||
const handleView = async (row: LandBlockVO) => {
|
||||
if (!row?.id) return proxy?.$modal.msgWarning('请选择有效的地块');
|
||||
|
||||
// 1. 重置方阵表单(清空历史数据)
|
||||
console.log('🚀 ~ handleView ~ row:', row);
|
||||
// 重置方阵表单
|
||||
resetMatrix();
|
||||
// 2. 绑定当前地块ID
|
||||
// 绑定当前地块ID
|
||||
formM.value.landId = row.id;
|
||||
// 3. 打开弹窗
|
||||
// 打开弹窗
|
||||
dialogMatrix.visible = true;
|
||||
|
||||
dialogMatrix.title = `关联方阵(地块:${row.landName || row.landCode})`;
|
||||
};
|
||||
|
||||
/** 新增方阵表单项 */
|
||||
const addUnitBoItem = () => {
|
||||
unitBoList.value.push({
|
||||
formM.value.unitBoList.push({
|
||||
unitProjectArea: '',
|
||||
unitProjectStatus: '',
|
||||
unitProjectId: [] // 级联选择初始为空数组
|
||||
unitProjectId: []
|
||||
});
|
||||
// 重置校验状态
|
||||
landBlockFormMatrixRef.value?.clearValidate();
|
||||
};
|
||||
|
||||
/** 删除方阵表单项 */
|
||||
const removeUnitBoItem = (index: number) => {
|
||||
if (unitBoList.value.length <= 1) {
|
||||
if (formM.value.unitBoList.length <= 1) {
|
||||
return proxy?.$modal.msgWarning('至少保留一项方阵配置');
|
||||
}
|
||||
unitBoList.value.splice(index, 1);
|
||||
// 重置表单校验状态(避免删除后残留校验提示)
|
||||
formM.value.unitBoList.splice(index, 1);
|
||||
landBlockFormMatrixRef.value?.clearValidate();
|
||||
};
|
||||
|
||||
/** 提交方阵关联表单 */
|
||||
/** 提交方阵关联表单(核心修复:数据处理逻辑) */
|
||||
const submitFormMatrix = () => {
|
||||
landBlockFormMatrixRef.value?.validate(async (valid: boolean) => {
|
||||
if (!valid) return;
|
||||
if (!formM.value.landId) return proxy?.$modal.msgWarning('地块ID异常,请重新选择地块');
|
||||
|
||||
try {
|
||||
// 处理方阵数据(拆分名称+ID)
|
||||
const unitBoListParams = unitBoList.value.map((item) => {
|
||||
const [unitProjectName, unitProjectId] = item.unitProjectId[1]?.split('_') || [];
|
||||
if (!unitProjectId) throw new Error('方阵ID解析失败,请重新选择方阵');
|
||||
// 处理方阵数据(修复ID拆分逻辑)
|
||||
const unitBoListParams = formM.value.unitBoList.map((item) => {
|
||||
// 取级联选择的最后一层值
|
||||
const lastLevelValue = item.unitProjectId[item.unitProjectId.length - 1];
|
||||
if (!lastLevelValue) throw new Error('请选择完整的方阵');
|
||||
|
||||
// 拆分名称和ID
|
||||
const [unitProjectName, unitProjectId] = String(lastLevelValue).split('_');
|
||||
if (!unitProjectId) throw new Error('方阵ID解析失败,请重新选择');
|
||||
|
||||
return {
|
||||
unitProjectArea: item.unitProjectArea.trim(),
|
||||
unitProjectStatus: item.unitProjectStatus.trim(),
|
||||
unitProjectId: unitProjectId, // 纯ID(后端需要)
|
||||
unitProjectName: unitProjectName // 名称(可选,用于显示)
|
||||
unitProjectId: unitProjectId,
|
||||
unitProjectName: unitProjectName
|
||||
};
|
||||
});
|
||||
|
||||
@ -456,7 +489,7 @@ const submitFormMatrix = () => {
|
||||
if (res.code === 200) {
|
||||
proxy?.$modal.msgSuccess('关联方阵成功');
|
||||
dialogMatrix.visible = false;
|
||||
await getList(); // 刷新地块列表
|
||||
await getList();
|
||||
} else {
|
||||
proxy?.$modal.msgError(res.msg || '关联失败');
|
||||
}
|
||||
@ -472,17 +505,14 @@ const cancelMatrix = () => {
|
||||
dialogMatrix.visible = false;
|
||||
};
|
||||
|
||||
/** 方阵表单重置(核心修改:清空所有数据+重置校验) */
|
||||
/** 方阵表单重置 */
|
||||
const resetMatrix = () => {
|
||||
// 1. 清空地块ID
|
||||
formM.value.landId = undefined;
|
||||
// 2. 重置方阵列表(仅保留一个空项)
|
||||
unitBoList.value = [{ unitProjectArea: '', unitProjectStatus: '', unitProjectId: [] }];
|
||||
// 3. 重置表单校验状态
|
||||
if (landBlockFormMatrixRef.value) {
|
||||
landBlockFormMatrixRef.value.resetFields();
|
||||
landBlockFormMatrixRef.value.clearValidate();
|
||||
}
|
||||
formM.value.landId = undefined;
|
||||
formM.value.unitBoList = [{ unitProjectArea: '', unitProjectStatus: '', unitProjectId: [] }];
|
||||
};
|
||||
|
||||
/** 监听项目变化,刷新数据 */
|
||||
@ -491,11 +521,11 @@ const listeningProject = watch(
|
||||
(newId) => {
|
||||
if (newId) {
|
||||
queryParams.value.projectId = newId;
|
||||
getfangzhenList(); // 刷新方阵列表
|
||||
getList(); // 刷新地块列表
|
||||
getfangzhenList();
|
||||
getList();
|
||||
}
|
||||
},
|
||||
{ immediate: true } // 初始加载时执行一次
|
||||
{ immediate: true }
|
||||
);
|
||||
|
||||
/** 导入Excel */
|
||||
@ -524,36 +554,34 @@ const handleImport = (options: { file: File }) => {
|
||||
loading.value = false;
|
||||
});
|
||||
};
|
||||
|
||||
/** 导出模板 */
|
||||
const exportFile = () => {
|
||||
// 导出模版文件
|
||||
try {
|
||||
// 创建a标签
|
||||
const link = document.createElement('a');
|
||||
// 设置PDF文件路径 - 相对于public目录
|
||||
link.href = '/dikuai.xlsx';
|
||||
// 设置下载后的文件名
|
||||
link.download = '地块信息导入模版.xlsx';
|
||||
// 触发点击
|
||||
document.body.appendChild(link);
|
||||
link.click();
|
||||
// 清理
|
||||
document.body.removeChild(link);
|
||||
} catch (error) {
|
||||
alert('下载失败,请重试');
|
||||
}
|
||||
};
|
||||
|
||||
/** 下载导入模板 */
|
||||
const downloadTemplate = () => {
|
||||
try {
|
||||
const link = document.createElement('a');
|
||||
link.href = '/landBlock.xlsx'; // 模板路径(需确保public目录下存在该文件)
|
||||
link.download = '地块信息导入模板.xlsx'; // 下载后文件名
|
||||
link.href = '/landBlock.xlsx';
|
||||
link.download = '地块信息导入模板.xlsx';
|
||||
document.body.appendChild(link);
|
||||
link.click(); // 触发下载
|
||||
link.click();
|
||||
} catch (err) {
|
||||
proxy?.$modal.msgError('模板下载失败,请重试');
|
||||
} finally {
|
||||
document.body.removeChild(link); // 清理DOM
|
||||
const link = document.querySelector('a[download="地块信息导入模板.xlsx"]');
|
||||
if (link) document.body.removeChild(link);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@ -91,7 +91,9 @@
|
||||
<template #default="scope">
|
||||
<!-- 查看子项按钮 -->
|
||||
<el-tooltip content="查看子项" placement="top">
|
||||
<el-button link type="primary" @click="handleViewSons(scope.row)" v-hasPermi="['land:landTransferLedger:view']"> 查看子项 </el-button>
|
||||
<el-button link type="primary" @click="handleViewSons(scope.row)" v-hasPermi="['land:landTransferLedger:childrenList']">
|
||||
查看子项
|
||||
</el-button>
|
||||
</el-tooltip>
|
||||
<el-tooltip content="删除" placement="top">
|
||||
<el-button link type="primary" @click="handleDelete(scope.row)" v-hasPermi="['land:landTransferLedger:remove']">删除</el-button>
|
||||
@ -147,7 +149,9 @@
|
||||
<template #header>
|
||||
<el-row :gutter="10" class="mb8">
|
||||
<el-col :span="1.5">
|
||||
<el-button type="primary" plain icon="Plus" @click="handleAddSon" v-hasPermi="['land:landTransferLedger:addSon']"> 新增子项 </el-button>
|
||||
<el-button type="primary" plain icon="Plus" @click="handleAddSon" v-hasPermi="['land:landTransferLedger:childrenAdd']">
|
||||
新增子项
|
||||
</el-button>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</template>
|
||||
|
||||
@ -144,13 +144,16 @@
|
||||
</el-table-column> -->
|
||||
<el-table-column label="备注" align="center" prop="remark" />
|
||||
<el-table-column label="创建时间" align="center" prop="createTime" width="180" />
|
||||
<el-table-column fixed="right" label="操作" align="center" class-name="small-padding fixed-width" width="400">
|
||||
<el-table-column fixed="right" label="操作" align="center" width="500">
|
||||
<template #default="scope">
|
||||
<el-space>
|
||||
<el-button link type="primary" icon="Edit" @click="handleCheckRules(scope.row)" v-hasPermi="['project:attendanceRule:byProjectId']"
|
||||
>打卡规则
|
||||
</el-button>
|
||||
<el-button link type="primary" icon="Edit" @click="handleScope(scope.row)" v-hasPermi="['project:project:edit']">打卡范围 </el-button>
|
||||
<el-button link type="primary" icon="FolderOpened" @click="handleShowUpload(scope.row)" v-hasPermi="['project:project:edit']"
|
||||
>导入安全协议书
|
||||
</el-button>
|
||||
|
||||
<el-button link type="success" icon="Edit" @click="handleUpdate(scope.row)" v-hasPermi="['project:project:edit']">修改 </el-button>
|
||||
<el-button link type="danger" icon="Delete" @click="handleDelete(scope.row)" v-hasPermi="['project:project:remove']">删除 </el-button>
|
||||
<el-button link type="primary" icon="upload" @click="handleUpload(scope.row)" v-hasPermi="['project:project:saveTenderFile']"
|
||||
@ -160,7 +163,6 @@
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
|
||||
<pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" @pagination="getList" />
|
||||
</el-card>
|
||||
<!-- 添加或修改项目对话框 -->
|
||||
@ -253,78 +255,6 @@
|
||||
</el-col>
|
||||
</el-row>
|
||||
</div>
|
||||
<div class="block-box">
|
||||
<div class="">打卡设置</div>
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="12" :offset="0">
|
||||
<el-form-item label="打卡开始时间" prop="playCardStart" label-width="110px">
|
||||
<!-- <el-time-picker value-format="HH:mm" v-model="form.playCardStart" placeholder="请输入打卡开始时间" /> -->
|
||||
<el-time-select
|
||||
v-model="form.playCardStart"
|
||||
style="width: 100%"
|
||||
class="mr-4"
|
||||
placeholder="请输入打卡开始时间"
|
||||
value-format="HH:mm"
|
||||
start="00:00"
|
||||
step="00:15"
|
||||
end="23:59"
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12" :offset="0">
|
||||
<el-form-item label="打卡结束时间" prop="playCardEnd" label-width="110px">
|
||||
<!-- <el-time-picker value-format="HH:mm" v-model="form.playCardEnd" placeholder="请输入打卡结束时间" /> -->
|
||||
<el-time-select
|
||||
v-model="form.playCardEnd"
|
||||
style="width: 100%"
|
||||
:min-time="form.playCardStart"
|
||||
class="mr-4"
|
||||
placeholder="请输入打卡结束时间"
|
||||
value-format="HH:mm"
|
||||
start="00:00"
|
||||
step="00:15"
|
||||
end="23:59"
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12" :offset="0">
|
||||
<el-form-item label="打卡类型" prop="playCardStart" label-width="110px">
|
||||
<!-- <el-time-picker value-format="HH:mm" v-model="form.playCardStart" placeholder="请输入打卡开始时间" /> -->
|
||||
<el-time-select
|
||||
v-model="form.playCardStart"
|
||||
style="width: 100%"
|
||||
class="mr-4"
|
||||
placeholder="请输入打卡开始时间"
|
||||
value-format="HH:mm"
|
||||
start="00:00"
|
||||
step="00:15"
|
||||
end="23:59"
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12" :offset="0">
|
||||
<el-form-item label="工作日" prop="playCardEnd" label-width="110px">
|
||||
<!-- <el-time-picker value-format="HH:mm" v-model="form.playCardEnd" placeholder="请输入打卡结束时间" /> -->
|
||||
<el-time-select
|
||||
v-model="form.playCardEnd"
|
||||
style="width: 100%"
|
||||
:min-time="form.playCardStart"
|
||||
class="mr-4"
|
||||
placeholder="请输入打卡结束时间"
|
||||
value-format="HH:mm"
|
||||
start="00:00"
|
||||
step="00:15"
|
||||
end="23:59"
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<!-- <el-col :span="24" :offset="0">
|
||||
<el-form-item label="安全协议书" prop="securityAgreement">
|
||||
<file-upload v-model="form.securityAgreement" :limit="1" :file-type="['pdf']" :file-size="50" />
|
||||
</el-form-item>
|
||||
</el-col> -->
|
||||
</el-row>
|
||||
</div>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<div class="dialog-footer">
|
||||
@ -342,13 +272,12 @@
|
||||
</div>
|
||||
</template>
|
||||
</el-dialog>
|
||||
|
||||
<!-- //选取项目地址弹窗 -->
|
||||
<el-dialog v-model="amapStatus" :title="form.projectName + '-获取经纬度'" width="80%">
|
||||
<el-dialog draggable v-model="amapStatus" :title="form.projectName + '-获取经纬度'" width="80%">
|
||||
<amap height="620px" @setLocation="setPoi"></amap>
|
||||
</el-dialog>
|
||||
<!-- 选取方阵地址 -->
|
||||
<el-dialog title="设置方阵" v-model="polygonStatus" width="1400px" :close-on-click-modal="false">
|
||||
<el-dialog draggable title="设置方阵" v-model="polygonStatus" width="1400px" :close-on-click-modal="false">
|
||||
<open-layers-map
|
||||
:project-id="projectId"
|
||||
:design-id="designId"
|
||||
@ -356,7 +285,7 @@
|
||||
@close="polygonStatus = false"
|
||||
></open-layers-map>
|
||||
</el-dialog>
|
||||
<el-dialog title="添加子项目" v-model="childProjectStatus" width="400">
|
||||
<el-dialog draggable title="添加子项目" v-model="childProjectStatus" width="400">
|
||||
<span>填写子项目名称</span>
|
||||
<el-input v-model="childProjectForm.projectName"></el-input>
|
||||
<template #footer>
|
||||
@ -366,7 +295,7 @@
|
||||
</span>
|
||||
</template>
|
||||
</el-dialog>
|
||||
<el-dialog title="上传文件" v-model="fileVisble" width="400">
|
||||
<el-dialog draggable title="上传文件" v-model="fileVisble" width="400">
|
||||
<file-upload v-model="fileForm.tenderFiles" :limit="10" :file-type="['pdf']" :file-size="50" />
|
||||
<template #footer>
|
||||
<div class="dialog-footer">
|
||||
@ -375,6 +304,91 @@
|
||||
</div>
|
||||
</template>
|
||||
</el-dialog>
|
||||
<el-dialog draggable title="打卡规则" v-model="ruleFlag" width="800">
|
||||
<template #footer>
|
||||
<el-form ref="projectFormRef" :model="form" :rules="rules" label-width="100px">
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="12" :offset="0">
|
||||
<el-form-item label="上班时间" prop="clockInTime">
|
||||
<el-time-select
|
||||
v-model="form.clockInTime"
|
||||
style="width: 100%"
|
||||
class="mr-4"
|
||||
placeholder="请输入打卡开始时间"
|
||||
value-format="HH:mm"
|
||||
start="00:00"
|
||||
step="00:15"
|
||||
end="23:59"
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12" :offset="0">
|
||||
<el-form-item label="下班时间" prop="clockOutTime">
|
||||
<el-time-select
|
||||
v-model="form.clockOutTime"
|
||||
style="width: 100%"
|
||||
:min-time="form.clockInTime"
|
||||
class="mr-4"
|
||||
placeholder="请输入打卡结束时间"
|
||||
value-format="HH:mm"
|
||||
start="00:00"
|
||||
step="00:15"
|
||||
end="23:59"
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="24" :offset="0">
|
||||
<el-form-item label="打卡类型" prop="type">
|
||||
<el-radio-group v-model="form.type">
|
||||
<el-radio value="1" size="large">无限制</el-radio>
|
||||
<el-radio value="2" size="large">范围内打卡</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="24">
|
||||
<el-form-item label="打卡类型" prop="weekday">
|
||||
<el-checkbox-group v-model="form.weekday" size="small">
|
||||
<el-checkbox label="星期一" value="1" />
|
||||
<el-checkbox label="星期二" value="2" />
|
||||
<el-checkbox label="星期三" value="3" />
|
||||
<el-checkbox label="星期四" value="4" />
|
||||
<el-checkbox label="星期五" value="5" />
|
||||
<el-checkbox label="星期六" value="6" />
|
||||
<el-checkbox label="星期日" value="7" />
|
||||
</el-checkbox-group>
|
||||
</el-form-item>
|
||||
</el-col> </el-row
|
||||
></el-form>
|
||||
<div class="dialog-footer">
|
||||
<el-button type="primary" @click="ruleSubmit"> 提交</el-button>
|
||||
<el-button @click="ruleFlag = false">取消</el-button>
|
||||
</div>
|
||||
</template>
|
||||
</el-dialog>
|
||||
<el-dialog draggable title="打卡范围" v-model="ScopeFlag" width="600">
|
||||
<div v-for="(item, i) of punchRangeList" :key="i" class="options_item">
|
||||
<el-row style="margin-bottom: 10px;">
|
||||
<el-col :span="1"> <el-color-picker v-model="item.punchColor" show-alpha /></el-col>
|
||||
<el-col :span="12"> <el-input v-model="item.punchName" placeholder="请输入打卡范围名称" class="ml-8" /></el-col>
|
||||
<el-col :span="10" style="text-align: right; margin-top: 5px">
|
||||
<el-button v-if="item.id" link type="primary" icon="view" @click="previewPunchRange(item)">预览</el-button>
|
||||
<el-button v-if="item.id" link type="primary" icon="delete" @click="handleScopeDel(item)">移除</el-button>
|
||||
<el-button v-if="!item.id" link type="primary" icon="plus" @click="addPunchRange(item)">添加</el-button>
|
||||
<el-button v-if="item.id" link type="primary" icon="download" @click="handleScopeEdit(item)">保存</el-button>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</div>
|
||||
<template #footer>
|
||||
<div class="dialog-footer">
|
||||
<el-button type="primary" @click="scopeSubmit">确定</el-button>
|
||||
<el-button @click="ScopeFlag = false">取消</el-button>
|
||||
</div>
|
||||
</template>
|
||||
</el-dialog>
|
||||
<CesiumEarthDialog ref="earthDialog" @send-data="handleEarthData"
|
||||
:position="position"
|
||||
:data="earthData"
|
||||
@close="handleEarthClose"></CesiumEarthDialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@ -382,17 +396,24 @@
|
||||
import {
|
||||
addChildProject,
|
||||
addProject,
|
||||
addProjectFacilities,
|
||||
addProjectPilePoint,
|
||||
addProjectSquare,
|
||||
delProject,
|
||||
uploadProjectFile,
|
||||
getProject,
|
||||
listProject,
|
||||
updateProject
|
||||
updateProject,
|
||||
attendanceRuleAdd,
|
||||
attendanceRuleEdit,
|
||||
byProjectIdDetail,
|
||||
getAttendanceRangeList,
|
||||
updateAttendanceRange,
|
||||
delAttendanceRange
|
||||
} from '@/api/project/project';
|
||||
import { ProjectForm, ProjectQuery, ProjectVO, childProjectQuery, locationType } from '@/api/project/project/types';
|
||||
import amap from '@/components/amap/index.vue';
|
||||
import CesiumEarthDialog from "./map.vue"
|
||||
import { useUserStoreHook } from '@/store/modules/user';
|
||||
const userStore = useUserStoreHook();
|
||||
const currentProject = computed(() => userStore.selectedProject);
|
||||
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
||||
const { sys_normal_disable, project_category_type, project_type, project_stage } = toRefs<any>(
|
||||
proxy?.useDict('sys_normal_disable', 'project_category_type', 'project_type', 'project_stage')
|
||||
@ -413,6 +434,22 @@ const polygonStatus = ref(false);
|
||||
const dxfFile = ref(null);
|
||||
const projectId = ref<string>('');
|
||||
const designId = ref<string>('');
|
||||
const ruleFlag = ref(false);
|
||||
const ScopeFlag = ref(false);
|
||||
const earthDialog = ref(null);
|
||||
const position = ref(''); //预览
|
||||
let earthData = reactive({
|
||||
projectId: '',
|
||||
punchName: '',
|
||||
punchColor: '#1983ff',
|
||||
punchRange: '',
|
||||
}); //传值给地图组件
|
||||
const punchRangeList = ref<any>([
|
||||
{
|
||||
punchName: '',
|
||||
punchColor: '#1983ff'
|
||||
}
|
||||
]);
|
||||
const childProjectForm = reactive<childProjectQuery>({
|
||||
projectName: '',
|
||||
pid: '',
|
||||
@ -432,7 +469,7 @@ const fileForm = ref({
|
||||
const jsonData = ref(null);
|
||||
const fullscreenLoading = ref(false);
|
||||
|
||||
const initFormData: ProjectForm = {
|
||||
const initFormData = {
|
||||
id: undefined,
|
||||
projectName: undefined,
|
||||
shortName: undefined,
|
||||
@ -451,13 +488,15 @@ const initFormData: ProjectForm = {
|
||||
lat: undefined,
|
||||
plan: undefined,
|
||||
onStreamTime: undefined,
|
||||
playCardStart: undefined,
|
||||
playCardEnd: undefined,
|
||||
clockInTime: undefined,
|
||||
clockOutTime: undefined,
|
||||
designTotal: undefined,
|
||||
securityAgreement: undefined,
|
||||
sort: 0,
|
||||
showHidden: undefined,
|
||||
isDelete: undefined
|
||||
isDelete: undefined,
|
||||
type: '1',
|
||||
weekday: []
|
||||
};
|
||||
const data = reactive<PageData<ProjectForm, ProjectQuery>>({
|
||||
form: { ...initFormData },
|
||||
@ -480,8 +519,6 @@ const data = reactive<PageData<ProjectForm, ProjectQuery>>({
|
||||
lat: undefined,
|
||||
plan: undefined,
|
||||
onStreamTime: undefined,
|
||||
playCardStart: undefined,
|
||||
playCardEnd: undefined,
|
||||
designTotal: undefined,
|
||||
securityAgreement: undefined,
|
||||
sort: undefined,
|
||||
@ -490,8 +527,8 @@ const data = reactive<PageData<ProjectForm, ProjectQuery>>({
|
||||
params: {}
|
||||
},
|
||||
rules: {
|
||||
playCardStart: [{ required: true, message: '打卡开始时间不能为空', trigger: 'blur' }],
|
||||
playCardEnd: [{ required: true, message: '打卡结束时间不能为空', trigger: 'blur' }],
|
||||
clockInTime: [{ required: true, message: '打卡开始时间不能为空', trigger: 'blur' }],
|
||||
clockOutTime: [{ required: true, message: '打卡结束时间不能为空', trigger: 'blur' }],
|
||||
projectName: [{ required: true, message: '项目名称不能为空', trigger: 'blur' }],
|
||||
shortName: [{ required: true, message: '项目简称不能为空', trigger: 'blur' }],
|
||||
principalPhone: [{ required: true, message: '负责人电话不能为空', trigger: 'blur' }],
|
||||
@ -692,7 +729,86 @@ const handleSetChild = async () => {
|
||||
}
|
||||
}
|
||||
};
|
||||
const handleScope = (row) => {
|
||||
console.log('row',row);
|
||||
// 打卡范围
|
||||
ScopeFlag.value = true;
|
||||
projectId.value = row.id;
|
||||
// 获取打卡范围列表
|
||||
getListScope(row.id);
|
||||
};
|
||||
// 获取打卡范围列表
|
||||
const getListScope = (id) => {
|
||||
punchRangeList.value = [{
|
||||
punchName: '',
|
||||
punchColor: '#1983ff'
|
||||
}];
|
||||
getAttendanceRangeList({ projectId: id, }).then((res) => {
|
||||
if (res.code === 200) {
|
||||
punchRangeList.value.unshift(...res.rows);
|
||||
}
|
||||
});
|
||||
}
|
||||
// 修改打卡范围
|
||||
const handleScopeEdit = (row) => {
|
||||
updateAttendanceRange(row).then((res) => {
|
||||
if (res.code === 200) {
|
||||
proxy.$modal.msgSuccess('修改成功');
|
||||
// ScopeFlag.value = false;
|
||||
getListScope(projectId.value);
|
||||
}
|
||||
});
|
||||
}
|
||||
// 删除打卡范围
|
||||
const handleScopeDel = (row) => {
|
||||
proxy.$modal.confirm('是否确认删除打卡范围?').then(() => {
|
||||
delAttendanceRange(row.id).then((res) => {
|
||||
if (res.code === 200) {
|
||||
proxy.$modal.msgSuccess('删除成功');
|
||||
getListScope(projectId.value);
|
||||
}
|
||||
});
|
||||
}).catch(() => {});
|
||||
}
|
||||
|
||||
|
||||
const scopeSubmit = () => {
|
||||
// 提交打卡范围
|
||||
};
|
||||
// 添加规则
|
||||
const handleCheckRules = async (row?: ProjectVO) => {
|
||||
reset();
|
||||
const _id = row?.id || ids.value[0];
|
||||
const res = await byProjectIdDetail(_id);
|
||||
if (res.data) {
|
||||
res.data.weekday = res.data.weekday.split(',');
|
||||
Object.assign(form.value, res.data);
|
||||
}
|
||||
projectId.value = row.id;
|
||||
ruleFlag.value = true;
|
||||
};
|
||||
const ruleSubmit = async () => {
|
||||
console.log(form.value);
|
||||
projectFormRef.value?.validate(async (valid: boolean) => {
|
||||
if (valid) {
|
||||
let obj = {
|
||||
weekday: form.value.weekday.join(','),
|
||||
projectId: projectId.value,
|
||||
id: projectId.value,
|
||||
clockInTime: form.value.clockInTime,
|
||||
clockOutTime: form.value.clockOutTime,
|
||||
type: form.value.type
|
||||
};
|
||||
if (form.value.id) {
|
||||
await attendanceRuleEdit(obj);
|
||||
} else {
|
||||
await attendanceRuleAdd(obj);
|
||||
}
|
||||
ruleFlag.value = false;
|
||||
await getList();
|
||||
}
|
||||
});
|
||||
};
|
||||
/** 导出按钮操作 */
|
||||
const handleExport = () => {
|
||||
proxy?.download(
|
||||
@ -703,7 +819,36 @@ const handleExport = () => {
|
||||
`project_${new Date().getTime()}.xlsx`
|
||||
);
|
||||
};
|
||||
|
||||
// 打开绘制范围
|
||||
const addPunchRange = (item) => {
|
||||
earthData.punchName = item.punchName
|
||||
earthData.punchColor = item.punchColor
|
||||
earthData.projectId = projectId.value
|
||||
earthData.id = ''
|
||||
earthData.punchRange = ''
|
||||
if (earthData.punchName=='') {
|
||||
proxy.$modal.msgError('请先填写打卡范围名称');
|
||||
return
|
||||
}
|
||||
earthDialog.value.show()
|
||||
}
|
||||
// 接受绘制范围
|
||||
const handleEarthData = (data) => {
|
||||
ScopeFlag.value = false;
|
||||
}
|
||||
// 关闭绘制范围
|
||||
const handleEarthClose = () => {
|
||||
earthDialog.value.show = false
|
||||
}
|
||||
// 预览范围
|
||||
const previewPunchRange = (item)=>{
|
||||
earthData.id = item.id
|
||||
earthData.projectId = item.projectId
|
||||
earthData.punchName = item.punchName
|
||||
earthData.punchColor = item.punchColor
|
||||
earthData.punchRange = item.punchRange
|
||||
earthDialog.value.show()
|
||||
}
|
||||
onMounted(() => {
|
||||
getList();
|
||||
});
|
||||
|
||||
305
src/views/project/project/map.vue
Normal file
305
src/views/project/project/map.vue
Normal file
@ -0,0 +1,305 @@
|
||||
<template>
|
||||
<el-dialog v-model="visible" title="地球可视化" :width="dialogWidth" :height="dialogHeight" :before-close="handleClose"
|
||||
destroy-on-close>
|
||||
<div v-loading="loading" id="earthMap" class="earth-container"></div>
|
||||
<template #footer>
|
||||
<el-button type="warning" @click="redraw">重新绘制</el-button>
|
||||
<el-button v-if="isDraw" type="success" @click="drawRange">绘制</el-button>
|
||||
<el-button type="primary" @click="handlesubmit">确定</el-button>
|
||||
<el-button type="danger" @click="handleClose">关闭</el-button>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, onMounted, watch, defineEmits, defineProps,onUnmounted } from 'vue';
|
||||
import { ElMessage } from 'element-plus';
|
||||
import {
|
||||
addAttendanceRange,
|
||||
updateAttendanceRange,
|
||||
} from '@/api/project/project';
|
||||
const emit = defineEmits(['send-data', 'close']);
|
||||
const props = defineProps({
|
||||
position: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
data: {
|
||||
type: Object,
|
||||
default: () => { }
|
||||
}
|
||||
});
|
||||
// 弹窗控制变量
|
||||
const visible = ref(false);
|
||||
const dialogWidth = ref('90%');
|
||||
const dialogHeight = ref('90%');
|
||||
let earthInstance = null;
|
||||
let earthContainer = ref(null);
|
||||
let loading = ref(true);
|
||||
let positions = ref([]);
|
||||
const entityObject = ref(null);
|
||||
const isDraw = ref(true);
|
||||
// 显示弹窗
|
||||
const show = () => {
|
||||
visible.value = true;
|
||||
console.log(props.data);
|
||||
if (props.data?.id) {
|
||||
console.log(231, props.data);
|
||||
isDraw.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
// 关闭弹窗
|
||||
const handleClose = () => {
|
||||
visible.value = false;
|
||||
// 清除地球实例
|
||||
if (earthInstance && earthInstance.destroy) {
|
||||
earthInstance.destroy();
|
||||
earthInstance = null;
|
||||
}
|
||||
// 清除全局变量引用
|
||||
if (window.Earth2) {
|
||||
delete window.Earth2;
|
||||
}
|
||||
};
|
||||
|
||||
// 监听弹窗显示状态,初始化地球
|
||||
watch(
|
||||
() => visible.value,
|
||||
(newVal) => {
|
||||
if (newVal && earthContainer.value) {
|
||||
createEarth();
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
// 创建地球
|
||||
const createEarth = () => {
|
||||
if (!window.YJ) {
|
||||
ElMessage.error('YJ库未加载,请检查依赖');
|
||||
return;
|
||||
}
|
||||
|
||||
window.YJ.on({
|
||||
ws: true,
|
||||
// host: getIP(), // 资源所在服务器地址
|
||||
// username: this.loginForm.username, // 用户名
|
||||
// password: md5pass, // 密码
|
||||
}).then((res) => {
|
||||
if (!earthContainer.value) return;
|
||||
loading.value = false;
|
||||
// 创建地球实例
|
||||
earthInstance = new YJ.YJEarth(earthContainer.value);
|
||||
window.Earth2 = earthInstance;
|
||||
|
||||
// 开启右键和左键点击事件
|
||||
YJ.Global.openRightClick(window.Earth2);
|
||||
YJ.Global.openLeftClick(window.Earth2);
|
||||
|
||||
// 设置初始视角
|
||||
const view = {
|
||||
position: {
|
||||
lng: 102.03643298211526,
|
||||
lat: 34.393586474501,
|
||||
alt: 11298179.51993155
|
||||
},
|
||||
orientation: {
|
||||
heading: 360,
|
||||
pitch: -89.94481747201486,
|
||||
roll: 0
|
||||
}
|
||||
};
|
||||
|
||||
YJ.Global.CesiumContainer(window.Earth2, {
|
||||
compass: false, //罗盘
|
||||
});
|
||||
// 加载底图
|
||||
loadBaseMap(earthInstance.viewer);
|
||||
|
||||
// 可以取消注释以下代码来设置初始视角
|
||||
// YJ.Global.flyTo(earthInstance, view);
|
||||
// YJ.Global.setDefaultView(earthInstance.viewer, view)
|
||||
if (props.data.punchRange) {
|
||||
renderRange(JSON.parse(props.data.punchRange));
|
||||
}
|
||||
})
|
||||
.catch((err) => {
|
||||
console.error('初始化地球失败:', err);
|
||||
ElMessage.error('初始化地球失败,请稍后重试');
|
||||
});
|
||||
};
|
||||
|
||||
// 加载底图
|
||||
const loadBaseMap = (viewer) => {
|
||||
if (!viewer || !Cesium) {
|
||||
ElMessage.error('Cesium库未加载,请检查依赖');
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
// 创建瓦片提供器
|
||||
const imageryProvider = new Cesium.UrlTemplateImageryProvider({
|
||||
url: 'https://webst01.is.autonavi.com/appmaptile?style=6&x={x}&y={y}&z={z}',
|
||||
fileExtension: 'png',
|
||||
minimumLevel: 0,
|
||||
maximumLevel: 18,
|
||||
projection: Cesium.WebMercatorProjection,
|
||||
credit: new Cesium.Credit('卫星图数据来源')
|
||||
});
|
||||
|
||||
// 添加图层到视图
|
||||
viewer.imageryLayers.addImageryProvider(imageryProvider);
|
||||
} catch (err) {
|
||||
console.error('加载底图失败:', err);
|
||||
ElMessage.error('加载底图失败');
|
||||
}
|
||||
};
|
||||
// 处理数据传递
|
||||
const handlesubmit = () => {
|
||||
if (!earthInstance || !earthInstance.viewer) {
|
||||
ElMessage.warning('地球实例未初始化,无法获取数据');
|
||||
return;
|
||||
}
|
||||
// 要传递的对象数据
|
||||
const dataToSend = {
|
||||
...props.data,
|
||||
punchRange: JSON.stringify(positions.value),
|
||||
};
|
||||
if (props.data.id) {
|
||||
updateAttendanceRange1(dataToSend)
|
||||
} else {
|
||||
addAttendanceRange1(dataToSend);
|
||||
}
|
||||
emit('send-data', dataToSend);
|
||||
};
|
||||
// 新增打卡范围接口
|
||||
const addAttendanceRange1 = (data) => {
|
||||
addAttendanceRange(data).then((res) => {
|
||||
if (res.code === 200) {
|
||||
ElMessage.success('新增打卡范围成功');
|
||||
handleClose();
|
||||
} else {
|
||||
ElMessage.error(res.msg);
|
||||
}
|
||||
}).catch((err) => {
|
||||
console.error('新增打卡范围失败:', err);
|
||||
ElMessage.error('新增打卡范围失败');
|
||||
});
|
||||
};
|
||||
// 修改打卡范围接口
|
||||
const updateAttendanceRange1 = (data) => {
|
||||
updateAttendanceRange(data).then((res) => {
|
||||
if (res.code === 200) {
|
||||
ElMessage.success('修改打卡范围成功');
|
||||
handleClose();
|
||||
} else {
|
||||
ElMessage.error(res.msg);
|
||||
}
|
||||
}).catch((err) => {
|
||||
console.error('修改打卡范围失败:', err);
|
||||
ElMessage.error('修改打卡范围失败');
|
||||
});
|
||||
};
|
||||
// 绘制范围
|
||||
const drawRange = () => {
|
||||
if (!earthInstance || !earthInstance.viewer) {
|
||||
ElMessage.warning('地球实例未初始化,无法绘制');
|
||||
return;
|
||||
}
|
||||
let draw = new YJ.Draw.DrawPolygon(window.Earth2);
|
||||
draw.start((err, params) => {
|
||||
if (err) {
|
||||
console.error('绘制失败:', err);
|
||||
ElMessage.error('绘制失败');
|
||||
return;
|
||||
}
|
||||
console.log('绘制成功:', params);
|
||||
positions.value = params;
|
||||
renderRange(params);
|
||||
});
|
||||
}
|
||||
// 渲染范围
|
||||
const renderRange = (params) => {
|
||||
let option = {
|
||||
id: 'Checkinrange',
|
||||
info: {
|
||||
type: "richText",
|
||||
text: "",
|
||||
hrefs: "",
|
||||
},
|
||||
positions: params,
|
||||
color: props.data.punchColor || "rgba(255,0,0,0.5)",
|
||||
line: {
|
||||
width: 3,
|
||||
color: "rgba(255,0,0,1)",
|
||||
},
|
||||
type: 0,
|
||||
show: true,
|
||||
}
|
||||
// PolygonObject
|
||||
let entity = new YJ.Obj.PolygonObject(
|
||||
window.Earth2,
|
||||
option
|
||||
);
|
||||
entity.flyTo();
|
||||
entityObject.value = entity
|
||||
}
|
||||
|
||||
|
||||
// 重新绘制
|
||||
const redraw = () => {
|
||||
if (entityObject.value) {
|
||||
entityObject.value.remove();
|
||||
}
|
||||
drawRange();
|
||||
}
|
||||
|
||||
// 组件挂载时设置容器ID
|
||||
onMounted(() => {
|
||||
if (!earthContainer.value) {
|
||||
earthContainer.value = 'earthMap'; // 设置与初始化代码中相同的ID
|
||||
}
|
||||
});
|
||||
|
||||
// 暴露显示方法给父组件
|
||||
defineExpose({
|
||||
show
|
||||
});
|
||||
|
||||
//
|
||||
onUnmounted(() => {
|
||||
if (earthInstance) {
|
||||
earthInstance.destroy();
|
||||
earthInstance = null;
|
||||
window.Earth2 = null;
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.earth-container {
|
||||
width: 100%;
|
||||
height: 600px;
|
||||
overflow: hidden;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
:deep(.el-dialog__body) {
|
||||
padding: 10px;
|
||||
height: calc(100% - 100px);
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
:deep(.el-dialog) {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
max-height: 90vh;
|
||||
}
|
||||
|
||||
:deep(.el-dialog__content) {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
overflow: hidden;
|
||||
}
|
||||
</style>
|
||||
@ -80,6 +80,11 @@
|
||||
<el-option v-for="item in team_clock_type" :key="item.value" :label="item.label" :value="item.value" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="打卡范围" prop="punchRangeList" v-if="form.isClockIn == 1">
|
||||
<el-select v-model="form.punchRangeList" multiple clearable placeholder="请选择打卡范围">
|
||||
<el-option v-for="item in projectTeamRangeList" :key="item.id" :label="item.punchName" :value="item.id" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="备注" prop="remark">
|
||||
<el-input v-model="form.remark" type="textarea" placeholder="请输入内容" />
|
||||
</el-form-item>
|
||||
@ -98,13 +103,15 @@
|
||||
</template>
|
||||
|
||||
<script setup name="ProjectTeam" lang="ts">
|
||||
import { addProjectTeam, delProjectTeam, getProjectTeam, listProjectTeam, updateProjectTeam } from '@/api/project/projectTeam';
|
||||
import { addProjectTeam, delProjectTeam, getProjectTeam, listProjectTeam, updateProjectTeam,getProjectTeamClockIn } from '@/api/project/projectTeam';
|
||||
import { ProjectTeamForm, ProjectTeamQuery, ProjectTeamVO } from '@/api/project/projectTeam/types';
|
||||
import { useUserStoreHook } from '@/store/modules/user';
|
||||
import UserListDialog from '@/views/project/projectTeam/component/UserListDialog.vue';
|
||||
|
||||
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
||||
const { team_clock_type } = toRefs<any>(proxy?.useDict('team_clock_type'));
|
||||
console.log(team_clock_type);
|
||||
|
||||
// 获取用户 store
|
||||
const userStore = useUserStoreHook();
|
||||
// 从 store 中获取项目列表和当前选中的项目
|
||||
@ -117,6 +124,7 @@ const ids = ref<Array<string | number>>([]);
|
||||
const single = ref(true);
|
||||
const multiple = ref(true);
|
||||
const total = ref(0);
|
||||
const projectTeamRangeList = ref([]);
|
||||
const currentRow = ref<ProjectTeamVO>({
|
||||
id: undefined,
|
||||
projectId: undefined,
|
||||
@ -140,7 +148,8 @@ const initFormData: ProjectTeamForm = {
|
||||
teamName: undefined,
|
||||
isClockIn: undefined,
|
||||
remark: undefined,
|
||||
peopleNumber: undefined
|
||||
peopleNumber: undefined,
|
||||
punchRangeList: undefined
|
||||
};
|
||||
const data = reactive<PageData<ProjectTeamForm, ProjectTeamQuery>>({
|
||||
form: { ...initFormData },
|
||||
@ -171,6 +180,14 @@ const getList = async () => {
|
||||
total.value = res.total;
|
||||
loading.value = false;
|
||||
};
|
||||
/** 获取该项目的打开范围 "*/
|
||||
const getClockIn = async () => {
|
||||
if(currentProject.value?.id){
|
||||
const res = await getProjectTeamClockIn({projectId:currentProject.value?.id});
|
||||
projectTeamRangeList.value = res.rows
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/** 取消按钮 */
|
||||
const cancel = () => {
|
||||
@ -280,5 +297,6 @@ onUnmounted(() => {
|
||||
|
||||
onMounted(() => {
|
||||
getList();
|
||||
getClockIn();
|
||||
});
|
||||
</script>
|
||||
|
||||
@ -5,6 +5,11 @@
|
||||
<div v-show="showSearch" class="mb-[10px]">
|
||||
<el-card shadow="hover">
|
||||
<el-form ref="queryFormRef" :model="queryParams" :inline="true">
|
||||
<el-form-item label="项目名称" prop="projectId">
|
||||
<el-select v-model="queryParams.projectId" clearable placeholder="全部">
|
||||
<el-option v-for="item in projectList" :key="item.value" :label="item.projectName" :value="item.id" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="人员姓名" prop="userName">
|
||||
<el-input v-model="queryParams.userName" placeholder="请输入人员姓名" clearable @keyup.enter="handleQuery" />
|
||||
</el-form-item>
|
||||
@ -156,6 +161,7 @@
|
||||
</el-button>
|
||||
<!-- <el-button link type="primary" icon="Switch" @click="handleToggle(scope.row)"> 切换人脸 </el-button> -->
|
||||
<el-button link type="primary" icon="Switch" @click="handleChange(scope.row)"> 人员迁移 </el-button>
|
||||
<el-button link type="primary" icon="Switch" @click="handleAssign(scope.row)"> 分配班组 </el-button>
|
||||
<el-button link type="primary" icon="ChatLineSquare" @click="handleExit(scope.row)"> 入退场记录 </el-button>
|
||||
<el-button link type="danger" icon="Delete" @click="handleDelete(scope.row)"
|
||||
v-hasPermi="['contractor:constructionUser:remove']">
|
||||
@ -443,6 +449,30 @@
|
||||
</template>
|
||||
</el-calendar>
|
||||
</el-dialog>
|
||||
<el-dialog draggable :title="skipName + '-人员分配'" v-model="personnelAllocation" width="500px">
|
||||
<el-form-item label="所属项目" label-width="130px">
|
||||
<el-select v-model="personnelAllocationObject.projectId" @change="selectProject1" placeholder="请选择所属项目" style="width: 240px">
|
||||
<el-option v-for="item in projectList" :key="item.id" :label="item.projectName" :value="item.id" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="岗位" label-width="130px">
|
||||
<el-select v-model="personnelAllocationObject.postId" placeholder="请选择岗位" style="width: 240px">
|
||||
<el-option v-for="item in user_post_type" :key="item.value" :label="item.label" :value="item.value" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="班组" label-width="130px">
|
||||
<el-select v-model="personnelAllocationObject.teamId" :disabled="!personnelAllocationObject.projectId" placeholder="请选择分包单位"
|
||||
style="width: 240px">
|
||||
<el-option v-for="item in teamList" :key="item.id" :label="item.teamName" :value="item.id" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<template #footer>
|
||||
<div class="dialog-footer">
|
||||
<el-button type="primary" @click="handlePersonnelAllocation">确认</el-button>
|
||||
<el-button @click="personnelAllocation = false"> 取消 </el-button>
|
||||
</div>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@ -462,7 +492,10 @@ import {
|
||||
getConstructionUserExit,
|
||||
dowloadConstructionUserTemplate,
|
||||
importConstructionUserInfo,
|
||||
listConstructionMonth
|
||||
listConstructionMonth,
|
||||
ProjectList,
|
||||
TeamList,
|
||||
TeamDistribution
|
||||
} from '@/api/project/constructionUser';
|
||||
import {
|
||||
ConstructionUserForm,
|
||||
@ -494,8 +527,8 @@ import { parseTime } from '@/utils/ruoyi';
|
||||
|
||||
const calendar = ref<CalendarInstance>();
|
||||
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
||||
const { type_of_work, user_sex_type, user_clock_type, user_file_type, user_status_type, wage_measure_unit_type } = toRefs<any>(
|
||||
proxy?.useDict('type_of_work', 'user_sex_type', 'user_clock_type', 'user_file_type', 'user_status_type', 'wage_measure_unit_type')
|
||||
const { type_of_work, user_sex_type, user_clock_type, user_file_type, user_status_type, wage_measure_unit_type,user_post_type } = toRefs<any>(
|
||||
proxy?.useDict('type_of_work', 'user_sex_type', 'user_clock_type', 'user_file_type', 'user_status_type', 'wage_measure_unit_type','user_post_type')
|
||||
);
|
||||
// 获取用户 store
|
||||
const userStore = useUserStoreHook();
|
||||
@ -511,6 +544,7 @@ const single = ref(true);
|
||||
const multiple = ref(true);
|
||||
const total = ref(0);
|
||||
const skip = ref(false);
|
||||
const personnelAllocation = ref(false);
|
||||
const fileStatus = ref(false);
|
||||
const showFaceDrawer = ref(false);
|
||||
const statusDialog = ref(false);
|
||||
@ -531,6 +565,10 @@ const queryFormRef = ref<ElFormInstance>();
|
||||
const constructionUserFormRef = ref<ElFormInstance>();
|
||||
const skipName = ref('');
|
||||
const calendarList = ref<Array<AttendanceMonthVO>>([]);
|
||||
// 项目列表
|
||||
const projectList = ref([]);
|
||||
// 班组列表
|
||||
const teamList = ref([]);
|
||||
const dialog = reactive<DialogOption>({
|
||||
visible: false,
|
||||
title: '',
|
||||
@ -543,6 +581,14 @@ const skipObject: skipType = reactive({
|
||||
projectId: '',
|
||||
contractorId: ''
|
||||
});
|
||||
// 人员分配
|
||||
const personnelAllocationObject = reactive({
|
||||
memberId: null,
|
||||
projectId: '',
|
||||
teamId: '',
|
||||
postId: '',
|
||||
});
|
||||
|
||||
const contractorList = ref<Array<skipTeamType>>([]);
|
||||
//项目列表
|
||||
const skipOptions = ref<Array<skipOptionType>>([]);
|
||||
@ -661,6 +707,13 @@ const uploadPath = computed(() => {
|
||||
return list;
|
||||
});
|
||||
|
||||
// 获取项目列表
|
||||
const getProjectList = async () => {
|
||||
const res = await ProjectList({});
|
||||
projectList.value = res.rows;
|
||||
projectList.value.unshift({ id: '', projectName: '全部' });
|
||||
};
|
||||
|
||||
/** 返回文件上传状态 */
|
||||
const uploadStatusColor = computed(() => (str: string) => {
|
||||
switch (str) {
|
||||
@ -825,7 +878,7 @@ const reset = () => {
|
||||
/** 搜索按钮操作 */
|
||||
const handleQuery = () => {
|
||||
queryParams.value.pageNum = 1;
|
||||
if (contractorOpt.value.length == 1) queryParams.value.contractorId = contractorOpt.value[0].value;
|
||||
// if (contractorOpt.value.length == 1) queryParams.value.contractorId = contractorOpt.value[0].value;
|
||||
getList();
|
||||
};
|
||||
|
||||
@ -1053,6 +1106,36 @@ const listeningProject = watch(
|
||||
getContractorList();
|
||||
}
|
||||
);
|
||||
// 分配班组
|
||||
const handleAssign = async (row: ConstructionUserVO) => {
|
||||
const _id = row?.id || ids.value[0];
|
||||
currentUserId.value = _id;
|
||||
personnelAllocationObject.memberId = row?.sysUserId;
|
||||
personnelAllocation.value = true;
|
||||
};
|
||||
// 选择项目1
|
||||
const selectProject1 = (e: any) => {
|
||||
// 请求班组
|
||||
getTeamList(personnelAllocationObject.projectId);
|
||||
|
||||
};
|
||||
const getTeamList = async (projectId) => {
|
||||
const res = await TeamList({
|
||||
projectId,
|
||||
pageNum: 1,
|
||||
pageSize: 100
|
||||
});
|
||||
teamList.value = res.rows;
|
||||
};
|
||||
// 人员分配
|
||||
const handlePersonnelAllocation = async () => {
|
||||
let res = await TeamDistribution(personnelAllocationObject);
|
||||
if (res.code == 200) {
|
||||
ElMessage.success(res.msg);
|
||||
personnelAllocation.value = false;
|
||||
getList();
|
||||
}
|
||||
};
|
||||
|
||||
onUnmounted(() => {
|
||||
listeningProject();
|
||||
@ -1060,6 +1143,7 @@ onUnmounted(() => {
|
||||
|
||||
onMounted(() => {
|
||||
getContractorList();
|
||||
getProjectList();
|
||||
});
|
||||
</script>
|
||||
<style scoped lang="scss">
|
||||
|
||||
Reference in New Issue
Block a user