husq
2023-09-01 f6bbabd538001e4c997b2d5474356dc345ff0ba5
项目-抽屉组件封装、天气阻飞设置页面搭建以及功能完善
8 files modified
4 files added
718 ■■■■ changed files
package-lock.json 14 ●●●● patch | view | raw | blame | history
package.json 1 ●●●● patch | view | raw | blame | history
src/components/Drawer/Drawer.vue 71 ●●●●● patch | view | raw | blame | history
src/components/Search/Select.vue 4 ●●●● patch | view | raw | blame | history
src/hooks/use-v-model.ts 21 ●●●●● patch | view | raw | blame | history
src/pages/page-web/projects/project_list/add_page/add.vue 253 ●●●● patch | view | raw | blame | history
src/pages/page-web/projects/project_list/add_page/components/WeatherDrawer.vue 135 ●●●●● patch | view | raw | blame | history
src/pages/page-web/projects/project_list/add_page/components/type.ts 48 ●●●●● patch | view | raw | blame | history
src/pages/page-web/projects/project_list/add_page/type.ts 142 ●●●● patch | view | raw | blame | history
src/styles/common.scss 7 ●●●●● patch | view | raw | blame | history
src/styles/flex.style.scss 14 ●●●●● patch | view | raw | blame | history
yarn.lock 8 ●●●● patch | view | raw | blame | history
package-lock.json
@@ -33,6 +33,7 @@
      },
      "devDependencies": {
        "@types/crypto-js": "^4.1.1",
        "@types/lodash": "^4.14.197",
        "@types/node": "^16.3.2",
        "@types/urlencode": "^1.1.2",
        "@typescript-eslint/eslint-plugin": "^5.8.1",
@@ -1298,10 +1299,9 @@
      "license": "MIT"
    },
    "node_modules/@types/lodash": {
      "version": "4.14.178",
      "resolved": "https://registry.npmmirror.com/@types/lodash/download/@types/lodash-4.14.178.tgz",
      "integrity": "sha512-0d5Wd09ItQWH1qFbEyQ7oTQ3GZrMfth5JkbN3EvTKLXcHLRDSXeLnlvlOn0wvxVIwK5o2M8JzP/OWz7T3NRsbw==",
      "license": "MIT"
      "version": "4.14.197",
      "resolved": "https://registry.npmmirror.com/@types/lodash/-/lodash-4.14.197.tgz",
      "integrity": "sha512-BMVOiWs0uNxHVlHBgzTIqJYmj+PgCo4euloGF+5m4okL3rEYzM2EEv78mw8zWSMM57dM7kVIgJ2QDvwHSoCI5g=="
    },
    "node_modules/@types/node": {
      "version": "16.11.19",
@@ -9959,9 +9959,9 @@
      "dev": true
    },
    "@types/lodash": {
      "version": "4.14.178",
      "resolved": "https://registry.npmmirror.com/@types/lodash/download/@types/lodash-4.14.178.tgz",
      "integrity": "sha512-0d5Wd09ItQWH1qFbEyQ7oTQ3GZrMfth5JkbN3EvTKLXcHLRDSXeLnlvlOn0wvxVIwK5o2M8JzP/OWz7T3NRsbw=="
      "version": "4.14.197",
      "resolved": "https://registry.npmmirror.com/@types/lodash/-/lodash-4.14.197.tgz",
      "integrity": "sha512-BMVOiWs0uNxHVlHBgzTIqJYmj+PgCo4euloGF+5m4okL3rEYzM2EEv78mw8zWSMM57dM7kVIgJ2QDvwHSoCI5g=="
    },
    "@types/node": {
      "version": "16.11.19",
package.json
@@ -33,6 +33,7 @@
  },
  "devDependencies": {
    "@types/crypto-js": "^4.1.1",
    "@types/lodash": "^4.14.197",
    "@types/node": "^16.3.2",
    "@types/urlencode": "^1.1.2",
    "@typescript-eslint/eslint-plugin": "^5.8.1",
src/components/Drawer/Drawer.vue
New file
@@ -0,0 +1,71 @@
<template>
    <div class="drawer" :class="[show ? 'active':'none']" v-show="show">
        <div class="side-header">
            <div class="side-option flex-display flex-align-center flex-justify-between">
                <h2 class="title">{{ title }}</h2>
                <CloseOutlined @click="close" />
            </div>
            <div class="border-bottom"></div>
        </div>
        <slot></slot>
    </div>
</template>
<script setup lang="ts">
import { defineProps, defineEmits } from 'vue'
import { CloseOutlined } from '@ant-design/icons-vue'
const porps = defineProps({
  show: {
    type: Boolean,
    default: false
  },
  title: {
    type: String,
    required: true
  }
})
const emits = defineEmits(['update:show'])
const close = () => {
  emits('update:show', false)
}
</script>
<style scoped lang="scss">
.active {
    z-index: 1;
    left: 100%;
}
.none {
    z-index: -1;
    left: 0;
}
.drawer {
    position: absolute;
    top: 0;
    width: 100%;
    height: 100%;
    transition: all .5s;
    box-shadow: -12px 0px 13px -6px rgba(0,0,0,0.1);
    background: #232323;
    .side-header {
        height: 60px;
        font-size: 16px;
        line-height: 60px;
        box-sizing: border-box;
        background-color: #232323;
        border-bottom: 1px solid #4f4f4f;
        .side-option {
            padding: 0 16px;
            .title {
                color: $text-white-basic;
                font-size: 18px;
                margin: 0;
                font-weight: 700;
            }
        }
    }
}
</style>
src/components/Search/Select.vue
@@ -12,14 +12,14 @@
const emit = defineEmits(['update:modelValue', 'handleChange'])
type Option = {
    label: string,
    value: string
    value: any
}
const props = defineProps({
  options: {
    type: Object as () => Option[],
    required: true,
  },
  modelValue: String,
  modelValue: [String, Number],
})
const value = computed({
  get: () => props.modelValue,
src/hooks/use-v-model.ts
New file
@@ -0,0 +1,21 @@
export function useVModel (props:any, propName:string, emit:any) {
  return computed({
    get () {
      return new Proxy(props[propName], {
        get (target, key) {
          return Reflect.get(target, key)
        },
        set (target, key, value) {
          emit('update:' + propName, {
            ...target,
            [key]: value
          })
          return true
        }
      })
    },
    set (val) {
      emit('update:' + propName, val)
    }
  })
}
src/pages/page-web/projects/project_list/add_page/add.vue
@@ -2,17 +2,17 @@
    <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">创建项目</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>
@@ -32,8 +32,8 @@
                    <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="openWeatherDrawer">
                                <span class="button_name">{{formState.projectBlocking.cloudBlockingConfigEnable == 1 ? '已开启' : '未开启' }}</span>
                                <template #icon><right-outlined
                                        :style="{ fontSize: '14px', color: '#fff', marginLeft: '8px' }" /></template>
                            </a-button>
@@ -50,8 +50,9 @@
                            </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" />
@@ -63,71 +64,170 @@
                        <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>
                    <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>
                                    <AimOutlined :style="{ fontSize: '14px', color: '#2d8cf0' }" />
                                </template>
                            </a-button>
                        </div>
                    </div>
                    <div class="latitude">经纬度:35.6761919°N 139.65031.6°E</div>
                </a-form-item>
            </a-form>
            <WeatherDrawer v-model:show="weatherDrawer" title="以下设置仅在当前项目中生效" >
                <ComWeather 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">创建项目</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 { ValidateErrorEntity } from 'ant-design-vue/es/form/interface'
import { cloneDeep } from 'lodash'
import router from '/@/router'
const dataSource = ref([])
const deviceSource = ref([])
const weatherDrawer = ref(false)
const editableData: UnwrapRef<Record<string, ProjectUser>> = reactive({})
const editDeviceData: UnwrapRef<Record<string, ProjectDevice>> = reactive({})
const formState = ref<FormState>({
  [FormProject.PROJECT_NAME]: '',
  [FormProject.PROJECT_NAME]: 'projectName',
  [FormProject.PROJECT_STATUS]: '',
  [FormProject.PROJCECT_INTRO]: '',
  [FormProject.LONGITUDE]: 0,
  [FormProject.LATITUDE]: 0,
  [FormProject.USERLIST]: []
  [FormProject.USERLIST]: [],
  [FormProject.PROJECT_BLOCKING]: {
    [blocking.CLOUDBLOCKINGCONFIGENABLE]: 1,
    [blocking.WEATHERREPORTENABLE]: 1,
    [blocking.WINDSPEED]: 12,
    [blocking.WINDSPEEDREPORT]: 15,
    [blocking.RAIN]: 3
  }
})
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 goBack = () => {
  router.go(-1)
}
// 天气组飞侧边栏
const openWeatherDrawer = () => {
  weatherDrawer.value = true
}
// 表单验证提交
const submit = () => {
  projectForm.value.validate().then(() => {
    console.log('验证通过', formState)
  }).catch((error:ValidateErrorEntity<FormState>) => {
    console.log(error)
  })
}
</script>
<style scoped lang="scss">
@@ -136,6 +236,7 @@
    flex-direction: column;
    height: 100%;
    color: #fff;
    position: relative;
    background-color: #232323;
    .side-header {
@@ -187,6 +288,54 @@
                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;
            color: #fff;
            border: none;
            border-bottom: 1px solid #4f4f4f;
            padding: 10px;
        }
        .ant-table-project :deep(.ant-table-placeholder) {
            background: #434343;
            border: none !important;
        }
        .ant-table-project :deep(.ant-table-thead) th {
            background: #3c3c3c;
            color: #fff;
            border: 1px solid #4f4f4f;
            padding: 10px;
        }
        .ant-table-project :deep(.ant-table-body) table {
            border: 1px solid #4f4f4f;
            border-right: 1px solid #4f4f4f;
        }
        .ant-table-project :deep(.ant-table-body) {
            background: #434343;
        }
        .ant-table-project :deep(.ant-empty-description) {
            color: #fff;
        }
    }
    .fix-button {
        position: sticky;
        bottom: 0;
        width: 100%;
        padding: 16px;
        border-top: 1px solid #4f4f4f;
    }
    :deep(.ant-form-item-label > label) {
src/pages/page-web/projects/project_list/add_page/components/WeatherDrawer.vue
New file
@@ -0,0 +1,135 @@
<template>
  <div class="com_weather">
    <div class="option">
      <div class="option-item" :style="[model.projectBlocking[blocking.CLOUDBLOCKINGCONFIGENABLE]!==1?'border:none' : '']">
        <span class="mr10">云端天气组飞设置</span>
        <a-switch :checkedValue="1" :unCheckedValue="2" v-model:checked="model.projectBlocking[blocking.CLOUDBLOCKINGCONFIGENABLE]" />
        <div v-if="model.projectBlocking[blocking.CLOUDBLOCKINGCONFIGENABLE]==1">
          <p class="mt10 describe">当风速或雨量大于设置值时,将对机场的飞行器进行阻飞。</p>
        </div>
        <div v-else>
          <p class="mt10 describe">关闭后,机场的阻飞仍生效。</p>
          <p class="mt10 describe">机场的阻飞条件:</p>
          <p class="mt10 describe">风速 (风速计) ≥12m/s 或 雨量 (雨量计) ≥大雨 </p>
        </div>
      </div>
      <div class="option-item" v-if="model.projectBlocking[blocking.CLOUDBLOCKINGCONFIGENABLE]==1">
        <span class="mr10">天气预报</span>
        <a-switch :checkedValue="1" :unCheckedValue="2" v-model:checked="model.projectBlocking[blocking.WEATHERREPORTENABLE]" />
        <p class="mt10 describe">天气阻飞将使用天气预报,同时也会使用机场风速计和雨量计数据。</p>
      </div>
      <div class="option-item-edit" v-if="model.projectBlocking[blocking.CLOUDBLOCKINGCONFIGENABLE]==1">
        <a-form ref="weatherFormRef" :model="FormWeatherModel" :rules="weatherRules">
          <a-form-item :name="FormWeather.WINDSPEED" ref="windDevice">
            <div class="edit-item flex-display flex-align-center flex-justify-between">
              <div class="white-color">风速<span class="describe">(风速计) (1-12m/s)</span></div>
              <div class="form-option flex-display flex-align-center white-color">
                <div :class="{ w48: edit }">
                  <span v-if="!edit">{{ model.projectBlocking[FormWeather.WINDSPEED] }}</span>
                  <a-input v-else v-model:value.number="FormWeatherModel[FormWeather.WINDSPEED]"></a-input>
                </div>
                <span>m/s</span>
              </div>
            </div>
          </a-form-item>
          <a-form-item :name="FormWeather.WINDSPEEDREPORT" v-if="model.projectBlocking.weatherReportEnable">
            <div class="edit-item flex-display flex-align-center flex-justify-between">
              <div class="white-color">风速<span class="describe">(天气预报) (1-15m/s)</span></div>
              <div class="form-option flex-display flex-align-center white-color">
                <div :class="{ w48: edit }">
                  <span v-if="!edit">{{ model.projectBlocking[FormWeather.WINDSPEEDREPORT] }}</span>
                  <a-input v-else v-model:value.number="FormWeatherModel[FormWeather.WINDSPEEDREPORT]"></a-input>
                </div>
                <span>m/s</span>
              </div>
            </div>
          </a-form-item>
          <a-form-item :name="FormWeather.RAIN">
            <div class="edit-item flex-display flex-align-center flex-justify-between">
              <div class="white-color">雨量<span class="describe">(雨量计/天气预报)</span></div>
              <div class="form-option flex-display flex-align-center white-color">
                <div :class="{ w60: edit }">
                  <span v-if="!edit">{{ WeatherEnum[model.projectBlocking[FormWeather.RAIN]] }}</span>
                  <Select :bordered="false" :options="rainSelect" v-model='FormWeatherModel[FormWeather.RAIN]' v-else />
                </div>
              </div>
            </div>
          </a-form-item>
        </a-form>
        <div class="btn-group" v-if="!edit">
          <a-button class="w96" type="primary" @click="() => edit = true">编辑</a-button>
        </div>
        <div class="btn-group" v-if="edit">
          <a-button class="mr20 w96" @click="cancel">取消</a-button>
          <a-button class='w96' type="primary" @click="submit">保存</a-button>
        </div>
      </div>
    </div>
  </div>
</template>
<script setup lang="ts">
import { defineProps, defineEmits } from 'vue'
import { cloneDeep } from 'lodash'
import { blocking } from '../type'
import { weatherRules, FormWeather, rainSelect, WeatherEnum, } from './type'
import { ValidateErrorEntity } from 'ant-design-vue/es/form/interface'
import Select from '/@/components/Search/Select.vue'
import { useVModel } from '/@/hooks/use-v-model'
interface FormState {
  [FormWeather.WINDSPEEDREPORT]: number
  [FormWeather.WINDSPEED]: number
  [FormWeather.RAIN]: number
}
const props = defineProps({
  modelValue: {
    type: Object,
    required: true
  },
})
const emit = defineEmits(['update:modelValue'])
const model = useVModel(props, 'modelValue', emit)
const edit = ref(false)
const weatherFormRef = ref()
const FormWeatherModel = ref<FormState>(cloneDeep(model.value.projectBlocking))
const submit = () => {
  weatherFormRef.value
    .validate()
    .then(() => {
      edit.value = false
      model.value.projectBlocking = { ...model.value.projectBlocking, ...FormWeatherModel.value }
    })
    .catch((error: ValidateErrorEntity<FormState>) => {
      console.log('error', error)
    })
}
const cancel = () => {
  FormWeatherModel.value = model.value.projectBlocking
  edit.value = false
}
</script>
<style scoped lang="scss">
.com_weather {
  padding: 16px;
  .option {
    &-item {
      border-bottom: 1px solid #4f4f4f;
      margin-bottom: 16px;
    }
    .form-option :deep(.ant-select-single .ant-select-selector) {
      background-color: inherit !important;
      color: #fff !important;
      padding: 0 !important;
    }
    .form-option :deep(.ant-select-arrow) {
      color: #fff;
    }
    // .form-option :deep(.)
  }
}
</style>
src/pages/page-web/projects/project_list/add_page/components/type.ts
New file
@@ -0,0 +1,48 @@
import { RuleObject, ValidateErrorEntity } from 'ant-design-vue/es/form/interface'
export enum FormWeather {
    WINDSPEED = 'windDevice',
    WINDSPEEDREPORT = 'windWeatherReport',
    RAIN = 'rain',
}
export enum WeatherEnum {
    '小雨' = 1,
    '中雨' = 2,
    '大雨' = 3
}
export const rainSelect = [
  {
    label: '小雨',
    value: 1,
  },
  {
    label: '中雨',
    value: 2,
  },
  {
    label: '大雨',
    value: 3,
  },
]
// export interface FormWeatherState {
//     [FormWeather.WINDSPEED]: number
//     [FormWeather.WINDSPEEDREPORT]: number
//     [FormWeather.RAIN]: string
// }
// export const formWeatherState = {
// }
export const weatherRules = {
  [FormWeather.WINDSPEED]: [
    { required: true, type: 'number', message: '请输入风速', trigger: 'blur' },
    { min: 1, max: 12, type: 'number', message: '风速有效值在1-12m/s之间' },
  ],
  [FormWeather.WINDSPEEDREPORT]: [
    { required: true, type: 'number', message: '请输入风速', trigger: 'blur' },
    { min: 1, max: 15, type: 'number', message: '风速有效值在1-15m/s之间' },
  ],
  [FormWeather.RAIN]: [
    { required: true, message: '请选择雨量', type: 'number', trigger: 'blur' },
  ],
}
src/pages/page-web/projects/project_list/add_page/type.ts
@@ -1,35 +1,123 @@
export enum FormProject{
    PROJECT_NAME = 'projectName',
    PROJECT_STATUS = 'projectStatus',
    PROJCECT_INTRO = 'projectIntro',
    LONGITUDE = 'longitude',
    LATITUDE = 'latitude',
    DEVICELIST = 'deviceList',
    USERLIST = 'userList',
    PROJECT_BLOCKING = 'projectBlocking',
export enum FormProject {
  PROJECT_NAME = 'projectName',
  PROJECT_STATUS = 'projectStatus',
  PROJCECT_INTRO = 'projectIntro',
  LONGITUDE = 'longitude',
  LATITUDE = 'latitude',
  DEVICELIST = 'deviceList',
  USERLIST = 'userList',
  PROJECT_BLOCKING = 'projectBlocking',
}
enum weather{
    '开启'=1,
    '关闭'=2
export enum blocking {
  WINDSPEED = 'windDevice',
  WINDSPEEDREPORT = 'windWeatherReport',
  RAIN = 'rain',
  CLOUDBLOCKINGCONFIGENABLE = 'cloudBlockingConfigEnable',
  WEATHERREPORTENABLE = 'weatherReportEnable',
}
enum weather {
  '开启' = 1,
  '关闭' = 2
}
interface deviceList {
    nickName:string
    deviceSource:number
    deviceType:number
    [key:string]:any
  nickName: string
  deviceSource: number
  deviceType: number
  [key: string]: any
}
interface projectBlocking {
    weatherBlockingConfigEnable:weather
    cloudBlockingConfigEnable:weather
  [blocking.WEATHERREPORTENABLE]?: weather
  [blocking.CLOUDBLOCKINGCONFIGENABLE]: weather
  [blocking.WINDSPEED]?: number
  [blocking.WINDSPEEDREPORT]?: number
  [blocking.RAIN]?: number
}
export interface FormState {
    [FormProject.PROJECT_NAME]: string
    [FormProject.PROJECT_STATUS]:string
    [FormProject.PROJCECT_INTRO]:string
    [FormProject.LONGITUDE]:number
    [FormProject.LATITUDE]:number
    [FormProject.DEVICELIST]?:deviceList[]
    [FormProject.USERLIST]:number[]
    [FormProject.PROJECT_BLOCKING]?:{}
  [FormProject.PROJECT_NAME]: string
  [FormProject.PROJECT_STATUS]: string
  [FormProject.PROJCECT_INTRO]: string
  [FormProject.LONGITUDE]: number
  [FormProject.LATITUDE]: number
  [FormProject.DEVICELIST]?: deviceList[]
  [FormProject.USERLIST]: number[]
  [FormProject.PROJECT_BLOCKING]: projectBlocking
}
/*
  项目成员表格
*/
export const Usercolumns = [
  {
    title: '人员项目呼号',
    dataIndex: 'name',
    key: 'name',
    ellipsis: true,
    slots: { customRender: 'name' },
  },
  {
    title: '项目角色',
    dataIndex: 'role',
    key: 'role',
    responsive: ['md'],
    ellipsis: true,
    slots: { customRender: 'role' },
  },
  {
    title: '编辑',
    dataIndex: 'edit',
    key: 'edit',
    responsive: ['lg'],
    width: '24%',
    ellipsis: true,
    slots: { customRender: 'operation' },
  },
]
export interface ProjectUser {
  key: string;
  name: string;
  role: number;
}
/*
  项目设备表格数据
*/
export const Devicecolumns = [
  {
    title: '项目设备呼号',
    dataIndex: 'device',
    key: 'device',
    ellipsis: true,
    slots: { customRender: 'device' },
  },
  {
    title: '设备型号',
    dataIndex: 'model',
    key: 'model',
    responsive: ['md'],
    ellipsis: true,
    slots: { customRender: 'model' },
  },
  {
    title: '编辑',
    dataIndex: 'edit',
    key: 'edit',
    responsive: ['lg'],
    width: '24%',
    ellipsis: true,
    slots: { customRender: 'operation' },
  },
]
export interface ProjectDevice {
  key: string;
  device: string;
  model: string;
}
// 校验表单规则
export const rules = {
  [FormProject.PROJECT_NAME]: [
    { required: true, message: '请输入项目名称', trigger: 'blur' },
  ],
}
src/styles/common.scss
@@ -6,6 +6,13 @@
.dis_opticy{
  opacity: .25;
}
.white-color {
  color: #fff;
}
.describe{
  font-size: 12px;
  color: hsla(0,0%,100%,.6);
}
body {
  background-color: #f7f9fa;
  -webkit-font-smoothing: antialiased;
src/styles/flex.style.scss
@@ -177,6 +177,20 @@
  margin-left: 10px !important;
}
.w48 {
  width: 48px;
}
.w60 {
  width: 60px;
}
.point {
  cursor: pointer;
}
.w96 {
  width: 96px;
}
.mr10 {
  margin-right: 10px !important;
}
yarn.lock
@@ -518,10 +518,10 @@
  "resolved" "https://registry.npm.taobao.org/@types/json5/download/@types/json5-0.0.29.tgz"
  "version" "0.0.29"
"@types/lodash@^4.14.165":
  "integrity" "sha512-0d5Wd09ItQWH1qFbEyQ7oTQ3GZrMfth5JkbN3EvTKLXcHLRDSXeLnlvlOn0wvxVIwK5o2M8JzP/OWz7T3NRsbw=="
  "resolved" "https://registry.npmmirror.com/@types/lodash/download/@types/lodash-4.14.178.tgz"
  "version" "4.14.178"
"@types/lodash@^4.14.165", "@types/lodash@^4.14.197":
  "integrity" "sha512-BMVOiWs0uNxHVlHBgzTIqJYmj+PgCo4euloGF+5m4okL3rEYzM2EEv78mw8zWSMM57dM7kVIgJ2QDvwHSoCI5g=="
  "resolved" "https://registry.npmmirror.com/@types/lodash/-/lodash-4.14.197.tgz"
  "version" "4.14.197"
"@types/node@*", "@types/node@^16.3.2", "@types/node@>= 14", "@types/node@>=13.7.0":
  "integrity" "sha512-BPAcfDPoHlRQNKktbsbnpACGdypPFBuX4xQlsWDE7B8XXcfII+SpOLay3/qZmCLb39kV5S1RTYwXdkx2lwLYng=="