|
|
@@ -0,0 +1,943 @@
|
|
|
+<script setup>
|
|
|
+import {
|
|
|
+ computed,
|
|
|
+ nextTick,
|
|
|
+ onMounted,
|
|
|
+ ref,
|
|
|
+ reactive,
|
|
|
+ defineExpose,
|
|
|
+ watch,
|
|
|
+} from "vue";
|
|
|
+import { useDataDictStore } from "@/store/modules/dataDict";
|
|
|
+import {
|
|
|
+ selectedDeptsEmployee,
|
|
|
+ getRuiHenProjectInfoPage,
|
|
|
+ getDevicesByDepts,
|
|
|
+ getRuiHenTaskDetail1,
|
|
|
+} from "@/api/ruihen";
|
|
|
+import { specifiedSimpleDepts } from "@/api";
|
|
|
+import { getDeptId } from "@/utils/auth";
|
|
|
+import DaTree from "@/components/da-tree/index.vue";
|
|
|
+
|
|
|
+const props = defineProps({
|
|
|
+ type: {
|
|
|
+ type: String,
|
|
|
+ default: "create",
|
|
|
+ },
|
|
|
+ id: {
|
|
|
+ type: Number,
|
|
|
+ default: null,
|
|
|
+ },
|
|
|
+});
|
|
|
+
|
|
|
+const dictStore = useDataDictStore();
|
|
|
+
|
|
|
+const isReadonly = computed(() => props.type === "detail");
|
|
|
+
|
|
|
+const createInitialForm = () => ({
|
|
|
+ id: "",
|
|
|
+ projectId: undefined,
|
|
|
+ wellName: "",
|
|
|
+ location: "",
|
|
|
+ technique: undefined,
|
|
|
+ workloadDesign: undefined,
|
|
|
+ workloadUnit: undefined,
|
|
|
+ deptIds: [],
|
|
|
+ deviceIds: [],
|
|
|
+ responsiblePerson: undefined,
|
|
|
+ remark: "",
|
|
|
+});
|
|
|
+
|
|
|
+const formRef = ref(null);
|
|
|
+const form = ref(createInitialForm());
|
|
|
+
|
|
|
+const rules = reactive({
|
|
|
+ projectId: {
|
|
|
+ rules: [{ required: true, errorMessage: "请选择合同" }],
|
|
|
+ },
|
|
|
+ wellName: {
|
|
|
+ rules: [{ required: true, errorMessage: "请输入井号" }],
|
|
|
+ },
|
|
|
+ location: {
|
|
|
+ rules: [{ required: true, errorMessage: "请输入施工地点" }],
|
|
|
+ },
|
|
|
+ technique: {
|
|
|
+ rules: [{ required: true, errorMessage: "请选择施工工艺" }],
|
|
|
+ },
|
|
|
+ workloadDesign: {
|
|
|
+ rules: [{ required: true, errorMessage: "请输入设计工作量" }],
|
|
|
+ },
|
|
|
+ workloadUnit: {
|
|
|
+ rules: [{ required: true, errorMessage: "请选择工作量单位" }],
|
|
|
+ },
|
|
|
+ deptIds: {
|
|
|
+ rules: [{ required: true, errorMessage: "请选择施工队伍" }],
|
|
|
+ },
|
|
|
+ deviceIds: {
|
|
|
+ rules: [{ required: true, errorMessage: "请选择施工设备" }],
|
|
|
+ },
|
|
|
+ responsiblePerson: {
|
|
|
+ rules: [{ required: true, errorMessage: "请选择责任人" }],
|
|
|
+ },
|
|
|
+});
|
|
|
+
|
|
|
+const validate = async () => {
|
|
|
+ return await formRef.value?.validate();
|
|
|
+};
|
|
|
+
|
|
|
+const buildSubmitData = () => {
|
|
|
+ return {
|
|
|
+ ...(form.value.id ? { id: form.value.id } : {}),
|
|
|
+ projectId: form.value.projectId,
|
|
|
+ wellName: form.value.wellName,
|
|
|
+ location: form.value.location,
|
|
|
+ technique: form.value.technique,
|
|
|
+ workloadDesign: form.value.workloadDesign,
|
|
|
+ workloadUnit: form.value.workloadUnit,
|
|
|
+ deptIds: form.value.deptIds,
|
|
|
+ deviceIds: form.value.deviceIds,
|
|
|
+ responsiblePerson: [form.value.responsiblePerson],
|
|
|
+ remark: form.value.remark,
|
|
|
+ platformWell: "0",
|
|
|
+ };
|
|
|
+};
|
|
|
+
|
|
|
+const defaultProps = computed(() => (label) => ({
|
|
|
+ inputBorder: false,
|
|
|
+ clearable: false,
|
|
|
+ placeholder: isReadonly.value ? " " : `请输入${label}`,
|
|
|
+ style: {
|
|
|
+ "text-align": "right",
|
|
|
+ },
|
|
|
+ styles: {
|
|
|
+ disableColor: "#fff",
|
|
|
+ },
|
|
|
+}));
|
|
|
+
|
|
|
+const contractPopup = ref(null);
|
|
|
+const contractPaging = ref(null);
|
|
|
+const contractList = ref([]);
|
|
|
+const contractSearchValue = ref("");
|
|
|
+const contractTempProjectId = ref("");
|
|
|
+const selectedContractLabel = ref("");
|
|
|
+
|
|
|
+const contractSearchInputStyles = reactive({
|
|
|
+ backgroundColor: "#f5f5f5",
|
|
|
+ color: "#333",
|
|
|
+});
|
|
|
+
|
|
|
+const contractDisplayText = computed(() => {
|
|
|
+ if (!form.value.projectId) return "";
|
|
|
+
|
|
|
+ const currentContract = contractList.value.find(
|
|
|
+ (item) => String(item.id) === String(form.value.projectId)
|
|
|
+ );
|
|
|
+
|
|
|
+ return selectedContractLabel.value || currentContract?.contractName || "";
|
|
|
+});
|
|
|
+
|
|
|
+const syncSelectedContractLabel = (list = []) => {
|
|
|
+ if (!form.value.projectId) return;
|
|
|
+
|
|
|
+ const currentContract = list.find(
|
|
|
+ (item) => String(item.id) === String(form.value.projectId)
|
|
|
+ );
|
|
|
+
|
|
|
+ if (currentContract?.contractName) {
|
|
|
+ selectedContractLabel.value = currentContract.contractName;
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+const queryContractList = async (pageNo, pageSize) => {
|
|
|
+ try {
|
|
|
+ const res = await getRuiHenProjectInfoPage({
|
|
|
+ deptId: getDeptId(),
|
|
|
+ pageNo,
|
|
|
+ pageSize,
|
|
|
+ ...(contractSearchValue.value
|
|
|
+ ? { contractName: contractSearchValue.value }
|
|
|
+ : {}),
|
|
|
+ });
|
|
|
+
|
|
|
+ const list = res?.data?.list || [];
|
|
|
+ const total = res?.data?.total || 0;
|
|
|
+
|
|
|
+ syncSelectedContractLabel(list);
|
|
|
+ contractPaging.value?.completeByTotal(list, total);
|
|
|
+ } catch (error) {
|
|
|
+ contractPaging.value?.complete(false);
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+const searchContractList = () => {
|
|
|
+ contractPaging.value?.reload();
|
|
|
+};
|
|
|
+
|
|
|
+const openContractPopup = () => {
|
|
|
+ contractSearchValue.value = "";
|
|
|
+ contractTempProjectId.value = form.value.projectId
|
|
|
+ ? String(form.value.projectId)
|
|
|
+ : "";
|
|
|
+ contractPopup.value?.open();
|
|
|
+
|
|
|
+ nextTick(() => {
|
|
|
+ contractPaging.value?.reload();
|
|
|
+ });
|
|
|
+};
|
|
|
+
|
|
|
+const closeContractPopup = () => {
|
|
|
+ contractPopup.value?.close();
|
|
|
+};
|
|
|
+
|
|
|
+const handleContractRadioChange = (event) => {
|
|
|
+ contractTempProjectId.value = event.detail.value;
|
|
|
+};
|
|
|
+
|
|
|
+const handleContractRowClick = (item) => {
|
|
|
+ contractTempProjectId.value = String(item.id);
|
|
|
+};
|
|
|
+
|
|
|
+const handleContractConfirm = () => {
|
|
|
+ if (!contractTempProjectId.value) {
|
|
|
+ uni.showToast({
|
|
|
+ title: "请选择合同",
|
|
|
+ icon: "none",
|
|
|
+ });
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ const currentContract = contractList.value.find(
|
|
|
+ (item) => String(item.id) === contractTempProjectId.value
|
|
|
+ );
|
|
|
+ const fallbackProjectId = Number(contractTempProjectId.value);
|
|
|
+
|
|
|
+ form.value.projectId =
|
|
|
+ currentContract?.id ??
|
|
|
+ (Number.isNaN(fallbackProjectId)
|
|
|
+ ? contractTempProjectId.value
|
|
|
+ : fallbackProjectId);
|
|
|
+ selectedContractLabel.value =
|
|
|
+ currentContract?.contractName || selectedContractLabel.value;
|
|
|
+
|
|
|
+ closeContractPopup();
|
|
|
+};
|
|
|
+
|
|
|
+const techniqueOptions = ref([]);
|
|
|
+const workloadUnitOptions = ref([]);
|
|
|
+
|
|
|
+const loadDictOptions = async () => {
|
|
|
+ if (dictStore.dataDict.length <= 0) {
|
|
|
+ await dictStore.loadDataDictList();
|
|
|
+ }
|
|
|
+
|
|
|
+ techniqueOptions.value = dictStore
|
|
|
+ .getIntDictOptions("rq_iot_project_technology_rh")
|
|
|
+ .map((item) => ({
|
|
|
+ text: item.label,
|
|
|
+ value: item.value,
|
|
|
+ }));
|
|
|
+
|
|
|
+ workloadUnitOptions.value = dictStore
|
|
|
+ .getIntDictOptions("rq_iot_project_measure_unit")
|
|
|
+ .map((item) => ({
|
|
|
+ text: item.label,
|
|
|
+ value: item.value,
|
|
|
+ }));
|
|
|
+};
|
|
|
+
|
|
|
+const deptOptions = ref([]);
|
|
|
+const treeData = ref([]);
|
|
|
+const deptLoading = ref(false);
|
|
|
+
|
|
|
+const handleTree = (data, id, parentId, children) => {
|
|
|
+ if (!Array.isArray(data)) {
|
|
|
+ console.warn("data must be an array");
|
|
|
+ return [];
|
|
|
+ }
|
|
|
+ const config = {
|
|
|
+ id: id || "id",
|
|
|
+ parentId: parentId || "parentId",
|
|
|
+ childrenList: children || "children",
|
|
|
+ };
|
|
|
+
|
|
|
+ const childrenListMap = {};
|
|
|
+ const nodeIds = {};
|
|
|
+ const tree = [];
|
|
|
+
|
|
|
+ for (const d of data) {
|
|
|
+ const parentId = d[config.parentId];
|
|
|
+ if (childrenListMap[parentId] == null) {
|
|
|
+ childrenListMap[parentId] = [];
|
|
|
+ }
|
|
|
+ nodeIds[d[config.id]] = d;
|
|
|
+ childrenListMap[parentId].push(d);
|
|
|
+ }
|
|
|
+
|
|
|
+ for (const d of data) {
|
|
|
+ const parentId = d[config.parentId];
|
|
|
+ if (nodeIds[parentId] == null) {
|
|
|
+ tree.push(d);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ for (const t of tree) {
|
|
|
+ adaptToChildrenList(t);
|
|
|
+ }
|
|
|
+
|
|
|
+ function adaptToChildrenList(o) {
|
|
|
+ if (childrenListMap[o[config.id]] !== null) {
|
|
|
+ o[config.childrenList] = childrenListMap[o[config.id]];
|
|
|
+ }
|
|
|
+ if (o[config.childrenList]) {
|
|
|
+ for (const c of o[config.childrenList]) {
|
|
|
+ adaptToChildrenList(c);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return tree;
|
|
|
+};
|
|
|
+
|
|
|
+async function loadDeptOptions() {
|
|
|
+ deptLoading.value = true;
|
|
|
+ try {
|
|
|
+ function sortTreeBySort(treeNodes) {
|
|
|
+ if (!treeNodes || !Array.isArray(treeNodes)) return treeNodes;
|
|
|
+ const sortedNodes = [...treeNodes].sort((a, b) => {
|
|
|
+ const sortA = a.sort != null ? a.sort : 999999;
|
|
|
+ const sortB = b.sort != null ? b.sort : 999999;
|
|
|
+ return sortA - sortB;
|
|
|
+ });
|
|
|
+
|
|
|
+ sortedNodes.forEach((node) => {
|
|
|
+ node.disabled = node.type !== "3";
|
|
|
+ if (node.children && Array.isArray(node.children)) {
|
|
|
+ node.children = sortTreeBySort(node.children);
|
|
|
+ }
|
|
|
+ });
|
|
|
+ return sortedNodes;
|
|
|
+ }
|
|
|
+
|
|
|
+ const depts = await specifiedSimpleDepts(getDeptId());
|
|
|
+
|
|
|
+ deptOptions.value = depts.data.map((item) => ({
|
|
|
+ text: item.name,
|
|
|
+ value: item.id,
|
|
|
+ raw: item,
|
|
|
+ }));
|
|
|
+ treeData.value = sortTreeBySort(handleTree(depts.data));
|
|
|
+ } catch (error) {
|
|
|
+ } finally {
|
|
|
+ deptLoading.value = false;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+const popup = ref();
|
|
|
+
|
|
|
+const openPopup = () => {
|
|
|
+ popup.value.open();
|
|
|
+};
|
|
|
+
|
|
|
+const selectDeptId = ref("");
|
|
|
+
|
|
|
+function handleTreeChange(values) {
|
|
|
+ selectDeptId.value = values;
|
|
|
+}
|
|
|
+
|
|
|
+function handleConfirm() {
|
|
|
+ form.value.deptIds = [selectDeptId.value];
|
|
|
+ popup.value.close();
|
|
|
+ loadDeviceOptions();
|
|
|
+ loadUserOptions();
|
|
|
+}
|
|
|
+
|
|
|
+const deviceOptions = ref([]);
|
|
|
+const deviceLoading = ref(false);
|
|
|
+
|
|
|
+const loadDeviceOptions = async (init = false) => {
|
|
|
+ deviceOptions.value = [];
|
|
|
+ if (!init) form.value.deviceIds = [];
|
|
|
+
|
|
|
+ if (!form.value.deptIds || form.value.deptIds.length === 0) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ deviceLoading.value = true;
|
|
|
+ try {
|
|
|
+ const res = await getDevicesByDepts({ deptIds: form.value.deptIds });
|
|
|
+ deviceOptions.value = res.data.map((item) => ({
|
|
|
+ text: `${item.deviceCode} ${item.deviceName}`,
|
|
|
+ value: item.id,
|
|
|
+ raw: item,
|
|
|
+ }));
|
|
|
+
|
|
|
+ form.value.deviceIds = deviceOptions.value.map((item) => item.value);
|
|
|
+ } finally {
|
|
|
+ deviceLoading.value = false;
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+const userOptions = ref([]);
|
|
|
+const userLoading = ref(false);
|
|
|
+
|
|
|
+const loadUserOptions = async (init = false) => {
|
|
|
+ userOptions.value = [];
|
|
|
+ if (!init) form.value.responsiblePerson = undefined;
|
|
|
+
|
|
|
+ if (!form.value.deptIds || form.value.deptIds.length === 0) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ userLoading.value = true;
|
|
|
+ try {
|
|
|
+ const res = await selectedDeptsEmployee({
|
|
|
+ deptIds: form.value.deptIds,
|
|
|
+ });
|
|
|
+ userOptions.value = res.data.map((item) => ({
|
|
|
+ text: item.nickname,
|
|
|
+ value: item.id,
|
|
|
+ raw: item,
|
|
|
+ }));
|
|
|
+ } finally {
|
|
|
+ userLoading.value = false;
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+const loadDetail = async (id) => {
|
|
|
+ if (!id) return;
|
|
|
+
|
|
|
+ const res = await getRuiHenTaskDetail1({ id });
|
|
|
+
|
|
|
+ const data = res.data.list[0] || createInitialForm();
|
|
|
+
|
|
|
+ Object.assign(form.value, {
|
|
|
+ id: data.id,
|
|
|
+ projectId: data.projectId,
|
|
|
+ wellName: data.wellName,
|
|
|
+ location: data.location,
|
|
|
+ technique: Number(data.technique),
|
|
|
+ workloadDesign: data.workloadDesign,
|
|
|
+ workloadUnit: Number(data.workloadUnit),
|
|
|
+ deptIds: data.deptIds || [],
|
|
|
+ deviceIds: data.deviceIds || [],
|
|
|
+ responsiblePerson: data.responsiblePerson
|
|
|
+ ? data.responsiblePerson[0]
|
|
|
+ : undefined,
|
|
|
+ remark: data.remark,
|
|
|
+ });
|
|
|
+
|
|
|
+ selectedContractLabel.value = data.contractName || "";
|
|
|
+
|
|
|
+ loadDeviceOptions(true);
|
|
|
+ loadUserOptions(true);
|
|
|
+};
|
|
|
+
|
|
|
+watch(
|
|
|
+ () => props.id,
|
|
|
+ async (newId) => {
|
|
|
+ if (props.type !== "create" && newId) {
|
|
|
+ await loadDetail(newId);
|
|
|
+ }
|
|
|
+ },
|
|
|
+ { immediate: true }
|
|
|
+);
|
|
|
+
|
|
|
+watch(
|
|
|
+ () => form.value.projectId,
|
|
|
+ (value) => {
|
|
|
+ if (!value) {
|
|
|
+ selectedContractLabel.value = "";
|
|
|
+ contractTempProjectId.value = "";
|
|
|
+ }
|
|
|
+ }
|
|
|
+);
|
|
|
+
|
|
|
+onMounted(async () => {
|
|
|
+ await Promise.all([loadDictOptions(), loadDeptOptions()]);
|
|
|
+});
|
|
|
+
|
|
|
+defineExpose({
|
|
|
+ form,
|
|
|
+ formRef,
|
|
|
+ validate,
|
|
|
+ buildSubmitData,
|
|
|
+});
|
|
|
+</script>
|
|
|
+
|
|
|
+<template>
|
|
|
+ <view class="content">
|
|
|
+ <uni-forms
|
|
|
+ ref="formRef"
|
|
|
+ labelWidth="auto"
|
|
|
+ :model="form"
|
|
|
+ :rules="rules"
|
|
|
+ validateTrigger="submit"
|
|
|
+ err-show-type="toast">
|
|
|
+ <uni-forms-item label="合同" name="projectId" required>
|
|
|
+ <view class="select-with-button">
|
|
|
+ <view
|
|
|
+ class="popup-select-value"
|
|
|
+ :class="{ 'popup-select-placeholder': !contractDisplayText }"
|
|
|
+ @click="!isReadonly && openContractPopup()">
|
|
|
+ {{ contractDisplayText || "请选择合同" }}
|
|
|
+ </view>
|
|
|
+ <button
|
|
|
+ v-if="!isReadonly"
|
|
|
+ class="popup-button"
|
|
|
+ type="primary"
|
|
|
+ size="mini"
|
|
|
+ @click="openContractPopup">
|
|
|
+ 选择
|
|
|
+ </button>
|
|
|
+ </view>
|
|
|
+ </uni-forms-item>
|
|
|
+ <uni-forms-item label="井号" name="wellName" required>
|
|
|
+ <uni-easyinput
|
|
|
+ v-bind="defaultProps('井号')"
|
|
|
+ v-model="form.wellName"
|
|
|
+ :disabled="isReadonly" />
|
|
|
+ </uni-forms-item>
|
|
|
+ <uni-forms-item label="施工地点" name="location" required>
|
|
|
+ <uni-easyinput
|
|
|
+ v-bind="defaultProps('施工地点')"
|
|
|
+ v-model="form.location"
|
|
|
+ :disabled="isReadonly" />
|
|
|
+ </uni-forms-item>
|
|
|
+ <uni-forms-item label="施工工艺" name="technique" required>
|
|
|
+ <uni-data-select
|
|
|
+ :clear="true"
|
|
|
+ align="right"
|
|
|
+ placeholder="请选择施工工艺"
|
|
|
+ :localdata="techniqueOptions"
|
|
|
+ placement="bottom"
|
|
|
+ hideRight
|
|
|
+ :disabled="isReadonly"
|
|
|
+ v-model="form.technique" />
|
|
|
+ </uni-forms-item>
|
|
|
+ <uni-forms-item label="设计工作量" name="workloadDesign" required>
|
|
|
+ <uni-easyinput
|
|
|
+ type="number"
|
|
|
+ v-bind="defaultProps('设计工作量')"
|
|
|
+ v-model.number="form.workloadDesign"
|
|
|
+ :disabled="isReadonly" />
|
|
|
+ </uni-forms-item>
|
|
|
+ <uni-forms-item label="工作量单位" name="workloadUnit" required>
|
|
|
+ <uni-data-select
|
|
|
+ :clear="true"
|
|
|
+ align="right"
|
|
|
+ placeholder="请选择工作量单位"
|
|
|
+ :localdata="workloadUnitOptions"
|
|
|
+ placement="bottom"
|
|
|
+ hideRight
|
|
|
+ :disabled="isReadonly"
|
|
|
+ v-model="form.workloadUnit" />
|
|
|
+ </uni-forms-item>
|
|
|
+ <uni-forms-item label="施工队伍" name="deptIds" required>
|
|
|
+ <view class="select-with-button">
|
|
|
+ <uni-data-select
|
|
|
+ :clear="true"
|
|
|
+ align="right"
|
|
|
+ placeholder="请选择施工队伍"
|
|
|
+ :localdata="deptOptions"
|
|
|
+ placement="bottom"
|
|
|
+ hideRight
|
|
|
+ :disabled="true"
|
|
|
+ multiple
|
|
|
+ v-model="form.deptIds" />
|
|
|
+ <button
|
|
|
+ v-if="!isReadonly"
|
|
|
+ class="popup-button"
|
|
|
+ type="primary"
|
|
|
+ size="mini"
|
|
|
+ :disabled="deptLoading"
|
|
|
+ @click="openPopup">
|
|
|
+ 选择
|
|
|
+ </button>
|
|
|
+ </view>
|
|
|
+ </uni-forms-item>
|
|
|
+ <uni-forms-item label="施工设备" name="deviceIds" required>
|
|
|
+ <uni-data-select
|
|
|
+ :clear="true"
|
|
|
+ align="right"
|
|
|
+ placeholder="请选择施工设备"
|
|
|
+ :localdata="deviceOptions"
|
|
|
+ placement="bottom"
|
|
|
+ hideRight
|
|
|
+ multiple
|
|
|
+ :disabled="isReadonly || deviceLoading"
|
|
|
+ v-model="form.deviceIds">
|
|
|
+ <template #selected="{ selectedItems }">
|
|
|
+ <view class="device-selected-box">
|
|
|
+ <view v-if="selectedItems.length" class="device-selected-list">
|
|
|
+ <view
|
|
|
+ v-for="item in selectedItems"
|
|
|
+ :key="item.value"
|
|
|
+ class="device-selected-item">
|
|
|
+ {{ item.text }}
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+ <view v-else class="device-selected-placeholder">
|
|
|
+ 请选择施工设备
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+ </template>
|
|
|
+ </uni-data-select>
|
|
|
+ </uni-forms-item>
|
|
|
+ <uni-forms-item label="责任人" name="responsiblePerson" required>
|
|
|
+ <uni-data-select
|
|
|
+ :clear="true"
|
|
|
+ align="right"
|
|
|
+ placeholder="请选择责任人"
|
|
|
+ :localdata="userOptions"
|
|
|
+ placement="bottom"
|
|
|
+ hideRight
|
|
|
+ :disabled="isReadonly || userLoading"
|
|
|
+ v-model="form.responsiblePerson" />
|
|
|
+ </uni-forms-item>
|
|
|
+ <uni-forms-item label="备注" name="remark">
|
|
|
+ <uni-easyinput
|
|
|
+ type="textarea"
|
|
|
+ autoHeight
|
|
|
+ v-bind="defaultProps('备注')"
|
|
|
+ v-model="form.remark"
|
|
|
+ :disabled="isReadonly"
|
|
|
+ :maxlength="1000" />
|
|
|
+ </uni-forms-item>
|
|
|
+ </uni-forms>
|
|
|
+ </view>
|
|
|
+
|
|
|
+ <uni-popup
|
|
|
+ ref="contractPopup"
|
|
|
+ type="bottom"
|
|
|
+ :is-mask-click="false"
|
|
|
+ border-radius="10px 10px 0 0">
|
|
|
+ <z-paging
|
|
|
+ ref="contractPaging"
|
|
|
+ v-model="contractList"
|
|
|
+ class="contract-popup-paging"
|
|
|
+ style="top: 140px"
|
|
|
+ :default-page-size="20"
|
|
|
+ @query="queryContractList">
|
|
|
+ <template #top>
|
|
|
+ <view class="contract-popup-top">
|
|
|
+ <view class="contract-popup-header">
|
|
|
+ <text class="contract-popup-action" @click="closeContractPopup">
|
|
|
+ 取消
|
|
|
+ </text>
|
|
|
+ <text class="contract-popup-title">选择合同</text>
|
|
|
+ <text
|
|
|
+ class="contract-popup-action primary"
|
|
|
+ @click="handleContractConfirm">
|
|
|
+ 确定
|
|
|
+ </text>
|
|
|
+ </view>
|
|
|
+ <view class="contract-search-row">
|
|
|
+ <uni-easyinput
|
|
|
+ v-model="contractSearchValue"
|
|
|
+ :inputBorder="false"
|
|
|
+ :styles="contractSearchInputStyles"
|
|
|
+ placeholder="请输入合同名称"
|
|
|
+ @confirm="searchContractList" />
|
|
|
+ <button
|
|
|
+ class="mini-btn contract-search-button"
|
|
|
+ type="primary"
|
|
|
+ size="mini"
|
|
|
+ @click="searchContractList">
|
|
|
+ 搜索
|
|
|
+ </button>
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+ </template>
|
|
|
+
|
|
|
+ <radio-group @change="handleContractRadioChange">
|
|
|
+ <view class="contract-popup-list">
|
|
|
+ <view
|
|
|
+ v-for="item in contractList"
|
|
|
+ :key="item.id"
|
|
|
+ class="contract-popup-item"
|
|
|
+ :class="{ active: String(item.id) === contractTempProjectId }"
|
|
|
+ @click="handleContractRowClick(item)">
|
|
|
+ <view class="contract-popup-item-main">
|
|
|
+ <view class="contract-popup-item-name">
|
|
|
+ {{ item.contractName || "--" }}
|
|
|
+ </view>
|
|
|
+ <!-- <view
|
|
|
+ v-if="item.projectNo || item.contractCode"
|
|
|
+ class="contract-popup-item-desc">
|
|
|
+ {{ item.projectNo || item.contractCode }}
|
|
|
+ </view> -->
|
|
|
+ </view>
|
|
|
+ <radio
|
|
|
+ :value="String(item.id)"
|
|
|
+ :checked="String(item.id) === contractTempProjectId"
|
|
|
+ color="#2979ff" />
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+ </radio-group>
|
|
|
+ </z-paging>
|
|
|
+ </uni-popup>
|
|
|
+
|
|
|
+ <uni-popup ref="popup" type="bottom">
|
|
|
+ <view class="popup-content">
|
|
|
+ <view class="tree">
|
|
|
+ <DaTree
|
|
|
+ :data="treeData"
|
|
|
+ labelField="name"
|
|
|
+ valueField="id"
|
|
|
+ disabledField="disabled"
|
|
|
+ defaultExpandAll
|
|
|
+ checkedDisabled
|
|
|
+ :defaultCheckedKeys="form.deptIds[0]"
|
|
|
+ @change="handleTreeChange"></DaTree>
|
|
|
+ </view>
|
|
|
+ <button class="mini-btn" type="primary" @click="handleConfirm">
|
|
|
+ 确定
|
|
|
+ </button>
|
|
|
+ </view>
|
|
|
+ </uni-popup>
|
|
|
+</template>
|
|
|
+
|
|
|
+<style lang="scss" scoped>
|
|
|
+.content {
|
|
|
+ background-color: #fff;
|
|
|
+ padding: 16px;
|
|
|
+ border-radius: 8px;
|
|
|
+ box-sizing: border-box;
|
|
|
+}
|
|
|
+
|
|
|
+.uni-forms {
|
|
|
+ margin-top: 10px;
|
|
|
+}
|
|
|
+
|
|
|
+:deep(.uni-forms-item) {
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ margin-bottom: 6px;
|
|
|
+ border-bottom: 1px dashed #cacccf;
|
|
|
+}
|
|
|
+
|
|
|
+:deep(.uni-forms-item__content) {
|
|
|
+ text-align: right;
|
|
|
+}
|
|
|
+
|
|
|
+:deep(.uni-forms-item__label) {
|
|
|
+ height: 44px;
|
|
|
+ font-weight: 500;
|
|
|
+ font-size: 14px;
|
|
|
+ color: #333 !important;
|
|
|
+ width: max-content !important;
|
|
|
+}
|
|
|
+
|
|
|
+:deep(.uni-select) {
|
|
|
+ border: none;
|
|
|
+ text-align: right;
|
|
|
+ padding-right: 10px;
|
|
|
+}
|
|
|
+
|
|
|
+:deep(.uniui-bottom:before) {
|
|
|
+ content: "\e6b5" !important;
|
|
|
+ font-size: 16px !important;
|
|
|
+}
|
|
|
+
|
|
|
+:deep(.uni-easyinput__content-textarea) {
|
|
|
+ min-height: inherit;
|
|
|
+ margin: 10px;
|
|
|
+}
|
|
|
+
|
|
|
+:deep(.uni-textarea-textarea:disabled),
|
|
|
+:deep(.uni-input-input:disabled),
|
|
|
+:deep(.is-disabled) {
|
|
|
+ color: #333 !important;
|
|
|
+}
|
|
|
+
|
|
|
+:deep(.uni-select--disabled) {
|
|
|
+ background-color: #fff;
|
|
|
+}
|
|
|
+
|
|
|
+.select-with-button {
|
|
|
+ display: flex;
|
|
|
+ justify-content: flex-end;
|
|
|
+ align-items: center;
|
|
|
+ gap: 10px;
|
|
|
+ width: 100%;
|
|
|
+}
|
|
|
+
|
|
|
+.readonly-input {
|
|
|
+ flex: 1;
|
|
|
+}
|
|
|
+
|
|
|
+.popup-select-value {
|
|
|
+ flex: 1;
|
|
|
+ min-height: 32px;
|
|
|
+ display: flex;
|
|
|
+ justify-content: flex-end;
|
|
|
+ align-items: center;
|
|
|
+ color: #333;
|
|
|
+ font-size: 14px;
|
|
|
+ line-height: 1.4;
|
|
|
+ text-align: right;
|
|
|
+ word-break: break-all;
|
|
|
+}
|
|
|
+
|
|
|
+.popup-select-placeholder {
|
|
|
+ color: #999;
|
|
|
+}
|
|
|
+
|
|
|
+.contract-popup-paging {
|
|
|
+ background-color: #fff;
|
|
|
+ border-radius: 10px 10px 0 0;
|
|
|
+}
|
|
|
+
|
|
|
+.contract-popup-top {
|
|
|
+ padding: 16px;
|
|
|
+ padding-bottom: 10px;
|
|
|
+ background-color: #fff;
|
|
|
+}
|
|
|
+
|
|
|
+.contract-popup-header {
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: space-between;
|
|
|
+ margin-bottom: 16px;
|
|
|
+ font-size: 15px;
|
|
|
+}
|
|
|
+
|
|
|
+.contract-popup-title {
|
|
|
+ font-size: 16px;
|
|
|
+ font-weight: 600;
|
|
|
+ color: #333;
|
|
|
+}
|
|
|
+
|
|
|
+.contract-popup-action {
|
|
|
+ color: #666;
|
|
|
+}
|
|
|
+
|
|
|
+.contract-popup-action.primary {
|
|
|
+ color: #2979ff;
|
|
|
+}
|
|
|
+
|
|
|
+.contract-search-row {
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ gap: 10px;
|
|
|
+}
|
|
|
+
|
|
|
+.contract-search-button {
|
|
|
+ width: 72px;
|
|
|
+ margin: 0;
|
|
|
+ flex-shrink: 0;
|
|
|
+}
|
|
|
+
|
|
|
+.contract-popup-list {
|
|
|
+ padding: 0 16px 16px;
|
|
|
+ background-color: #fff;
|
|
|
+}
|
|
|
+
|
|
|
+.contract-popup-item {
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: space-between;
|
|
|
+ gap: 12px;
|
|
|
+ padding: 14px 0;
|
|
|
+ border-bottom: 1px solid #f0f0f0;
|
|
|
+}
|
|
|
+
|
|
|
+.contract-popup-item.active {
|
|
|
+ color: #2979ff;
|
|
|
+}
|
|
|
+
|
|
|
+.contract-popup-item-main {
|
|
|
+ flex: 1;
|
|
|
+ min-width: 0;
|
|
|
+}
|
|
|
+
|
|
|
+.contract-popup-item-name {
|
|
|
+ font-size: 14px;
|
|
|
+ line-height: 1.5;
|
|
|
+ color: inherit;
|
|
|
+ word-break: break-all;
|
|
|
+}
|
|
|
+
|
|
|
+.contract-popup-item-desc {
|
|
|
+ margin-top: 4px;
|
|
|
+ font-size: 12px;
|
|
|
+ color: #999;
|
|
|
+}
|
|
|
+
|
|
|
+.device-selected-box {
|
|
|
+ width: 100%;
|
|
|
+ min-height: 24px;
|
|
|
+ display: flex;
|
|
|
+ justify-content: flex-end;
|
|
|
+ align-items: center;
|
|
|
+}
|
|
|
+
|
|
|
+.device-selected-list {
|
|
|
+ width: 100%;
|
|
|
+ display: flex;
|
|
|
+ flex-wrap: wrap;
|
|
|
+ justify-content: flex-end;
|
|
|
+ gap: 6px;
|
|
|
+}
|
|
|
+
|
|
|
+.device-selected-item {
|
|
|
+ max-width: 100%;
|
|
|
+ padding: 4px 8px;
|
|
|
+ border-radius: 4px;
|
|
|
+ background: #f3f5f9;
|
|
|
+ color: #333;
|
|
|
+ font-size: 12px;
|
|
|
+ line-height: 1.4;
|
|
|
+ word-break: break-all;
|
|
|
+}
|
|
|
+
|
|
|
+.device-selected-placeholder {
|
|
|
+ color: #999;
|
|
|
+ font-size: 14px;
|
|
|
+}
|
|
|
+
|
|
|
+:deep(.popup-button) {
|
|
|
+ width: 62px;
|
|
|
+ margin: 0;
|
|
|
+ flex-shrink: 0;
|
|
|
+}
|
|
|
+
|
|
|
+.popup-content {
|
|
|
+ display: flex;
|
|
|
+ flex-direction: column;
|
|
|
+ justify-content: space-between;
|
|
|
+ padding: 15px;
|
|
|
+ height: 500px;
|
|
|
+ background-color: #fff;
|
|
|
+}
|
|
|
+
|
|
|
+.tree {
|
|
|
+ flex: 1;
|
|
|
+ max-height: 420px;
|
|
|
+}
|
|
|
+
|
|
|
+.popup-content button {
|
|
|
+ width: 100%;
|
|
|
+ height: 44px;
|
|
|
+}
|
|
|
+
|
|
|
+:deep(.uni-select__selector-item) {
|
|
|
+ padding: 0;
|
|
|
+ width: 100%;
|
|
|
+ overflow-x: auto;
|
|
|
+ overflow-y: hidden;
|
|
|
+ white-space: nowrap;
|
|
|
+ -webkit-overflow-scrolling: touch;
|
|
|
+
|
|
|
+ uni-text {
|
|
|
+ padding: 0 10px;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+:deep(.uni-select__selector-item uni-text),
|
|
|
+:deep(.uni-select__selector-item uni-text span) {
|
|
|
+ display: inline-block;
|
|
|
+ white-space: nowrap;
|
|
|
+ min-width: max-content;
|
|
|
+}
|
|
|
+</style>
|