原创自研uniapp+vue3手机桌面os管理系统

简介: vue3-uniapp-os一款基于uniapp+vue3跨端手机版后台os系统新解决方案。

问题背景

市面上关于pc桌面端的后台管理系统,已经有很多成熟的应用方案。然而手机端OA系统管理却没有一些比较令人满意的产品。原因可能是手机设备尺寸有限、没有像pc端操作方便。还有就是很难颠覆传统的左侧菜单列表+右侧操作区的思想。


于是历经一个月潜心研发,我的原创新作uniapp-vue3-os手机os桌面系统项目正式见面了。 未标题-1-.png

带来一种全新os桌面式系统后台管理解决方案!

未标题-5.png

只需要简单配置桌面JSON菜单,就能轻松跳转到相应的页面。


技术栈

  • 编辑器:HbuilderX 4.15
  • 技术框架:uniapp+vite5.x+vue3+pinia2
  • UI组件库:uni-ui+uv-ui(uniapp vue3组件库)
  • 弹框组件:uv3-popup(基于uniapp+vue3自定义弹框组件)
  • 表格组件:uv3-table(基于uniapp+vue3增强版表格)
  • 模拟数据:mockjs(用于自定义表格模拟数据)
  • 缓存技术:pinia-plugin-unistorage
  • 支持编译:h5+小程序端+app端


p2.gif


支持运行编译到h5端+小程序端+APP端。另外运行到pc端效果依然棒棒哒~

pc1.gif

未标题-3.png 未标题-6.png 未标题-7.png 未标题-aaa.png


为了达到整体效果一致性,摒弃传统的输入框登录验证,采用全新的数字密码解锁模式。


001360截图20240520183214121.png 002360截图20240520183251306.png

image.png

<template>
  <uv3-layout>
    <view class="uv3__launch">
      <view v-if="splashScreen" class="uv3__launch-splash" @touchstart="handleTouchStart" @touchmove="handleTouchUpdate">
        <view class="body flex1">
          <Today />
        </view>
        <view class="foot">
          <view class="btn flex-c"><image src="/static/svg/flashlight.svg" mode="widthFix" /></view>
          <view class="text flex1 flexbox flex-col">
            <uni-icons type="up" color="#fff" />
            上滑解锁
          </view>
          <view class="btn flex-c"><image src="/static/svg/camera.svg" mode="widthFix" /></view>
        </view>
      </view>
      <view v-else class="uv3__launch-keyboard" :class="{'closed': authPassed}">
        <view class="uv3__launch-pwdwrap">
          <view class="text">密码解锁</view>
          <view class="circle flexbox">
            <view v-for="(num, index) in passwordArr" :key="index" class="dot" :class="{'active': num <= pwdValue.length}"></view>
          </view>
        </view>
        <view class="uv3__launch-numwrap">
          <view v-for="(item, index) in keyNumbers" :key="index" class="numbox" @click="handleClickNum(item.num)">
            <view class="num">{{item.num}}</view><view class="letter">{{item.letter}}</view>
          </view>
        </view>
        <view class="foot flexbox">
          <view class="c-fff">紧急呼叫</view>
          <view v-if="pwdValue" class="c-fff" @click="handleDel">删除</view>
          <view v-else class="c-fff" @click="handleBack">返回</view>
        </view>
      </view>
    </view>
  </uv3-layout>
</template>
<script setup>
  import { ref, computed, inject, nextTick } from 'vue'
  import { authStore } from '@/pinia/modules/auth'
  import { uuid, guid } from '@/utils'
  
  ...

  // 数字键盘输入值
  const pwdValue = ref('')
  const keyNumbers = ref([
    {num: 1, letter: ''},
    {num: 2, letter: 'ABC'},
    {num: 3, letter: 'DEF'},
    {num: 4, letter: 'GHI'},
    {num: 5, letter: 'JKL'},
    {num: 6, letter: 'MNO'},
    {num: 7, letter: 'PQRS'},
    {num: 8, letter: 'TUV'},
    {num: 9, letter: 'WXYZ'},
    {num: 0, letter: '+'},
  ])
  
  // 点击数字键盘
  const handleClickNum = (num) => {
    let pwdLen = passwordArr.value.length
    if(pwdValue.value.length >= pwdLen) return
    pwdValue.value += num
    // 校验密码
    if(pwdValue.value.length == pwdLen) {
      // 验证通过
      if(pwdValue.value == password.value) {
        authPassed.value = true
        authState.setAuthorization(guid(32))
        authState.setUserInfo({
          avatar: '',
          username: 'Andy',
          token: uuid(64)
        })
        setTimeout(() => {
          uni.redirectTo({
            url: '/pages/desk/desk'
          })
        }, 200)
      }else {
        setTimeout(() => {
          pwdValue.value = ''
        }, 200)
      }
    }
  }
  // 删除
  const handleDel = () => {
    let num = Array.from(pwdValue.value)
    num.splice(-1, 1)
    pwdValue.value = num.join('')
  }
  
  ...
