applications/drone-command/src/views/system/user/FormDiaLog.vue
New file @@ -0,0 +1,451 @@ <template> <el-dialog v-model="visible" :title="titleEnum[dialogMode]" :close-on-click-modal="false" width="800px"> <!-- 查看模式 --> <div v-if="readonly" class="view-mode"> <el-row :gutter="16"> <el-col :span="12"> <div class="view-item"> <span class="label">登录账号:</span> {{ formData.account }} </div> </el-col> <el-col :span="12"> <div class="view-item"> <span class="label">用户姓名:</span> {{ formData.realName }} </div> </el-col> <el-col :span="12"> <div class="view-item"> <span class="label">手机号码:</span> {{ formData.phone }} </div> </el-col> <el-col :span="12"> <div class="view-item"> <span class="label">电子邮箱:</span> {{ formData.email }} </div> </el-col> <el-col :span="12"> <div class="view-item"> <span class="label">用户性别:</span> {{ getSexLabel(formData.sex) }} </div> </el-col> <el-col :span="12"> <div class="view-item"> <span class="label">用户生日:</span> {{ formData.birthday }} </div> </el-col> <el-col :span="12"> <div class="view-item"> <span class="label">所属角色:</span> {{ formData.roleName }} </div> </el-col> <el-col :span="12"> <div class="view-item"> <span class="label">所属部门:</span> {{ formData.deptName }} </div> </el-col> <el-col :span="12"> <div class="view-item"> <span class="label">用户编号:</span> {{ formData.code }} </div> </el-col> <el-col :span="12"> <div class="view-item"> <span class="label">账号状态:</span> {{ formData.statusName }} </div> </el-col> <el-col :span="12"> <div class="view-item"> <span class="label">到期时间:</span> {{ formData.expireTime }} </div> </el-col> <el-col :span="12"> <div class="view-item"> <span class="label">次数限制:</span> {{ formData.maxLoginNum }} </div> </el-col> <el-col :span="12"> <div class="view-item"> <span class="label">飞行开始时间:</span> {{ formData.flightStartTime }} </div> </el-col> <el-col :span="12"> <div class="view-item"> <span class="label">飞行结束时间:</span> {{ formData.flightEndTime }} </div> </el-col> </el-row> </div> <!-- 编辑/新增模式 --> <el-form v-else ref="formRef" :model="formData" :rules="rules" label-width="110px"> <el-divider content-position="left">基础信息</el-divider> <el-row :gutter="16"> <el-col :span="12"> <el-form-item label="登录账号" prop="account"> <el-input v-model="formData.account" maxlength="50" placeholder="请输入" clearable /> </el-form-item> </el-col> <el-col :span="12" v-if="dialogMode === 'add'"> <el-form-item label="密码" prop="password"> <el-input v-model="formData.password" type="password" maxlength="50" placeholder="请输入" clearable show-password /> </el-form-item> </el-col> <el-col :span="12" v-if="dialogMode === 'add'"> <el-form-item label="确认密码" prop="password2"> <el-input v-model="formData.password2" type="password" maxlength="50" placeholder="请输入" clearable show-password /> </el-form-item> </el-col> </el-row> <el-divider content-position="left">详细信息</el-divider> <el-row :gutter="16"> <el-col :span="12"> <el-form-item label="用户姓名" prop="realName"> <el-input v-model="formData.realName" maxlength="50" placeholder="请输入" clearable /> </el-form-item> </el-col> <el-col :span="12"> <el-form-item label="手机号码" prop="phone"> <el-input v-model="formData.phone" maxlength="20" placeholder="请输入" clearable /> </el-form-item> </el-col> <el-col :span="12"> <el-form-item label="电子邮箱" prop="email"> <el-input v-model="formData.email" maxlength="50" placeholder="请输入" clearable /> </el-form-item> </el-col> <el-col :span="12"> <el-form-item label="用户性别" prop="sex"> <el-select v-model="formData.sex" placeholder="请选择" clearable> <el-option label="男" :value="1" /> <el-option label="女" :value="2" /> <el-option label="未知" :value="3" /> </el-select> </el-form-item> </el-col> <el-col :span="12"> <el-form-item label="用户生日" prop="birthday"> <el-date-picker v-model="formData.birthday" type="datetime" placeholder="请选择" format="YYYY-MM-DD HH:mm:ss" value-format="YYYY-MM-DD HH:mm:ss" clearable /> </el-form-item> </el-col> </el-row> <el-divider content-position="left">职责信息</el-divider> <el-row :gutter="16"> <el-col :span="12"> <el-form-item label="用户编号" prop="code"> <el-input v-model="formData.code" maxlength="50" placeholder="请输入" clearable /> </el-form-item> </el-col> <el-col :span="12"> <el-form-item label="所属角色" prop="roleId"> <el-tree-select v-model="formData.roleId" :data="roleTree" :props="treeProps" node-key="id" check-strictly clearable placeholder="请选择" /> </el-form-item> </el-col> <el-col :span="12"> <el-form-item label="所属部门" prop="deptId"> <el-tree-select v-model="formData.deptId" :data="deptTree" :props="deptTreeSelectProps" node-key="id" check-strictly clearable placeholder="请选择" /> </el-form-item> </el-col> </el-row> <el-divider content-position="left">登录限制</el-divider> <el-row :gutter="16"> <el-col :span="12"> <el-form-item label="到期时间" prop="expireTime"> <el-date-picker v-model="formData.expireTime" type="datetime" placeholder="请选择" format="YYYY-MM-DD HH:mm:ss" value-format="YYYY-MM-DD HH:mm:ss" clearable /> </el-form-item> </el-col> <el-col :span="12"> <el-form-item label="次数限制" prop="maxLoginNum"> <el-input v-model="formData.maxLoginNum" placeholder="请输入" clearable /> </el-form-item> </el-col> <el-col :span="12"> <el-form-item label="飞行开始时间" prop="flightStartTime"> <el-time-picker v-model="formData.flightStartTime" placeholder="请选择" format="HH:mm" value-format="HH:mm" clearable /> </el-form-item> </el-col> <el-col :span="12"> <el-form-item label="飞行结束时间" prop="flightEndTime"> <el-time-picker v-model="formData.flightEndTime" placeholder="请选择" format="HH:mm" value-format="HH:mm" clearable /> </el-form-item> </el-col> </el-row> </el-form> <template #footer> <el-button @click="handleCancel">{{ readonly ? '关闭' : '取消' }}</el-button> <el-button v-if="!readonly" type="primary" :loading="submitting" :disabled="submitting" @click="handleSubmit"> 确定 </el-button> </template> </el-dialog> </template> <script setup> import { computed, onMounted, ref } from 'vue' import { ElMessage } from 'element-plus' import { getUser, add, update } from '@/api/system/user' import { getDeptTree } from '@/api/system/dept' import { getRoleTree } from '@/api/system/role' import func from '@/utils/func' // 初始化表单 const initForm = () => ({ account: '', password: '', password2: '', realName: '', phone: '', email: '', sex: null, birthday: '', code: '', roleId: '', deptId: '', expireTime: '', maxLoginNum: '', flightStartTime: '', flightEndTime: '', }) const treeProps = { label: 'title', children: 'children', } const deptTreeSelectProps = { label: 'name', value: 'id', children: 'children', } const emit = defineEmits(['success']) const formRef = ref(null) const formData = ref(initForm()) const visible = defineModel() const dialogMode = ref('add') const submitting = ref(false) const readonly = computed(() => dialogMode.value === 'view') const titleEnum = ref({ edit: '编辑用户', view: '查看用户', add: '新增用户' }) const roleTree = ref([]) const deptTree = ref([]) // 密码验证 const validatePass = (rule, value, callback) => { if (value === '') { callback(new Error('请输入密码')) } else { callback() } } const validatePass2 = (rule, value, callback) => { if (value === '') { callback(new Error('请再次输入密码')) } else if (value !== formData.value.password) { callback(new Error('两次输入密码不一致!')) } else { callback() } } const rules = { account: [{ required: true, message: '请输入登录账号', trigger: 'blur' }], password: [{ required: true, validator: validatePass, trigger: 'blur' }], password2: [{ required: true, validator: validatePass2, trigger: 'blur' }], realName: [ { required: true, message: '请输入用户姓名', trigger: 'blur' }, { min: 2, max: 50, message: '姓名长度在2到50个字符', trigger: 'blur' }, ], roleId: [{ required: true, message: '请选择所属角色', trigger: 'change' }], deptId: [{ required: true, message: '请选择所属部门', trigger: 'change' }], } // 获取性别标签 function getSexLabel(sex) { const map = { 1: '男', 2: '女', 3: '未知' } return map[sex] || '' } // 获取角色树 async function getRoleTreeData() { const res = await getRoleTree('000000') roleTree.value = res.data.data } // 获取部门树 async function getDeptTreeData() { const res = await getDeptTree('000000') deptTree.value = res.data.data } // 关闭弹框 function handleCancel() { visible.value = false } // 验证飞行时间 function validateFlightTime() { if (formData.value.flightStartTime && formData.value.flightEndTime) { const [startHours, startMinutes] = formData.value.flightStartTime.split(':').map(Number) const [endHours, endMinutes] = formData.value.flightEndTime.split(':').map(Number) const startTotalMinutes = startHours * 60 + startMinutes const endTotalMinutes = endHours * 60 + endMinutes if (endTotalMinutes < startTotalMinutes) { ElMessage.error('飞行结束时间不能小于飞行开始时间') return false } } return true } // 提交新增/编辑 async function handleSubmit() { const isValid = await formRef.value?.validate().catch(() => false) if (!isValid) return if (!validateFlightTime()) return submitting.value = true try { const submitData = { ...formData.value } submitData.roleId = func.toStr(submitData.roleId) submitData.name = submitData.realName if (dialogMode.value === 'add') { await add(submitData) ElMessage.success('新增成功') } else { await update(submitData) ElMessage.success('更新成功') } visible.value = false emit('success') } finally { submitting.value = false } } // 加载详情 async function loadDetail() { if (!formData.value.id) return const res = await getUser(formData.value.id) const data = res?.data?.data ?? {} // 处理 roleId if (data.roleId) { data.roleId = func.split(data.roleId)[0] || data.roleId } formData.value = data } // 打开弹框 async function open({ mode, row } = {}) { dialogMode.value = mode || 'add' if (dialogMode.value === 'add') { formData.value = initForm() } else { formData.value = { id: row.id } await loadDetail() } } onMounted(() => { getRoleTreeData() getDeptTreeData() }) defineExpose({ open }) </script> <style scoped lang="scss"> .view-mode { .view-item { padding: 10px 0; .label { color: #606266; font-weight: 500; } } } :deep(.el-select) { width: 100%; } :deep(.el-date-editor) { width: 100%; } :deep(.el-tree-select) { width: 100%; } </style> applications/drone-command/src/views/system/user/index.vue
New file @@ -0,0 +1,504 @@ <template> <basic-container> <!-- 左侧部门树 --> <el-row :gutter="16" class="user-container"> <el-col :span="4"> <div class="tree-box"> <el-scrollbar> <el-tree :data="deptTree" :props="deptTreeProps" node-key="id" :load="loadDeptTree" lazy @node-click="handleDeptNodeClick" /> </el-scrollbar> </div> </el-col> <!-- 右侧列表区 --> <el-col :span="20"> <!-- 搜索表单 --> <el-form ref="queryParamsRef" :model="searchParams"> <el-row :gutter="16"> <el-col :span="5"> <el-form-item label="登录账号" prop="account"> <el-input v-model="searchParams.account" placeholder="请输入" clearable @clear="handleSearch" /> </el-form-item> </el-col> <el-col :span="5"> <el-form-item label="用户姓名" prop="realName"> <el-input v-model="searchParams.realName" placeholder="请输入" clearable @clear="handleSearch" /> </el-form-item> </el-col> <el-col :span="4"> <el-form-item> <el-button @click="resetForm">重置</el-button> <el-button type="primary" @click="handleSearch">查询</el-button> </el-form-item> </el-col> </el-row> </el-form> <!-- 操作按钮 --> <div class="btn-group"> <el-button v-if="permission.user_add && !auditMode" type="primary" @click="openForm('add')">新增</el-button> <el-button v-if="permission.user_delete && !auditMode" type="danger" :disabled="!selectedIds.length" @click="handleDelete()" > 删除 </el-button> <el-button v-if="userInfo.role_name?.includes('admin') && auditMode" type="success" :disabled="!selectedIds.length" @click="handleAuditPass" > 通过 </el-button> <el-button v-if="userInfo.role_name?.includes('admin') && auditMode" type="danger" :disabled="!selectedIds.length" @click="handleAuditRefuse" > 拒绝 </el-button> <el-button v-if="userInfo.role_name?.includes('admin') && auditMode" type="primary" plain @click="handleAuditBack" > 返回 </el-button> <el-button v-if="permission.user_role && !auditMode" type="info" plain :disabled="!selectedIds.length" @click="handleGrant" > 角色配置 </el-button> <el-button v-if="permission.user_reset && !auditMode" type="info" plain :disabled="!selectedIds.length" @click="handleReset" > 密码重置 </el-button> <el-button v-if="userInfo.role_name?.includes('admin') && !auditMode" type="info" plain :disabled="!selectedIds.length" @click="handleLock" > 账号解封 </el-button> <el-button v-if="userInfo.role_name?.includes('admin') && !auditMode" type="success" plain @click="handleImport" > 导入 </el-button> <el-button v-if="userInfo.role_name?.includes('admin') && !auditMode" type="warning" plain @click="handleExport" > 导出 </el-button> </div> <!-- 用户列表 --> <el-table v-loading="loading" :data="list" @selection-change="handleSelectionChange"> <el-table-column type="selection" width="55" /> <el-table-column type="index" width="60" label="序号" /> <el-table-column prop="account" label="登录账号" /> <el-table-column prop="realName" label="用户姓名" /> <el-table-column prop="roleName" label="所属角色"> <template v-slot="{ row }"> <el-tag v-if="row.roleName">{{ row.roleName }}</el-tag> </template> </el-table-column> <el-table-column prop="deptName" label="所属部门"> <template v-slot="{ row }"> <el-tag v-if="row.deptName">{{ row.deptName }}</el-tag> </template> </el-table-column> <el-table-column prop="phone" label="手机号码" /> <el-table-column label="操作" width="180"> <template v-slot="{ row }"> <el-link v-if="permission.user_view" @click="openForm('view', row)" type="primary">查看</el-link> <el-link v-if="permission.user_edit && !auditMode" @click="openForm('edit', row)" type="warning"> 编辑 </el-link> <el-link v-if="permission.user_delete && !auditMode" @click="handleDelete(row)" type="danger"> 删除 </el-link> </template> </el-table-column> </el-table> <!-- 分页 --> <div> <el-pagination v-model:current-page="searchParams.current" v-model:page-size="searchParams.size" :total="total" @change="getList" /> </div> </el-col> </el-row> <!-- 用户表单弹框 --> <FormDiaLog v-if="dialogVisible" v-model="dialogVisible" ref="dialogRef" @success="getList" /> <!-- 角色配置弹框 --> <el-dialog title="用户角色配置" append-to-body v-model="roleBox" width="345px"> <el-tree :data="roleGrantList" show-checkbox check-strictly default-expand-all node-key="id" ref="treeRoleRef" :default-checked-keys="roleTreeObj" :props="roleProps" ></el-tree> <template #footer> <span class="dialog-footer"> <el-button @click="roleBox = false">取 消</el-button> <el-button type="primary" @click="submitRole">确 定</el-button> </span> </template> </el-dialog> <!-- 导入弹框 --> <el-dialog title="用户数据导入" append-to-body v-model="excelBox" width="555px"> <el-form :model="excelForm" label-width="100px"> <el-form-item label="数据覆盖"> <el-switch v-model="excelForm.isCovered" :active-value="1" :inactive-value="0" /> </el-form-item> <el-form-item label="模板上传"> <el-upload :action="uploadAction" :on-success="handleUploadSuccess" accept=".xls,.xlsx" :show-file-list="false" > <el-button type="primary">点击上传</el-button> </el-upload> <div class="upload-tip">请上传 .xls,.xlsx 标准格式文件</div> </el-form-item> <el-form-item label="模板下载"> <el-button type="primary" @click="handleTemplate">点击下载</el-button> </el-form-item> </el-form> </el-dialog> </basic-container> </template> <script setup> import { computed, nextTick, onMounted, ref } from 'vue' import { ElMessage, ElMessageBox } from 'element-plus' import { useStore } from 'vuex' import FormDiaLog from './FormDiaLog.vue' import { getList as getListApi, remove, grant, resetPassword, unlock, auditPass, auditRefuse } from '@/api/system/user' import { exportBlob } from '@/api/common' import { getDeptTree, getDeptLazyTree } from '@/api/system/dept' import { getRoleTree } from '@/api/system/role' import website from '@/config/website' import { getToken } from '@/utils/auth' import { downloadXls } from '@/utils/util' import NProgress from 'nprogress' import 'nprogress/nprogress.css' import func from '@/utils/func' const store = useStore() const userInfo = computed(() => store.getters.userInfo) const permission = computed(() => store.getters.permission) // 初始化搜索参数 const initSearchParams = () => ({ account: '', realName: '', current: 1, size: 10, }) const searchParams = ref(initSearchParams()) const total = ref(0) const loading = ref(false) const list = ref([]) const selectedIds = ref([]) const selectionList = ref([]) const queryParamsRef = ref(null) const dialogRef = ref(null) const dialogVisible = ref(false) const auditMode = ref(false) const treeDeptId = ref('') // 部门树 const deptTree = ref([]) const deptTreeProps = { label: 'title', children: 'children', isLeaf: 'leaf', } // 角色配置 const roleBox = ref(false) const roleGrantList = ref([]) const roleTreeObj = ref([]) const treeRoleRef = ref(null) const roleProps = { label: 'title', value: 'key', } // 导入相关 const excelBox = ref(false) const excelForm = ref({ isCovered: 0, }) const uploadAction = computed(() => `/blade-system/user/import-user?isCovered=${excelForm.value.isCovered}`) provide('treeDeptId', treeDeptId) // 加载部门树节点 async function loadDeptTree(node, resolve) { const parentId = node.level === 0 ? 0 : node.data.id const param = { parentId: parentId, level: node.level, } const res = await getDeptLazyTree(param) resolve( res.data.data.map(item => ({ ...item, leaf: !item.hasChildren, })) ) } // 部门节点点击 function handleDeptNodeClick(data) { treeDeptId.value = data.id searchParams.value.current = 1 getList() } // 获取列表 async function getList() { loading.value = true try { const res = await getListApi( searchParams.value.current, searchParams.value.size, { account: searchParams.value.account, realName: searchParams.value.realName, status: auditMode.value ? 0 : 1, }, treeDeptId.value ) list.value = res?.data?.data?.records ?? [] total.value = res?.data?.data?.total ?? 0 } finally { loading.value = false } } // 查询 function handleSearch() { searchParams.value.current = 1 getList() } // 重置查询 function resetForm() { queryParamsRef.value?.resetFields() searchParams.value = initSearchParams() treeDeptId.value = '' getList() } // 删除 async function handleDelete(row) { const tips = row ? '该条' : '选中的项' await ElMessageBox.confirm(`确认删除${tips}吗?`, '提示', { type: 'warning' }) const ids = row ? row.id : selectedIds.value.join(',') await remove(ids) ElMessage.success('删除成功') selectedIds.value = [] getList() } // 勾选值设置 function handleSelectionChange(rows) { selectionList.value = rows selectedIds.value = rows.map(item => item.id) } // 角色配置 async function handleGrant() { if (selectedIds.value.length === 0) { ElMessage.warning('请选择至少一条数据') return } roleTreeObj.value = [] if (selectionList.value.length === 1) { roleTreeObj.value = selectionList.value[0].roleId?.split(',') || [] } const res = await getRoleTree() roleGrantList.value = res.data.data roleBox.value = true } // 提交角色配置 async function submitRole() { const roleList = treeRoleRef.value.getCheckedKeys().join(',') await grant(selectedIds.value.join(','), roleList) roleBox.value = false ElMessage.success('操作成功') getList() } // 密码重置 async function handleReset() { if (selectedIds.value.length === 0) { ElMessage.warning('请选择至少一条数据') return } await ElMessageBox.confirm('确定将选择账号密码重置为123456?', '提示', { type: 'warning' }) await resetPassword(selectedIds.value.join(',')) ElMessage.success('操作成功') } // 账号解封 async function handleLock() { if (selectedIds.value.length === 0) { ElMessage.warning('请选择至少一条数据') return } await ElMessageBox.confirm('确定将选择账号解封?', '提示', { type: 'warning' }) await unlock(selectedIds.value.join(',')) ElMessage.success('操作成功') } // 审核通过 async function handleAuditPass() { if (selectedIds.value.length === 0) { ElMessage.warning('请选择至少一条数据') return } await ElMessageBox.confirm('确定将选择数据通过审核?', '提示', { type: 'warning' }) await auditPass(selectedIds.value.join(',')) ElMessage.success('操作成功') getList() } // 审核拒绝 async function handleAuditRefuse() { if (selectedIds.value.length === 0) { ElMessage.warning('请选择至少一条数据') return } await ElMessageBox.confirm('确定将选择数据拒绝审核?', '提示', { type: 'warning' }) await auditRefuse(selectedIds.value.join(',')) ElMessage.success('操作成功') getList() } // 返回正常模式 function handleAuditBack() { auditMode.value = false getList() } // 导入 function handleImport() { excelBox.value = true } // 上传成功 function handleUploadSuccess() { excelBox.value = false getList() ElMessage.success('导入成功') } // 导出 function handleExport() { const account = func.toStr(searchParams.value.account) const realName = func.toStr(searchParams.value.realName) ElMessageBox.confirm('是否导出用户数据?', '提示', { type: 'warning' }).then(() => { NProgress.start() exportBlob( `/blade-system/user/export-user?${website.tokenHeader}=${getToken()}&account=${account}&realName=${realName}` ).then(res => { downloadXls(res.data, `用户数据表${new Date().toISOString().slice(0, 10)}.xlsx`) NProgress.done() }) }) } // 下载模板 function handleTemplate() { exportBlob(`/blade-system/user/export-template?${website.tokenHeader}=${getToken()}`).then(res => { downloadXls(res.data, '用户数据模板.xlsx') }) } // 新增/编辑/查看 弹框 function openForm(mode, row) { dialogVisible.value = true nextTick(() => { dialogRef.value?.open({ mode, row }) }) } onMounted(() => { getList() }) </script> <style scoped lang="scss"> .user-container { height: 100%; } .tree-box { height: 100%; padding: 10px; border-radius: 5px; background-color: #fff; box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1); :deep(.el-scrollbar) { height: 100%; } } .btn-group { margin-bottom: 16px; } .upload-tip { color: #999; font-size: 12px; margin-top: 8px; } </style> uniapps/work-wx/src/pages.json
@@ -11,8 +11,7 @@ { "path": "pages/page/index", "style": { "navigationBarTitleText": "首页", "navigationStyle": "custom" "navigationBarTitleText": "首页" } }, { @@ -24,23 +23,20 @@ { "path": "pages/equipmentManagement/index", "style": { "navigationBarTitleText": "设备管理", "navigationStyle": "custom" "navigationBarTitleText": "设备管理" } }, { "path": "pages/legalPolicy/index", "style": { "navigationBarTitleText": "法律政策", "navigationStyle": "custom" "navigationBarTitleText": "法律政策" } }, { "path": "pages/user/index", "style": { "navigationBarTitleText": "我的", "navigationStyle": "custom" "navigationBarTitleText": "我的" } }, { @@ -101,13 +97,6 @@ } }, { "path": "workDetail/mapWork/index", "style": { "navigationBarTitleText": "地图展示", "navigationStyle": "custom" } }, { "path": "userDetail/infos/index", "style": { "navigationBarTitleText": "个人资料" @@ -135,26 +124,26 @@ "backgroundColor": "#ffffff", "list": [ { "iconPath": "static/images/tabbar/icon_order.png", "selectedIconPath": "static/images/tabbar/icon_order_selected.png", "iconPath": "static/images/tabbar/home.png", "selectedIconPath": "static/images/tabbar/home-selected.png", "pagePath": "pages/page/index", "text": "首页" }, { "iconPath": "static/images/tabbar/icon_order.png", "selectedIconPath": "static/images/tabbar/icon_order_selected.png", "iconPath": "static/images/tabbar/sbgl.png", "selectedIconPath": "static/images/tabbar/sbgl-selected.png", "pagePath": "pages/equipmentManagement/index", "text": "设备管理" }, { "iconPath": "static/images/tabbar/icon_home1.png", "selectedIconPath": "static/images/tabbar/icon_home_selected.png", "iconPath": "static/images/tabbar/flzc.png", "selectedIconPath": "static/images/tabbar/flzc-selected.png", "pagePath": "pages/legalPolicy/index", "text": "法律政策" }, { "iconPath": "static/images/tabbar/icon_me.png", "selectedIconPath": "static/images/tabbar/icon_me_selected.png", "iconPath": "static/images/tabbar/my.png", "selectedIconPath": "static/images/tabbar/my-selected.png", "pagePath": "pages/user/index", "text": "我的" } uniapps/work-wx/src/pages/equipmentManagement/index.vue
@@ -24,8 +24,8 @@ <script setup> import { reactive, ref } from 'vue' import lbPng from '@/static/images/lb.png' import addSvg from '@/static/images/add.svg' import droneSvg from '@/static/images/drone.svg' import addSvg from '@/static/images/add.png' import droneSvg from '@/static/images/drone.png' import { myDevicePageInfoApi, aircraftInfoPageInfoOfMyApi } from '@/api/index.js' const equipmentList = ref([]) const noticeTitle = ref('') @@ -35,11 +35,10 @@ try { const res = await aircraftInfoPageInfoOfMyApi({ current: 1, size: 10, size: 99, model:'', name: '', }) console.log(8888888,res.data.data.records) equipmentList.value = res.data.data.records || [] } catch (error) { console.error('获取设备列表失败:', error) @@ -73,7 +72,7 @@ height: 100%; display: flex; flex-direction: column; .u-search { :deep(.u-search) { padding: 10px 20px; height: 68rpx; flex: 0; uniapps/work-wx/src/pages/legalPolicy/index.vue
@@ -96,7 +96,7 @@ display: flex; flex-direction: column; .u-search { :deep(.u-search) { padding: 10px 20px; height: 68rpx; flex: 0; uniapps/work-wx/src/pages/login/index.vue
@@ -9,24 +9,25 @@ <input v-model="loginForm.username" placeholder="请输入用户名" /> </div> <div class="pass-word"> <input v-model="loginForm.password" :type="isShowPassword ? 'text' : 'password'" placeholder="请输入密码"/> <u-input type="password" border="bottom" v-model="loginForm.password" placeholder="请输入密码"></u-input> <!-- <input v-model="loginForm.password" :type="isShowPassword ? 'text' : 'password'" placeholder="请输入密码"/> <image v-if="!isShowPassword" :src="showPasswordSvg" @click="isShowPassword = !isShowPassword" /> <image v-else :src="showPsdSvg" @click="isShowPassword = !isShowPassword" /> <image v-else :src="showPsdSvg" @click="isShowPassword = !isShowPassword" /> --> </div> </view> <div class="remember-password"> <view class="remember"> <checkbox-group @change="toggleRemember"> <!-- <checkbox-group @change="toggleRemember"> <checkbox :checked="rememberPassword" color="#1D6FE9" style="transform: scale(0.7)" /> </checkbox-group> 记住密码 记住密码 --> </view> <view class="forget"> 忘记密码 <view class="forget" @click="forgetClick"> 忘记密码? </view> </div> <button class="login-btn" :style="[inputStyle]" @tap="submit">登录</button> @@ -43,10 +44,8 @@ import { HOME_PATH, LOGIN_PATH, removeQueryString } from "@/router"; import { ref } from "vue"; import logoSvg from "@/static/images/logo.svg"; import droneLogSvg from "@/static/images/user/droneLogo.svg"; import showPsdSvg from "@/static/images/user/showPsd.svg"; import showPasswordSvg from "@/static/images/show-password.svg"; import logoSvg from "@/static/images/logo.png"; import droneLogSvg from "@/static/images/user/droneLogo.png"; const droneSvg = getAssetsImage("/images/login/droneSvg.svg"); const usernameSvg = getAssetsImage("/images/login/username.svg"); @@ -151,6 +150,12 @@ }); } function forgetClick() { uni.navigateTo({ url: "/subPackages/userDetail/password/index", }); } // 从本地存储加载记住的密码 onMounted(() => { const savedUserInfo = uni.getStorageSync("rememberedUser"); @@ -176,8 +181,8 @@ width: 100%; .logo { width: 127px; height: 51px; width: 67px; height: 67px; margin: 0 auto; margin-top: 162px; margin-bottom: 16px; uniapps/work-wx/src/pages/page/index.vue
@@ -71,10 +71,10 @@ <script setup> import { onMounted, reactive, ref } from 'vue' import lbPng from '@/static/images/lb.png' import kyxxPng from '@/static/images/kyxx.svg' import fxsqPng from '@/static/images/fxsq.svg' import flfgPng from '@/static/images/flfg.svg' import zczdPng from '@/static/images/zczd.svg' import kyxxPng from '@/static/images/kyxx.png' import fxsqPng from '@/static/images/fxsq.png' import flfgPng from '@/static/images/flfg.png' import zczdPng from '@/static/images/zczd.png' import docSvg from '@/static/images/doc.png' import { sysNoticePageInfoApi, flightAirspacePageInfoApi } from '@/api/index' const lbList = reactive([]); @@ -225,8 +225,8 @@ height: 100%; display: flex; flex-direction: column; .u-grid { margin-top: 20px; :deep(.u-grid) { margin-top: 40rpx; .grid-text { font-family: Source Han Sans CN, Source Han Sans CN; font-weight: 500; uniapps/work-wx/src/pages/register/index.vue
@@ -4,7 +4,7 @@ <view class="pageBg"></view> <view class="content"> <view class="row"> <view class="label"><span>*</span>手机号码</view> <view class="label"><span class="required">*</span>手机号码</view> <view class="input"> <u-input input-align="right" border="bottom" v-model="formParams.userName" placeholder="请输入手机号码"></u-input> </view> @@ -16,23 +16,23 @@ </view> </view> <view class="row"> <view class="label"><span>*</span>密码</view> <view class="label"><span class="required">*</span>密码</view> <view class="input"> <u-input type="password" input-align="right" border="bottom" v-model="formParams.password" placeholder="请输入密码"></u-input> </view> </view> <view class="row"> <view class="label"><span>*</span>确认密码</view> <view class="label"><span class="required">*</span>确认密码</view> <view class="input"> <u-input type="password" input-align="right" border="bottom" v-model="formParams.password2" placeholder="请确认密码"></u-input> </view> </view> <view class="row"> <view class="label"><span>*</span>验证码</view> <view class="label"><span class="required">*</span>验证码</view> <view class="input"> <u-input input-align="right" border="bottom" v-model="formParams.code" placeholder="请输入验证码"></u-input> </view> <u-button class="getCode" :disabled="countDown > 0" @click="sendVerificationCode" type="primary" color="#007AFF"> <u-button :disabled="countDown > 0" @click="sendVerificationCode" type="primary" color="#007AFF"> {{ countDown > 0 ? `${countDown}s后重发` : '获取验证码' }} </u-button> </view> @@ -214,7 +214,7 @@ left: 0; width: 100%; height: 100%; background: url("@/static/images/user/userbg.svg") no-repeat ; background-image: url("../../static/images/user/userbg.svg") no-repeat ; background-size: 100%; } .content { @@ -238,7 +238,7 @@ font-weight: 400; font-size: 15px; color: #222324; span { .required { color: #FF4444; } } @@ -251,15 +251,19 @@ :deep(.u-icon--right) { display: none; } .getCode { :deep(.u-button) { width: 180rpx; } } .register { position: fixed; left: 24rpx; right: 24rpx; bottom: 126rpx; :deep(.u-button) { position: fixed; left: 24rpx; right: 24rpx; bottom: 126rpx; width: 80% !important; height: 100rpx !important; } } } </style> uniapps/work-wx/src/pages/user/index.vue
@@ -55,7 +55,7 @@ import { getDeviceRegionApi } from "@/api/map.js"; import defaultAvatar from '/static/images/defaultAvatar.svg' import rightImage from '@/static/images/user/rightBtn.svg'; import showDefaultHeader from "@/static/images/user/default-header.svg"; import showDefaultHeader from "@/static/images/user/default-header.png"; const { setClipboardData, getClipboardData } = useClipboard(); // // const rightImage = getAssetsImage("/images/user/rightBtn.svg"); @@ -100,7 +100,7 @@ height: 100%; } .pageUser { background: url("@/static/images/user/userbg.svg") no-repeat; background-image: url("../../static/images/user/userbg.svg") no-repeat; background-size: 100%; } .userBox { uniapps/work-wx/src/static/images/fly-apply.svg
File was deleted uniapps/work-wx/src/static/images/logo.pnguniapps/work-wx/src/static/images/user/droneLogo.png
uniapps/work-wx/src/static/images/zczd.svg
File was deleted uniapps/work-wx/src/subPackages/deviceRegistration/add.vue
@@ -220,53 +220,54 @@ placeholder="请输入" ></u-input> </u-form-item> <u-button class="submit-button-wrapper" color="#1D6FE9" size="large" @click="submitForm"> 注册 </u-button> <!-- 飞行器型号 --> <u-picker :show="showType" :columns="[typeList]" keyName="label" @confirm="onPickerConfirmType" @cancel="showType = false" /> <!-- 飞行器厂商 --> <u-picker :show="showManufacturer" :columns="[manufacturerList]" keyName="label" @confirm="onPickerConfirmManufacturer" @cancel="showManufacturer = false" /> <u-picker :show="showIsModified" :columns="[actionsModified]" keyName="label" @confirm="onPickerConfirm" @cancel="showIsModified = false" /> <u-picker :show="showHasInsurance" :columns="[actionsHasInsurance]" keyName="label" @confirm="onPickerConfirmHasInsurance" @cancel="showHasInsurance = false" /> <u-datetime-picker :show="showPurchaseDate" v-model="birthdayValue" mode="date" @confirm="onPurchaseDate" @cancel="showPurchaseDate = false" /> <!-- 所属区域 --> <u-cascader show="show" v-model="value" :data="areaData" ></u-cascader> <!-- 飞行器型号 --> <u-picker :show="showType" :columns="[typeList]" keyName="label" @confirm="onPickerConfirmType" @cancel="showType = false" /> <!-- 飞行器厂商 --> <u-picker :show="showManufacturer" :columns="[manufacturerList]" keyName="label" @confirm="onPickerConfirmManufacturer" @cancel="showManufacturer = false" /> <u-picker :show="showIsModified" :columns="[actionsModified]" keyName="label" @confirm="onPickerConfirm" @cancel="showIsModified = false" /> <u-picker :show="showHasInsurance" :columns="[actionsHasInsurance]" keyName="label" @confirm="onPickerConfirmHasInsurance" @cancel="showHasInsurance = false" /> <u-datetime-picker :show="showPurchaseDate" v-model="birthdayValue" mode="date" @confirm="onPurchaseDate" @cancel="showPurchaseDate = false" /> <!-- 所属区域 --> <u-cascader show="show" v-model="value" :data="areaData" ></u-cascader> </u-form> <u-button @click="submitForm" color="#1D6FE9">提交</u-button> <!-- <u-button class="submit-button-wrapper" color="#1D6FE9" size="large" @click="submitForm"> 注册 </u-button> --> </view> </template> <script setup> @@ -585,9 +586,11 @@ padding: 24rpx; } .submit-button-wrapper { :deep(.u-button) { width: 80%; padding: 28rpx; border-radius: 8rpx 8rpx 8rpx 8rpx; margin-bottom: 20rpx; } :deep(.u-form-item) { uniapps/work-wx/src/subPackages/flightApplication/add.vue
@@ -290,13 +290,9 @@ ></up-icon> </template> </u-form-item> <u-button class="submit-button-wrapper" color="#1D6FE9" size="large" @click="submitForm"> <!-- <u-button class="submit-button-wrapper" color="#1D6FE9" size="large" @click="submitForm"> 飞行申请 </u-button> <!-- 飞任务类型 --> <view class="attention"> 注:新增空域/航线/飞手等前往吉安市低空经济服务一体化 </view> </u-button> --> <u-picker :show="isShowFlightTaskType" :columns="[actionsFlightTaskType]" @@ -377,7 +373,11 @@ @cancel="isShowFlightRouteInfo = false" /> </u-form> <u-button @click="submitForm" color="#1D6FE9">飞行申请</u-button> <!-- 飞任务类型 --> <view class="attention"> 注:新增空域/航线/飞手等前往吉安市低空经济服务一体化 </view> </view> </template> <script setup> @@ -751,6 +751,20 @@ margin-bottom: 24rpx; padding-left: 0rpx !important; } :deep(.u-button) { width: 80%; padding: 28rpx; border-radius: 8rpx 8rpx 8rpx 8rpx; margin-bottom: 20rpx; } .attention { font-family: Source Han Sans CN, Source Han Sans CN; font-weight: 400; font-size: 12px; color: #1D6FE9; // margin-top: 24rpx; text-align: center; } .select-wrapper { position: relative; width: 100%; @@ -785,13 +799,6 @@ // width: 80%; // height: 100rpx; border-radius: 8rpx 8rpx 8rpx 8rpx; } .attention { font-family: Source Han Sans CN, Source Han Sans CN; font-weight: 400; font-size: 12px; color: #1D6FE9; margin-top: 24rpx; } :deep(.u-form-item) { margin-bottom: 40rpx; uniapps/work-wx/src/subPackages/flightApplication/index.vue
@@ -33,10 +33,10 @@ </view> </template> <script setup> import spSvg from '@/static/images/sp.svg' import spSvg from '@/static/images/sp.png' import { flightPlanPageInfoApi } from '@/api/index.js' import fxsqSvg from '@/static/images/fly-apply.svg' import mysbSvg from '@/static/images/my-sb.svg' import fxsqSvg from '@/static/images/fly-apply.png' import mysbSvg from '@/static/images/my-sb.png' import { ref } from 'vue' @@ -130,7 +130,7 @@ .header-top { width: 100%; height: 350rpx; background: url('@/static/images/fxsq-bg.png') no-repeat center center; background: url('@/static/images/fxsq-bg.png') no-repeat center; background-size: 100% 100%; position: fixed; top: 0; @@ -170,7 +170,7 @@ } } } .u-search { :deep(.u-search) { position: absolute; width: 90%; left: 50%; uniapps/work-wx/src/subPackages/regulationsDetail/copy.vue
File was deleted uniapps/work-wx/src/subPackages/userDetail/infos/index.vue
@@ -41,7 +41,7 @@ </template> <script setup> import showDefaultHeader from "@/static/images/user/default-header.svg"; import showDefaultHeader from "@/static/images/user/default-header.png"; import { getEnvObj, getWebViewUrl @@ -252,7 +252,7 @@ left: 0; width: 100%; height: 100%; background: url("@/static/images/user/userbg.svg") no-repeat ; background-image: url("../../../static/images/user/userbg.svg") no-repeat ; background-size: 100%; } .avatarBox { uniapps/work-wx/src/subPackages/userDetail/password/index.vue
@@ -1,6 +1,6 @@ <!-- 修改密码 --> <template> <view class="container"> <view class="user-password"> <view class="pageBg"></view> <view class="detailBox"> <div class="detailCon"> @@ -20,7 +20,7 @@ <div class="orderRow"> <div class="rowTitle">验证码</div> <input type="text" v-model="passwordForm.code" placeholder="请输入验证码" class="input-item" /> <u-button class="getCode" :disabled="countDown > 0" @click="sendVerificationCode" type="primary" color="#007AFF"> <u-button :disabled="countDown > 0" @click="sendVerificationCode" type="primary" color="#007AFF"> {{ countDown > 0 ? `${countDown}s后重发` : '获取验证码' }} </u-button> </div> @@ -34,6 +34,7 @@ </template> <script setup> import userbgSvg from "@/static/images/user/userbg.svg"; import { useUserStore } from "@/store/index.js"; @@ -246,126 +247,125 @@ </script> <style lang="scss" scoped> .container { .user-password { width: 100%; height: 100%; display: flex; flex-direction: column; align-items: center; position: relative; } .pageBg { position: fixed; top: 0; left: 0; width: 100%; height: 100%; background: url("@/static/images/user/userbg.svg") no-repeat ; background-size: 100%; } .detailBox { position: absolute; top: 180rpx; // margin-top: 40rpx; width: 702rpx; min-height: 326rpx; background: #FFFFFF; border-radius: 12rpx; box-shadow: 0 4rpx 20rpx rgba(0, 0, 0, 0.05); .detailCon { padding: 0 24rpx; .pageBg { position: fixed; top: 0; left: 0; width: 100%; height: 100%; background-image: url("https://wrj.shuixiongit.com/aiskyminio/cloud-bucket/ztzf_app_assets/images/user/bg.png"); background-size: 100%; } .orderRow { .detailBox { position: absolute; top: 180rpx; // margin-top: 40rpx; width: 702rpx; min-height: 326rpx; background: #FFFFFF; border-radius: 12rpx; box-shadow: 0 4rpx 20rpx rgba(0, 0, 0, 0.05); .detailCon { padding: 0 24rpx; } .orderRow { display: flex; justify-content: space-between; align-items: center; height: 96rpx; border-bottom: 2rpx solid #f5f5f5; color: #7b7b7b; .rowTitle { font-family: Source Han Sans CN, Source Han Sans CN; font-weight: 400; font-size: 30rpx; color: #222324; white-space: nowrap; } input.input-item { text-align: right; border: none !important; background: transparent !important; box-shadow: none !important; padding: 0 !important; margin: 0 !important; height: auto !important; outline: none; font-size: 30rpx; color: #222324; font-family: Source Han Sans CN, Source Han Sans CN; } :deep(.uni-input-placeholder) { color: #D5D5D5; } input.input-item::placeholder { font-size: 30rpx; } // .code-container { // display: flex; // align-items: center; // justify-content: flex-end; // width: 100%; // } .send-code-btn { margin-left: 20rpx; width: 200rpx; height: 70rpx; line-height: 70rpx; font-size: 26rpx; background: #f5f5f5; color: #666; border-radius: 8rpx; } .send-code-btn:disabled { background: #e0e0e0; color: #999; } :deep(.u-button){ width: 180rpx !important; height: 60rpx !important; } } } .btngroup { display: flex; justify-content: space-between; align-items: center; height: 96rpx; border-bottom: 2rpx solid #f5f5f5; color: #7b7b7b; .rowTitle { font-family: Source Han Sans CN, Source Han Sans CN; font-weight: 400; font-size: 30rpx; color: #222324; white-space: nowrap; } input.input-item { text-align: right; border: none !important; background: transparent !important; box-shadow: none !important; padding: 0 !important; margin: 0 !important; height: auto !important; outline: none; font-size: 30rpx; color: #222324; font-family: Source Han Sans CN, Source Han Sans CN; } :deep(.uni-input-placeholder) { color: #D5D5D5; } input.input-item::placeholder { font-size: 30rpx; } // .code-container { // display: flex; // align-items: center; // justify-content: flex-end; // width: 100%; // } .send-code-btn { margin-left: 20rpx; width: 200rpx; height: 70rpx; line-height: 70rpx; font-size: 26rpx; background: #f5f5f5; color: #666; border-radius: 8rpx; } .send-code-btn:disabled { background: #e0e0e0; color: #999; position: absolute; bottom: 150rpx; :deep(.u-button){ width: 276rpx !important; height: 100rpx !important; } } } .btngroup { display: flex; position: absolute; bottom: 150rpx; } :deep(.u-button:first-child) { margin-right: 30rpx !important; } :deep(.u-button:first-child) { margin-right: 30rpx !important; .custom-style { width: 276rpx; height: 100rpx; font-family: "Source Han Sans CN"; font-weight: 400; font-size: 36rpx; } } .custom-style { width: 276rpx; height: 100rpx; font-family: "Source Han Sans CN"; font-weight: 400; font-size: 36rpx; } :deep(.u-button.data-v-461e713c){ width: 276rpx !important; height: 100rpx !important; } .getCode { margin-left: 20rpx; width: 180rpx; } </style> uniapps/work-wx/src/subPackages/workDetail/addWork/index.vue
File was deleted uniapps/work-wx/src/subPackages/workDetail/index.vue
File was deleted uniapps/work-wx/src/subPackages/workDetail/mapWork/index.vue
File was deleted uniapps/work-wx/src/subPackages/workDetail/photoMagnify/index.vue
File was deleted