| | |
| | | <div class="project_add"> |
| | | <div class="side-header"> |
| | | <div class="side-option flex-display flex-align-center"> |
| | | <left-outlined :style="{ fontSize: '18px', marginRight: '8px' }" /> |
| | | <h2 class="title">创建项目</h2> |
| | | <left-outlined class="point" @click="goBack" :style="{ fontSize: '18px', marginRight: '8px' }" /> |
| | | <h2 class="title point" @click="goBack">{{ route.query.id ? '编辑项目' : '创建项目' }}</h2> |
| | | </div> |
| | | <div class="border-bottom"></div> |
| | | </div> |
| | | <div class="side-form-content"> |
| | | <a-form layout="vertical" :model="formState"> |
| | | <a-form-item label="项目名称"> |
| | | <a-form hideRequiredMark layout="vertical" :model="formState" :rules="rules" ref="projectForm"> |
| | | <a-form-item label="项目名称" :name="FormProject.PROJECT_NAME"> |
| | | <a-input v-model:value="formState[FormProject.PROJECT_NAME]" placeholder="项目名称" /> |
| | | </a-form-item> |
| | | <a-form-item label="项目简介"> |
| | | <a-form-item label="项目简介" :name="FormProject.PROJCECT_INTRO"> |
| | | <a-textarea :auto-size="{ minRows: 4, maxRows: 8 }" type="textarea" |
| | | v-model:value="formState[FormProject.PROJCECT_INTRO]" placeholder="项目简介" /> |
| | | </a-form-item> |
| | |
| | | <div class="application flex-display flex-align-center flex-justify-between"> |
| | | <p>天气阻飞设置</p> |
| | | <div class="btn"> |
| | | <a-button type="text" disabled> |
| | | <span class="button_name">未开启</span> |
| | | <a-button type="text" @click="openDrawer('weatherDrawer')"> |
| | | <span class="button_name">{{ formState.projectBlocking && |
| | | formState.projectBlocking.cloudBlockingConfigEnable == '1' ? |
| | | '已开启' |
| | | : '未开启' }}</span> |
| | | <template #icon><right-outlined |
| | | :style="{ fontSize: '14px', color: '#fff', marginLeft: '8px' }" /></template> |
| | | </a-button> |
| | |
| | | <div class="application flex-display flex-align-center flex-justify-between"> |
| | | <p>项目成员</p> |
| | | <div> |
| | | <a-button type="text"> |
| | | <a-button type="text" @click="openDrawer('userDrawer')"> |
| | | <span class="button_add">添加成员</span> |
| | | <template #icon><plus-outlined :style="{ fontSize: '14px', color: '#2d8cf0' }" /></template> |
| | | </a-button> |
| | | </div> |
| | | </div> |
| | | <a-table :columns="columns" :data-source="dataSource" bordered> |
| | | <template v-for="col in ['name', 'age', 'address']" #[col]="{ text, record }" :key="col"> |
| | | <a-table class="ant-table-project" :columns="Usercolumns" :data-source="dataSource" bordered |
| | | :pagination="false" :rowClassName="() => 'project_dark'"> |
| | | <template v-for="col in ['name', 'role', 'edit']" #[col]="{ text, record }" :key="col"> |
| | | <div> |
| | | <a-input v-if="editableData[record.key]" v-model:value="editableData[record.key][col]" |
| | | style="margin: -5px 0" /> |
| | |
| | | <template #operation="{ record }"> |
| | | <div class="editable-row-operations"> |
| | | <span v-if="editableData[record.key]"> |
| | | <a @click="save(record.key)">Save</a> |
| | | <a-popconfirm title="Sure to cancel?" @confirm="cancel(record.key)"> |
| | | <a>Cancel</a> |
| | | </a-popconfirm> |
| | | <div class="flex-display flex-align-center flex-justify-between"> |
| | | <CheckOutlined :style="{ fontSize: '14px', color: '#28d445' }" |
| | | @click="save(record.key, 'editableData')" /> |
| | | <a-popconfirm title="确定取消?" ok-text="确定" cancel-text="取消" |
| | | @confirm="cancel(record.key, 'editableData')"> |
| | | <CloseOutlined :style="{ fontSize: '14px', color: '#e70102' }" /> |
| | | </a-popconfirm> |
| | | </div> |
| | | </span> |
| | | <span v-else> |
| | | <a @click="edit(record.key)">Edit</a> |
| | | <div class="flex-display flex-align-center flex-justify-between"> |
| | | <EditOutlined :style="{ fontSize: '14px', color: '#1180ff' }" |
| | | @click="edit(record.key, 'editableData')" /> |
| | | <DeleteOutlined :style="{ fontSize: '14px', color: '#e70102' }" |
| | | @click="del(record.key, 'editableData')" /> |
| | | </div> |
| | | </span> |
| | | </div> |
| | | </template> |
| | | </a-table> |
| | | </a-form-item> |
| | | <a-form-item> |
| | | <a-button type="primary">Submit</a-button> |
| | | <div class="application flex-display flex-align-center flex-justify-between"> |
| | | <p>项目设备</p> |
| | | <div> |
| | | <a-button type="text"> |
| | | <span class="button_add">添加飞行器</span> |
| | | <template #icon><plus-outlined :style="{ fontSize: '14px', color: '#2d8cf0' }" /></template> |
| | | </a-button> |
| | | </div> |
| | | </div> |
| | | <a-table class="ant-table-project" :columns="Devicecolumns" :data-source="deviceSource" bordered |
| | | :pagination="false" :rowClassName="() => 'project_dark'"> |
| | | <template v-for="col in ['name', 'role', 'edit']" #[col]="{ text, record }" :key="col"> |
| | | <div> |
| | | <a-input v-if="editDeviceData[record.key]" v-model:value="editDeviceData[record.key][col]" |
| | | style="margin: -5px 0" /> |
| | | <template v-else> |
| | | {{ text }} |
| | | </template> |
| | | </div> |
| | | </template> |
| | | <template #operation="{ record }"> |
| | | <div class="editable-row-operations"> |
| | | <span v-if="editDeviceData[record.key]"> |
| | | <div class="flex-display flex-align-center flex-justify-between"> |
| | | <CheckOutlined :style="{ fontSize: '14px', color: '#28d445' }" |
| | | @click="save(record.key, 'editDeviceData')" /> |
| | | <a-popconfirm title="确定取消?" ok-text="确定" cancel-text="取消" |
| | | @confirm="cancel(record.key, 'editDeviceData')"> |
| | | <CloseOutlined :style="{ fontSize: '14px', color: '#e70102' }" /> |
| | | </a-popconfirm> |
| | | </div> |
| | | </span> |
| | | <span v-else> |
| | | <div class="flex-display flex-align-center flex-justify-between"> |
| | | <EditOutlined :style="{ fontSize: '14px', color: '#1180ff' }" |
| | | @click="edit(record.key, 'editDeviceData')" /> |
| | | <DeleteOutlined :style="{ fontSize: '14px', color: '#e70102' }" |
| | | @click="del(record.key, 'editDeviceData')" /> |
| | | </div> |
| | | </span> |
| | | </div> |
| | | </template> |
| | | </a-table> |
| | | </a-form-item> |
| | | <a-form-item :name="FormProject.LATITUDE"> |
| | | <div class="application flex-display flex-align-center flex-justify-between"> |
| | | <p>项目作业中心点</p> |
| | | <div> |
| | | <a-button type="text" @click="configCenter"> |
| | | <span class="button_add">设置项目中心点</span> |
| | | <template #icon> |
| | | <AimOutlined :style="{ fontSize: '14px', color: '#2d8cf0' }" /> |
| | | </template> |
| | | </a-button> |
| | | </div> |
| | | </div> |
| | | <div class="latitude" v-if="latitude && latitude != 0"> |
| | | 经纬度:{{ latitude }}°N {{ longitude }}°E</div> |
| | | </a-form-item> |
| | | </a-form> |
| | | <WeatherDrawer v-model:show="drawerConfig.weatherDrawer" title="以下设置仅在当前项目中生效"> |
| | | <ComWeather v-model="formState" /> |
| | | </WeatherDrawer> |
| | | <WeatherDrawer v-model:show="drawerConfig.userDrawer" title="添加成员"> |
| | | <ComUser v-model="formState" /> |
| | | </WeatherDrawer> |
| | | </div> |
| | | <div class="fix-button"> |
| | | <a-button @click="submit" style="width: 100%;height: 36px;justify-content: center;" |
| | | class="flex-display flex-align-center" type="primary">{{ route.query.id ? '编辑项目' : '创建项目' }}</a-button> |
| | | </div> |
| | | </div> |
| | | </template> |
| | | |
| | | <script setup lang="ts"> |
| | | import { LeftOutlined, RightOutlined, PlusOutlined } from '@ant-design/icons-vue' |
| | | import { FormState, FormProject } from './type' |
| | | import { LeftOutlined, RightOutlined, PlusOutlined, EditOutlined, DeleteOutlined, CheckOutlined, CloseOutlined, AimOutlined } from '@ant-design/icons-vue' |
| | | import { FormState, FormProject, Usercolumns, ProjectUser, Devicecolumns, ProjectDevice, rules, blocking } from './type' |
| | | import { UnwrapRef } from 'vue' |
| | | const columns = [ |
| | | { |
| | | title: '人员项目呼号', |
| | | dataIndex: 'name', |
| | | key: 'name', |
| | | }, |
| | | { |
| | | title: '项目角色', |
| | | dataIndex: 'role', |
| | | key: 'role', |
| | | responsive: ['md'], |
| | | }, |
| | | { |
| | | title: '编辑', |
| | | dataIndex: 'edit', |
| | | key: 'edit', |
| | | responsive: ['lg'], |
| | | }, |
| | | ] |
| | | interface DataItem { |
| | | key: string; |
| | | name: string; |
| | | role: number; |
| | | edit: string; |
| | | } |
| | | const dataSource = ref([ |
| | | { |
| | | key: '1', |
| | | name: '接口活', |
| | | role: '项目管理员' |
| | | } |
| | | ]) |
| | | const editableData: UnwrapRef<Record<string, DataItem>> = reactive({}) |
| | | import WeatherDrawer from '/@/components/Drawer/Drawer.vue' |
| | | import ComWeather from './components/WeatherDrawer.vue' |
| | | import ComUser from './components/UserDrawer.vue' |
| | | import { ValidateErrorEntity } from 'ant-design-vue/es/form/interface' |
| | | import { Form, message } from 'ant-design-vue' |
| | | import { cloneDeep } from 'lodash' |
| | | import { add, detail, edit as projectEdit } from '/@/api/project-page/index' |
| | | import { addPoint } from '/@/hooks/use-center-point' |
| | | import { useMyStore } from '/@/store/index' |
| | | const { appContext } = getCurrentInstance() |
| | | const global = appContext.config.globalProperties |
| | | const router = useRouter() |
| | | const store = useMyStore() |
| | | const route = useRoute() |
| | | const dataSource = ref([]) |
| | | const deviceSource = ref([]) |
| | | const editableData: UnwrapRef<Record<string, ProjectUser>> = reactive({}) |
| | | const editDeviceData: UnwrapRef<Record<string, ProjectDevice>> = reactive({}) |
| | | const longitude = computed(() => { |
| | | return store.state.map.centerConfig.longitude |
| | | }) |
| | | const latitude = computed(() => { |
| | | return store.state.map.centerConfig.latitude |
| | | }) |
| | | const formState = ref<FormState>({ |
| | | [FormProject.PROJECT_NAME]: '', |
| | | [FormProject.PROJECT_STATUS]: '', |
| | | [FormProject.PROJCECT_INTRO]: '', |
| | | [FormProject.LONGITUDE]: 0, |
| | | [FormProject.LATITUDE]: 0, |
| | | [FormProject.USERLIST]: [] |
| | | [FormProject.LONGITUDE]: null, |
| | | [FormProject.LATITUDE]: null, |
| | | [FormProject.USERLIST]: [], |
| | | [FormProject.PROJECT_BLOCKING]: { |
| | | [blocking.CLOUDBLOCKINGCONFIGENABLE]: '1', |
| | | [blocking.WEATHERREPORTENABLE]: '1', |
| | | [blocking.WINDSPEED]: 12, |
| | | [blocking.WINDSPEEDREPORT]: 15, |
| | | [blocking.RAIN]: 3 |
| | | } |
| | | }) |
| | | const drawerConfig = ref({ |
| | | userDrawer: false, |
| | | weatherDrawer: false, |
| | | }) |
| | | const projectForm = ref() |
| | | // 表格操作方法 |
| | | const edit = (key: string, type: string) => { |
| | | if (type === 'editableData') { |
| | | editableData[key] = cloneDeep(dataSource.value.filter(item => key === item.key)[0]) |
| | | } else { |
| | | editDeviceData[key] = cloneDeep(deviceSource.value.filter(item => key === item.key)[0]) |
| | | } |
| | | } |
| | | const save = (key: string, type: string) => { |
| | | if (type === 'editableData') { |
| | | Object.assign(dataSource.value.filter(item => key === item.key)[0], editableData[key]) |
| | | delete editableData[key] |
| | | } else { |
| | | Object.assign(deviceSource.value.filter(item => key === item.key)[0], editDeviceData[key]) |
| | | delete editDeviceData[key] |
| | | } |
| | | } |
| | | const cancel = (key: string, type: string) => { |
| | | if (type === 'editableData') { |
| | | delete editableData[key] |
| | | } else { |
| | | delete editDeviceData[key] |
| | | } |
| | | } |
| | | const del = (key: string, type: string) => { |
| | | console.log(key) |
| | | } |
| | | // 获取项目详情 |
| | | const getDetail = async () => { |
| | | if (!route.query.id) return |
| | | const id = route.query.id |
| | | const res = await detail(id) |
| | | if (res.code !== 5000) return |
| | | formState.value = res.data |
| | | addPoint(global.$viewer, res.data.id, res.data.latitude, res.data.latitude) |
| | | store.commit('SET_CENTER_CONFIG_LATITUDE', { latitude: formState.value.latitude, longitude: formState.value.longitude }) |
| | | } |
| | | // 编辑项目 |
| | | const editProject = async () => { |
| | | const res = await projectEdit(formState.value) |
| | | if (res.code !== 5000) return |
| | | message.success('修改成功') |
| | | router.go(-1) |
| | | store.commit('SET_CENTER_CONFIG_TYPE', false) |
| | | store.commit('SET_CENTER_CONFIG_LATITUDE', { latitude: null, longitude: null }) |
| | | } |
| | | // 新增项目 |
| | | const addProject = async () => { |
| | | const res = await add(formState.value) |
| | | if (res.code !== 5000) return |
| | | message.success('保存成功') |
| | | router.go(-1) |
| | | store.commit('SET_CENTER_CONFIG_TYPE', false) |
| | | store.commit('SET_CENTER_CONFIG_LATITUDE', { latitude: null, longitude: null }) |
| | | } |
| | | const goBack = () => { |
| | | router.go(-1) |
| | | store.commit('SET_CENTER_CONFIG_TYPE', false) |
| | | store.commit('SET_CENTER_CONFIG_LATITUDE', { latitude: null, longitude: null }) |
| | | } |
| | | // 天气组飞侧边栏 |
| | | const openDrawer = (name: string) => { |
| | | for (const key in drawerConfig.value) { |
| | | if (key === name) { |
| | | drawerConfig.value[key] = true |
| | | } else { |
| | | drawerConfig.value[key] = false |
| | | } |
| | | } |
| | | } |
| | | // 表单验证提交 |
| | | const submit = () => { |
| | | formState.value[FormProject.LATITUDE] = latitude.value |
| | | formState.value[FormProject.LONGITUDE] = longitude.value |
| | | projectForm.value.validate().then(async () => { |
| | | if (route.query.id) { |
| | | editProject() |
| | | } else { |
| | | addProject() |
| | | } |
| | | }).catch((error: ValidateErrorEntity<FormState>) => { |
| | | console.log(error) |
| | | }) |
| | | } |
| | | |
| | | // 设置项目中心点 |
| | | const configCenter = () => { |
| | | if (store.state.map.centerConfig.type === true) return |
| | | store.commit('SET_CENTER_CONFIG_TYPE', true) |
| | | } |
| | | onMounted(() => { |
| | | getDetail() |
| | | }) |
| | | </script> |
| | | |
| | |
| | | flex-direction: column; |
| | | height: 100%; |
| | | color: #fff; |
| | | position: relative; |
| | | background-color: #232323; |
| | | |
| | | .side-header { |
| | |
| | | margin: 0; |
| | | } |
| | | } |
| | | |
| | | .latitude { |
| | | margin-top: 8px; |
| | | font-size: 12px; |
| | | line-height: 20px; |
| | | color: hsla(0, 0%, 100%, .45); |
| | | } |
| | | |
| | | .ant-table-project :deep(.project_dark) td { |
| | | background-color: #232323 !important; |
| | | color: #fff !important; |
| | | border: none !important; |
| | | border-bottom: 1px solid #4f4f4f; |
| | | padding: 10px; |
| | | } |
| | | |
| | | .ant-table-project :deep(.ant-table-placeholder) { |
| | | background: #434343 !important; |
| | | border: none !important; |
| | | } |
| | | |
| | | .ant-table-project :deep(.ant-table-thead) th { |
| | | background: #3c3c3c !important; |
| | | color: #fff !important; |
| | | border: 1px solid #4f4f4f !important; |
| | | padding: 10px; |
| | | } |
| | | |
| | | .ant-table-project :deep(.ant-table-body) table { |
| | | border: 1px solid #4f4f4f !important; |
| | | border-right: 1px solid #4f4f4f !important; |
| | | } |
| | | |
| | | .ant-table-project :deep(.ant-table-body) { |
| | | background: #434343 !important; |
| | | } |
| | | |
| | | .ant-table-project :deep(.ant-empty-description) { |
| | | color: #fff !important; |
| | | } |
| | | } |
| | | |
| | | .fix-button { |
| | | position: sticky; |
| | | bottom: 0; |
| | | width: 100%; |
| | | padding: 16px; |
| | | border-top: 1px solid #4f4f4f; |
| | | } |
| | | |
| | | :deep(.ant-form-item-label > label) { |