</script>

p1.gif

最终效果如上图:效果非常丝滑,验证解锁更加方便快捷。


公共模板文件

定义公共布局模板,初始化一些桌面图标变量。

<script setup>
    import { ref } from 'vue'
    import { appStore } from '@/pinia/modules/app'
    
    const appState = appStore()
    
    // #ifdef MP-WEIXIN
    defineOptions({
        /**
         * 解决小程序class、id透传问题(vue3写法)
         * manifest.json中配置mergeVirtualHostAttributes: true, 在微信小程序平台不生效,组件外部传入的class没有挂到组件根节点上
         * https://github.com/dcloudio/uni-ui/issues/753
         */
        options: { virtualHost: true }
    })
    // #endif
    const props = defineProps({
        showBackground: { type: [Boolean, String], default: true },
    })
    
    // 自定义变量(桌面图标)
    const deskVariable = ref({
        '--icon-radius': '15px', // 圆角
        '--icon-size': '118rpx', // 图标尺寸
        '--icon-gap-col': '25px', // 水平间距
        '--icon-gap-row': '45px', // 垂直间距
        '--icon-labelSize': '12px', // 标签文字大小
        '--icon-labelColor': '#fff', // 标签颜色
        '--icon-fit': 'contain', // 图标自适应模式
    })
</script>

<template>
    <view class="uv3__container flexbox flex-col flex1" :style="deskVariable">
        <!-- 顶部插槽 -->
        <slot name="header" />
        
        <!-- 内容区 -->
        <view class="uv3__scrollview flex1">
            <slot />
        </view>
        
        <!-- 底部插槽 -->
        <slot name="footer" />
        
        <!-- 背景图(修复小程序不支持background背景图) -->
        <image v-if="showBackground" class="fixwxbg" :src="appState.config.skin || '/static/skin/theme.png'" mode="scaleToFill" />
    </view>
</template>

p3.gif p5.gif p6.gif p4.gif

uniapp桌面栅格菜单

82e8dc507bdbb2f32893405d5acfe89b_1289798-20240521181036651-2076891044.png

edf1f4fe3c6b7ab3c7ce55864536e5f9_1289798-20240521181536058-225601898.png

e0cf5376230c1d2613dfc1e8204ce06b_1289798-20240521181336890-18459133.png

桌面菜单采用json配置

/**
 * label 图标标题
 * imgico 图标(本地或网络图片) 当type: 'icon'则为uni-icons图标名,当type: 'widget'则为自定义小部件标识名
 * type 图标类型(icon | widget) icon为uni-icons图标、widget为自定义小部件
 * path 跳转路由页面
 * link 跳转外部链接
 * hideLabel 是否隐藏图标标题
 * background 自定义图标背景色
 * size 栅格磁贴布局(16种) 1x1 1x2 1x3 1x4、2x1 2x2 2x3 2x4、3x1 3x2 3x3 3x4、4x1 4x2 4x3 4x4
 * onClick 点击图标回调函数 * children 二级菜单
 */

273367ff085b8a5d1a9f80d911fec2c7_1289798-20240521182123160-966261481.png

7c936801fc60c8abfbdf3f5c5d8d30c8_1289798-20240521182418267-528184192.png

<template>
    <swiper
        class="uv3__deskmenu"
        :indicator-dots="true"
        indicator-color="rgba(255,255,255,.5)"
        indicator-active-color="#fff"
    >
        <swiper-item v-for="(mitem, mindex) in deskMenu" :key="mindex">
            <view class="uv3__gridwrap">
                <view v-for="(item, index) in mitem.list" :key="index" class="uv3__gridwrap-item" @click="handleClickDeskMenu(item)">
                    <!-- 图标 -->
                    <view class="ico" :style="{'background': item.background}">
                        <!-- 二级菜单 -->
                        <template v-if="Array.isArray(item.children)">
                            <view class="uv3__gridwrap-thumb">
                                ...
                            </view>
                        </template>
                        <template v-else>
                            <template v-if="item.type == 'widget'">
                                <!-- 自定义部件 -->
                                <component :is="item.imgico" />
                            </template>
                            <template v-else>
                                <!-- 自定义图标 -->
                                ...
                            </template>
                        </template>
                    </view>
                    <!-- 标题 -->
                    <view v-if="!item.hideLabel" class="label clamp2">{{item.label}}</view>
                </view>
            </view>
        </swiper-item>
    </swiper>
    
    <!-- 二级弹窗式菜单 -->
    <Popup v-model="deskPopupVisible">
        <view class="uv3__deskpopup">
            ...
        </view>
    </Popup>

    ...
</template>

点击桌面菜单,处理不同的事件逻辑。

const handleClickDeskMenu = (item) => {
    if(item.link) {
        // 链接
        openURL(item.link)
    }else if(item.path) {
        // 页面路由地址
        uni.navigateTo({
            url: item.path.substr(0, 1) == '/' ? item.path : '/' + item.path
        })
    }else if(Array.isArray(item.children)) {
        // 二级菜单
        deskPopupMenu.value = item
        deskPopupVisible.value = true
    }
    // 绑定点击事件
    typeof item.onClick === 'function' && item.onClick()
}

桌面菜单json配置片段

const deskMenu = ref([
    {
        pid: 20240507001,
        list: [
            {label: '今日', imgico: 'today', type: 'widget', hideLabel: true, size: '2x1'},
            {label: '天气', imgico: 'weather', type: 'widget', hideLabel: true, size: '2x1'},
            {label: '日历', imgico: 'fullcalendar', type: 'widget', path: 'pages/calendar/index', size: '4x2'},
            // {label: '日历', imgico: 'date', type: 'widget', size: '2x2'},
            // {label: '备忘录', imgico: 'note', type: 'widget', size: '2x2'},
            {label: 'audio', imgico: 'audio', type: 'widget', size: '2x1'},
            {
                label: '相册', imgico: '/static/svg/huaban.svg', background: '#00aa7f',
                onClick: () => {
                    // ...
                }
            },
            ...
        ]
    },
    ...
    {
        pid: 20240510001,
        list: [
            {label: 'Github', imgico: '/static/svg/github.svg', background: '#607d8b', size: '3x1'},
            {label: '码云Gitee', imgico: '/static/svg/gitee.svg', background: '#bb2124',},
            {label: '抖音', imgico: '/static/svg/douyin.svg', background: '#1c0b1a', size: '1x2'},
            {label: 'ChatGPT', imgico: '/static/svg/chatgpt.svg', hideLabel: true, background: '#11b6a7', size: '3x2'},
            ...
        ]
    },
    {
        pid: 20240511003,
        list: [
            {label: 'uni-app', imgico: '/static/uni.png', link: 'https://uniapp.dcloud.net.cn/'},
            {label: 'vitejs官方文档', imgico: '/static/vite.png', link: 'https://vitejs.dev/'},
            {
                label: '主题壁纸', imgico: 'color-filled', type: 'icon',
                onClick: () => {
                    // ...
                }
            },
            {label: '日历', imgico: 'calendar', type: 'widget', path: 'pages/calendar/index', background: '#fff',},
            {label: '首页', imgico: 'home', type: 'icon', path: 'pages/index/index'},
            {label: '工作台', imgico: 'shop-filled', type: 'icon', path: 'pages/index/dashboard'},
            {
                label: '组件',
                'children': [
                    {label: '组件', imgico: '/static/svg/component.svg', path: 'pages/component/index'},
                    {label: '表格', imgico: '/static/svg/table.svg', path: 'pages/component/table'},
                    ...
                ]
            },
            ...
            {
                label: '关于', imgico: 'info-filled', type: 'icon',
                onClick: () => {
                    // ...
                }
            },
            {
                label: '公众号', imgico: 'weixin', type: 'icon',
                onClick: () => {
                    // ...
                }
            },
        ]
    }
])

通过开发这个uniapp-vue3-os项目,旨在探索一种全新的手机后台OA管理系统新模式。

目前这个项目已经得到了很多小伙伴们的喜欢支持!

后面会考虑用flutter技术再开发一版类似的跨平台OA系统。

目录
相关文章
|
2月前
|
移动开发 Android开发 开发者
移动应用与系统:探索移动开发与操作系统的协同进化###
本文深入探讨了移动应用开发与移动操作系统之间错综复杂的关系,揭示了技术进步如何推动用户体验的飞跃。通过案例分析和技术解析,本文阐述了开发者在适应不断变化的操作系统环境中面临的挑战与机遇,以及这种互动如何塑造了我们的数字生活。 ###
|
2月前
|
人工智能 Linux Android开发
移动应用与系统:探索移动应用开发和操作系统的奥秘
【10月更文挑战第5天】 这篇文章将深入探讨移动应用与系统的关键技术,包括移动应用开发的基本流程、工具和技术,以及移动操作系统的核心原理和架构。我们将从浅入深,逐步揭开移动应用与系统的神秘面纱,帮助读者更好地理解和掌握这一领域的知识。
42 2
|
23天前
|
人工智能 Android开发 数据安全/隐私保护
移动应用与系统:探索开发趋势与操作系统的协同进化####
当今时代,移动应用不再仅仅是简单的软件工具,它们已成为扩展智能手机及平板等设备功能的关键。本文旨在深入分析当前移动应用的开发趋势,探讨移动操作系统的最新进展及其对应用开发的影响,并阐述两者如何相互促进、协同进化,共同推动移动互联网技术向前发展。 ####
|
25天前
|
移动开发 人工智能 Android开发
移动应用与系统:探索移动开发与操作系统的协同进化####
当今数字化时代,移动设备已成为日常生活不可或缺的一部分。本文旨在深入探讨移动应用开发与移动操作系统之间的紧密关系及其相互影响,揭示技术创新如何推动这一领域的发展。通过分析当前主流移动操作系统的特点、移动应用的开发趋势以及两者间的互动机制,本文为开发者和用户提供了一个全面了解该领域的窗口。 ####
|
22天前
|
开发工具 Android开发 iOS开发
移动应用与系统:涵盖移动应用开发、移动操作系统等相关话题####
本文深入探讨了移动应用开发和移动操作系统的复杂世界。从移动应用开发的基本概念到移动操作系统的核心功能,再到两者如何相互作用以提供无缝的用户体验,本文全面涵盖了这一领域的各个方面。无论你是开发者、技术爱好者还是普通用户,这篇文章都将为你提供有价值的见解。 ####
25 1
|
28天前
|
人工智能 物联网 Android开发
移动应用与系统:探索开发趋势与操作系统的协同进化####
本文深入探讨了移动应用开发的当前趋势,以及这些趋势如何与移动操作系统的发展相互影响、协同进化。通过分析最新的技术动态、市场数据及用户行为变化,本文旨在为开发者提供关于未来移动应用开发方向的洞察,并讨论操作系统层面的创新如何促进或制约应用的发展。 ####
|
5天前
|
5G 数据安全/隐私保护 Android开发
移动应用与系统:探索开发趋势与操作系统革新####
本文深入剖析当前移动应用开发的最新趋势,涵盖跨平台开发框架的兴起、人工智能技术的融合、5G技术对移动应用的影响,以及即时应用的发展现状。随后,文章将探讨主流移动操作系统的最新特性及其对开发者社区的影响,包括Android的持续进化、iOS的创新举措及华为鸿蒙OS的崛起。最后,还将讨论移动应用开发中面临的挑战与未来的发展机遇,为读者提供全面而深入的行业洞察。 ####
|
1月前
|
安全 物联网 Android开发
移动应用与系统:探索开发趋势与操作系统的演进####
【10月更文挑战第29天】 本文深入探讨了移动应用开发的最新趋势与挑战,并分析了主流移动操作系统(如Android、iOS)的发展动态。通过对比不同系统的技术特点和市场表现,揭示了移动应用生态系统的复杂性及其对开发者的影响。此外,还讨论了跨平台开发工具的兴起如何改变应用开发流程,以及这些变化对未来移动计算领域的潜在影响。 ####
35 4
|
1月前
|
人工智能 Android开发 数据安全/隐私保护
移动应用与系统:探索移动应用开发及操作系统的未来趋势####
本文深入探讨了移动应用开发和移动操作系统的现状、挑战与未来发展趋势。通过分析当前主流的移动操作系统(如Android和iOS)以及移动应用开发的最新技术,旨在为开发者提供有价值的参考,帮助他们更好地应对未来的挑战。 ####
|
29天前
|
安全 Android开发 iOS开发
移动应用与系统:探索移动应用开发与操作系统的协同进化###
【10月更文挑战第29天】 本文深入探讨了移动应用开发与移动操作系统之间的紧密联系与相互促进作用,分析了当前主流移动操作系统(如iOS、Android)的最新特性及其对应用开发的影响,并展望了未来移动应用与系统协同发展的新趋势。通过具体案例分析,揭示了开发者如何利用系统特性优化应用性能,提升用户体验,同时指出了跨平台开发工具的兴起如何进一步模糊了应用与系统间的界限,推动了整个移动互联网生态系统的繁荣发展。 ###
40 2