ZaiZai 4 hónapja
szülő
commit
4c65b317d9

+ 8 - 0
.editorconfig

@@ -0,0 +1,8 @@
+root = true
+
+[*]
+indent_style = space
+indent_size = 4
+charset = utf-8
+trim_trailing_whitespace = true
+insert_final_newline = true

+ 11 - 0
.gitignore

@@ -0,0 +1,11 @@
+.idea
+.vscode
+.hbuilderx
+.DS_Store
+
+node_modules
+cache
+debug
+dist
+release
+resources

+ 0 - 4
.idea/misc.xml

@@ -11,8 +11,4 @@
       </profile-state>
     </entry>
   </component>
-  <component name="VcsManagerConfiguration">
-    <option name="CHECK_CODE_SMELLS_BEFORE_PROJECT_COMMIT" value="false" />
-    <option name="CHECK_NEW_TODO" value="false" />
-  </component>
 </project>

+ 8 - 0
components/index.js

@@ -0,0 +1,8 @@
+import ZaiRow from './zai-row-col/row.vue'
+import ZaiCol from './zai-row-col/col.vue'
+
+//注册全局组件
+export const setupComponents = (App) => {
+    App.component('ZaiRow', ZaiRow)
+    App.component('ZaiCol', ZaiCol)
+}

+ 50 - 0
components/zai-row-col/col.vue

@@ -0,0 +1,50 @@
+<template>
+    <div class="zai-col" :style="styleVal">
+        <slot />
+    </div>
+</template>
+
+<script setup>
+import {getCurrentInstance, onMounted, ref, watch} from "vue";
+const props = defineProps({
+    span: { //栅格占据的列数,1-24
+        type: [Number, String],
+        default: 24,
+    },
+})
+
+//获取父组件实例
+const parent = getCurrentInstance().parent
+//渲染完成
+onMounted(() => {
+    setStyleValue(props.span)
+})
+
+//监听
+watch(() => [
+    props.span,
+], ([span]) => {
+    setStyleValue(span)
+})
+
+//设置样式
+const styleVal = ref({})
+const setStyleValue = (span) => {
+    if (parent?.type?.name === 'HcRow') {
+        //处理栅格间隔
+        const gutter = Number(parent?.props?.gutter ?? 0)
+        if (gutter !== 0) {
+            const num = Math.floor(gutter / 2) + (gutter % 2) + 'px'
+            styleVal.value['--zai-row-padding'] = num ? num : '0'
+        }
+        //计算栅栏宽度
+        const width = (1 / 24) * Number(span) * 100
+        styleVal.value['--zai-col-width'] = `${width}%`
+        styleVal.value['--zai-col-flex'] = `0 0 ${width}%`
+    }
+}
+</script>
+
+<style scoped lang="scss">
+@import "./style.scss";
+</style>

+ 59 - 0
components/zai-row-col/row.vue

@@ -0,0 +1,59 @@
+<template>
+    <div class="zai-row" :style="styleVal">
+        <slot />
+    </div>
+</template>
+
+<script>
+export default {name: 'HcRow'}
+</script>
+
+<script setup>
+import {onMounted, ref, watch} from "vue";
+const props = defineProps({
+    //栅格间隔
+    gutter: {
+        type: [Number, String],
+        default: 0,
+    },
+    //水平排列方式
+    justify: {
+        type: String,
+        default: '',
+    },
+    //垂直排列方式
+    align: {
+        type: String,
+        default: '',
+    },
+})
+
+onMounted(() => {
+    setStyleValue(props.gutter, props.justify, props.align)
+})
+
+//监听
+watch(() => [
+    props.gutter,
+    props.justify,
+    props.align,
+], ([gutter, justify, align]) => {
+    setStyleValue(gutter, justify, align)
+})
+
+//处理栅格间隔
+const styleVal = ref({})
+function setStyleValue(gutter, justify, align) {
+    const gutters = Number(gutter)
+    styleVal.value['--zai-row-justify'] = justify ? justify : 'start'
+    styleVal.value['--zai-row-align'] = align ? align : 'start'
+    if (gutters !== 0) {
+        const num = Math.floor(gutters / -2) + (gutters % 2) + 'px'
+        styleVal.value['--zai-row-margin'] = num ? num : '0'
+    }
+}
+</script>
+
+<style scoped lang="scss">
+@import "./style.scss";
+</style>

+ 16 - 0
components/zai-row-col/style.scss

@@ -0,0 +1,16 @@
+.zai-row {
+    display: flex;
+    flex-wrap: wrap;
+    position: relative;
+    box-sizing: border-box;
+    margin: var(--zai-row-margin, 0);
+    justify-content: var(--zai-row-justify, start);
+    align-items: var(--zai-row-align, start);
+}
+.zai-col {
+    position: relative;
+    box-sizing: border-box;
+    padding: var(--zai-row-padding, 0);
+    max-width: var(--zai-col-width, 100%);
+    flex: var(--zai-col-flex, 0 0 100%)
+}

+ 38 - 0
config/envApi.js

@@ -0,0 +1,38 @@
+import website from '@/config/index';
+
+//获取请求url
+export const getAppApiUrl = () => {
+    let url = '', {testApi, baseApi} = website;
+    if (process.env.NODE_ENV === 'development') {
+        //#ifdef APP-PLUS
+        url = testApi.api;
+        //#endif
+    } else {
+        //#ifdef APP-PLUS
+        url = baseApi.api;
+        //#endif
+    }
+    return url
+}
+
+//获取表单的url
+export const getFormApiUrl = () => {
+    let url = '', {testApi, baseApi} = website;
+    if (process.env.NODE_ENV === 'development') {
+        url = testApi.form;
+    } else {
+        url = baseApi.form;
+    }
+    return url
+}
+
+//获取长连接的地址
+export const getWssApiUrl = () => {
+    let url = '', {testApi, baseApi} = website;
+    if (process.env.NODE_ENV === 'development') {
+        url = testApi.wss;
+    } else {
+        url = baseApi.wss;
+    }
+    return url
+}

+ 32 - 0
config/index.js

@@ -0,0 +1,32 @@
+export default {
+    title: "工程云家",
+    platform: 'client',         //app的key,用于检测升级
+    key: 'uni-app',             //配置主键,目前用于存储
+    clientId: 'uni-app',        // 客户端id
+    clientSecret: 'app_secret', // 客户端密钥
+    tenantMode: true,   // 是否开启租户模式
+    tenantId: "000000", // 管理组租户编号
+    captchaMode: false, // 是否开启验证码模式
+    switchMode: false,  // 是否开启部门切换模式
+    lockPage: '/lock',
+    tokenTime: 1700,
+    //测试环境
+    testApi: {
+        //api: 'http://192.168.0.109:8090/',  //请求地址
+        //form: 'http://192.168.0.199:5174/', //表单地址
+        api: 'http://39.108.216.210:8090/', //请求地址
+        form: 'https://user.hcxxy.com/',    //表单地址
+        wss: 'wss://business.hcxxy.com/wss/websocket/', //长连接地址
+    },
+    //正式环境
+    baseApi: {
+        api: 'http://39.108.216.210:8090/', //请求地址
+        form: 'https://user.hcxxy.com/',    //表单地址
+        wss: 'wss://business.hcxxy.com/wss/websocket/', //长连接地址
+    },
+    //H5测试设置
+    vite: {
+        port: '3001',
+        host: '0.0.0.0'
+    }
+}

+ 19 - 0
httpApi/modules/api.js

@@ -0,0 +1,19 @@
+import { httpApi } from '../request/httpApi'
+
+export default {
+    async post(form) {
+        return httpApi({
+            url: '/api/' + form.url,
+            method: 'post',
+            params: form.params,
+            data: form.data,
+        })
+    },
+    async get(form) {
+        return httpApi({
+            url: '/api/' + form.url,
+            params: form.params,
+            method: 'get',
+        })
+    },
+}

+ 27 - 0
httpApi/modules/menu.js

@@ -0,0 +1,27 @@
+import { httpApi } from '../request/httpApi'
+import website from "@/config/index";
+
+export default {
+    async getRoutes() {
+        return httpApi({
+            url: '/api/blade-system/menu/routes',
+            method: 'get',
+            params: {
+                sysType: website.clientId,
+            },
+        })
+    },
+    async getButtons() {
+        return httpApi({
+            url: '/api/blade-system/menu/buttons',
+            method: 'get',
+        })
+    },
+    async getAazyList(form) {
+        return httpApi({
+            url: '/api/blade-system/menu/lazy-list',
+            method: 'get',
+            params: form,
+        })
+    },
+}

+ 48 - 0
httpApi/modules/upload.js

@@ -0,0 +1,48 @@
+import {getTokenHeader} from '../request/header'
+import {getObjValue} from "js-fast-way";
+import {getAppApiUrl} from "@/config/envApi";
+
+export const getUploadApi = () => {
+    let url = '';
+    //#ifdef H5
+        url = '/api/';
+    //#endif
+    //#ifdef APP-PLUS
+        url = getAppApiUrl()
+    //#endif
+    return url
+}
+
+export const uploadApi = async (file, form= {}) => {
+    const url = getUploadApi() + 'blade-resource/oss/endpoint/upload-file';
+    return uploadFileApi(url, file, form)
+}
+
+export const uploadApi2 = async (file, form= {}) => {
+    const url = getUploadApi() + 'blade-resource/oss/endpoint/put-file';
+    return uploadFileApi(url, file, form)
+}
+
+export const uploadFileApi = async (url, file, form= {}) => {
+    return new Promise((resolve) => {
+        uni.uploadFile({
+            url: url,
+            name: 'file',
+            formData: form,
+            header: getTokenHeader(),
+            filePath: file,
+            success:(res) => {
+                const {code, msg, data} = JSON.parse(res?.data)
+                if (code === 200) {
+                    resolve({error: false, msg: msg, data: getObjValue(data)})
+                } else {
+                    resolve({error: true, msg: msg, data: {}})
+                }
+            },
+            fail:()=> {
+                resolve({error: true, msg: '上传失败', data: {}})
+            }
+        });
+    })
+}
+

+ 91 - 0
httpApi/modules/user/index.js

@@ -0,0 +1,91 @@
+import {httpApi} from "../../request/httpApi";
+import website from "@/config/index";
+import md5 from 'js-md5'
+
+export default {
+    //分页数据
+    async userLogin({tenantId, deptId, roleId, username, password, type, key, code}) {
+        return httpApi({
+            url: '/api/blade-auth/oauth/token',
+            method: 'post',
+            headers: {
+                'Tenant-Id': tenantId,
+                'Dept-Id': (website.switchMode ? deptId : ''),
+                'Role-Id': (website.switchMode ? roleId : ''),
+                'Captcha-Key': key,
+                'Captcha-Code': code,
+            },
+            params: {
+                tenantId,
+                username,
+                password: md5(password),
+                grant_type: (website.captchaMode ? "captcha" : "password"),
+                scope: "all",
+                type
+            }
+        })
+    },
+    async refreshToken({token, tenantId, deptId, roleId}) {
+        return httpApi({
+            url: '/api/blade-auth/oauth/token',
+            method: 'post',
+            headers: {
+                'Tenant-Id': tenantId,
+                'Dept-Id': (website.switchMode ? deptId : ''),
+                'Role-Id': (website.switchMode ? roleId : ''),
+            },
+            params: {
+                tenantId,
+                refresh_token: token,
+                grant_type: 'refresh_token',
+                scope: 'all',
+            },
+        })
+    },
+    async queryCurrentUserData() {
+        return httpApi({
+            url: '/api/blade-business/userViewProjectContract/queryCurrentUserData',
+            method: 'post',
+            data: {},
+        })
+    },
+    //更新用户信息
+    async updateUserInfo(form) {
+        return httpApi({
+            url: '/api/blade-user/update-info',
+            method: 'post',
+            data: form,
+        })
+    },
+    async appQuerYownData(form) {
+        return httpApi({
+            url: '/api/blade-manager/managerHomePage/appqueryowndata',
+            method: 'post',
+            data: form,
+        })
+    },
+    //修改密码
+    async updatePassword(form) {
+        return httpApi({
+            url: '/api/blade-user/update-password',
+            method: 'post',
+            params: form,
+        })
+    },
+    //用户配置详情
+    async userConfigInfo(form) {
+        return httpApi({
+            url: '/api/blade-business/defaultConfig/detail',
+            method: 'get',
+            params: form,
+        })
+    },
+    //用户配置保存
+    async userConfigSave(form) {
+        return httpApi({
+            url: '/api/blade-business/defaultConfig/saveOrUpdate',
+            method: 'post',
+            data: form,
+        })
+    },
+}

+ 48 - 0
httpApi/modules/user/project.js

@@ -0,0 +1,48 @@
+import {httpApi} from "../../request/httpApi";
+
+export default {
+    //获取项目和合同段
+    async getProjectAndContract() {
+        return httpApi({
+            url: '/api/blade-business/userViewProjectContract/queryUserViewProjectAndContract',
+            method: 'get',
+            params: {}
+        });
+    },
+    //获取默认项目
+    async getDefaultProject(form) {
+        return httpApi({
+            url: '/api/blade-business/defaultProject/queryUserDefault',
+            method: 'get',
+            params: form
+        });
+    },
+    //获取项目详情
+    async getProjectInfo(id) {
+        return httpApi({
+            url: '/api/blade-manager/projectInfo/detail',
+            method: 'get',
+            params: {
+                id: id ? id + '' : ''
+            }
+        });
+    },
+    //获取合同段详情
+    async getContractInfo(id) {
+        return httpApi({
+            url: '/api/blade-manager/contractInfo/detail',
+            method: 'get',
+            params: {
+                id: id ? id + '' : ''
+            }
+        });
+    },
+    //设置默认项目
+    async setDefaultProject(form) {
+        return httpApi({
+            url: '/api/blade-business/defaultProject/save',
+            method: 'post',
+            data: form
+        });
+    },
+}

+ 16 - 0
httpApi/request/header.js

@@ -0,0 +1,16 @@
+import {Base64} from 'js-base64';
+import website from '@/config/index';
+import {getToken} from '../util/auth';
+
+export function getTokenHeader(text= false) {
+    let headers = {};
+    headers['Authorization'] = `Basic ${Base64.encode(`${website.clientId}:${website.clientSecret}`)}`;
+    //让每个请求携带token
+    const token = getToken()
+    if (token) headers['Blade-Auth'] = 'bearer ' + token
+    //headers中配置text请求
+    if (text === true) {
+        headers["Content-Type"] = "text/plain";
+    }
+    return headers;
+}

+ 64 - 0
httpApi/request/httpApi.js

@@ -0,0 +1,64 @@
+import request from "./index";
+import {getObjValue} from "js-fast-way"
+
+//封装的请求
+export const httpApi = async (obj) => {
+    return new Promise((resolve) => {
+        //发起请求
+        request(obj).then(async (response) => {
+            resolve(await getResData(response, false))
+        }).catch(async (response) => {
+            resolve(await getResData(response, true))
+        })
+    })
+}
+
+//处理数据
+const getResData = async (response, error = false) => {
+    return new Promise((resolve) => {
+        const { headers, data, config } = response
+        const resData = getObjValue(data)
+        const httpData = {
+            response,
+            res: data,
+            data: resData?.data,
+            code: resData?.code,
+            msg: resData?.msg,
+            status: response?.statusCode,
+            headers: headers,
+            message: getMsgVal(response),
+            error: error,
+        }
+        //处理延迟响应
+        if (error) {
+            resolve(httpData)
+        } else {
+            const { startTime, endTime } = config.metadata
+            if (config.isDelay) {
+                const duration = endTime - startTime
+                if (duration < 500) {
+                    setTimeout(() => {
+                        resolve(httpData)
+                    }, 1000 - duration)
+                } else {
+                    resolve(httpData)
+                }
+            } else {
+                resolve(httpData)
+            }
+        }
+    })
+}
+
+//获取msg消息内容
+const getMsgVal = ({statusCode, data}) => {
+    const { code, msg, error_description } = getObjValue(data)
+    if (statusCode === 404) {
+        return '服务器异常,请联系管理员!'
+    }
+    if (code === 500 || code === 504) {
+        return '该功能正在升级优化,请联系管理员!'
+    } else {
+        return msg || error_description || '未知错误'
+    }
+}

+ 72 - 0
httpApi/request/index.js

@@ -0,0 +1,72 @@
+import ajax from 'uni-ajax'
+import {getToken} from '../util/auth';
+import website from '@/config/index';
+import {Base64} from 'js-base64';
+import {toSerialize} from "js-fast-way"
+import {getAppApiUrl} from '@/config/envApi';
+
+// 创建请求实例
+const instance = ajax.create({
+    baseURL: getAppApiUrl(),
+    timeout: 1800000,
+    validateStatus: function (status) {
+        return status >= 200 && status <= 500;
+    },
+    //跨域请求,允许保存cookie
+    withCredentials: true,
+})
+
+//http request拦截
+instance.interceptors.request.use(config => {
+    const meta = (config.meta || {});
+    const isToken = meta.isToken === false;
+    config.header = {...config.headers}
+    config.header['Authorization'] = `Basic ${Base64.encode(`${website.clientId}:${website.clientSecret}`)}`;
+    //让每个请求携带token
+    const token = getToken()
+    if (token && !isToken) {
+        config.header['Blade-Auth'] = 'bearer ' + token
+    }
+    //headers中配置text请求
+    if (config.text === true) {
+        config.header["Content-Type"] = "text/plain";
+    }
+    //headers中配置serialize为true开启序列化
+    if (config.method === 'post' && meta.isSerialize === true) {
+        config.data = toSerialize(config.data);
+    }
+    //#ifdef APP-PLUS
+    config.url = config.url.replace(/^\/api/, '/');
+    //#endif
+    config.metadata = { startTime: new Date() }
+    return config
+}, error => {
+    return Promise.reject(error)
+});
+
+//http response 拦截
+instance.interceptors.response.use(res => {
+    //响应时间
+    res.config.metadata.endTime = new Date()
+    //获取状态码
+    const status = res?.data?.code || res.statusCode
+    //如果是401则跳转到登录页面
+    if (status === 401) {
+        uni.showToast({
+            title: '身份失效',
+            icon: 'none'
+        });
+        uni.redirectTo({
+            url: '/pages/login/login'
+        });
+    }
+    // 如果请求为非200否者默认统一处理
+    if (status !== 200) {
+        return Promise.reject(res)
+    }
+    return res;
+}, error => {
+    return Promise.reject(new Error(error));
+});
+
+export default instance;

+ 70 - 0
httpApi/request/socket.js

@@ -0,0 +1,70 @@
+import {getWssApiUrl} from "@/config/envApi";
+import {getStorage} from "@/utils/storage";
+import {getObjVal, getObjValue, isString} from "js-fast-way";
+import {useAppStore} from "@/store";
+import {isNullES} from "js-fast-way";
+
+export default class HcSocket {
+    static socketTask = null
+    static timeID = null
+    static isConnect = false
+
+    static initSocket() {
+        let _this = this;
+        this.timeID = setInterval(() => {
+            if (!_this.isConnect) {
+                const { user_id } = getObjValue(getStorage('userInfo'))
+                if (isNullES(user_id)) return false;
+                _this.connectSocket(user_id)
+            } else {
+                clearInterval(_this.timeID)
+            }
+        }, 3000)
+    }
+
+    static connectSocket(user_id) {
+        const _this = this, store = useAppStore();
+        this.socketTask = uni.connectSocket({
+            url: getWssApiUrl() + user_id,
+            success: ()=> {
+                console.log('socket 连接成功')
+            },
+            fail: () => {
+                console.log('socket 连接失败')
+            }
+        });
+        //连接已打开
+        this.socketTask.onOpen(function(res) {
+            console.log('socket 连接已打开');
+            _this.isConnect = true
+            const projectId = getStorage('projectId')
+            const contractId = getStorage('contractId')
+            _this.sendSocketMsg(`${projectId},${contractId}`)
+        })
+        //连接失败
+        this.socketTask.onError(function(res) {
+            console.log('socket 连接打开失败,请检查!');
+        })
+        //监听连接关闭
+        this.socketTask.onClose((e) => {
+            console.log('socket 连接关闭!');
+            //进入重新连接
+            setTimeout(() => {
+                _this.connectSocket();
+            }, 3000)
+        })
+        //收到的消息
+        this.socketTask.onMessage(function({data}) {
+            const countData = isString(data) ? JSON.parse(data) : {}
+            if (getObjVal(countData)) {
+                console.log('收到服务器内容:', countData);
+                store.setMsgCountData(countData)
+            }
+        });
+    }
+
+    //发送消息
+    static sendSocketMsg(msg) {
+        this.socketTask.send({data: msg});
+    }
+}

+ 41 - 0
httpApi/util/auth.js

@@ -0,0 +1,41 @@
+import {getStorage, setStorage, delStorage} from "@/utils/storage";
+import {calcDate} from 'js-fast-way'
+
+//计算token是否过期
+export const getTokenTime = (tokenKey) => {
+    const token = getStorage(tokenKey, true)
+    if (token) {
+        const date = calcDate(token.datetime, new Date().getTime())
+        if (date.seconds > 2000) {
+            removeToken()
+            removeRefreshToken()
+        }
+    }
+}
+
+export const getToken = () => {
+    getTokenTime('token')
+    return getStorage('token')
+}
+
+export const setToken = (token) => {
+    setStorage('token', token)
+}
+
+export const getRefreshToken = () => {
+    getTokenTime('refreshToken')
+    return getStorage('refreshToken')
+}
+
+export const setRefreshToken = (token) => {
+    setStorage('refreshToken', token)
+}
+
+export const removeToken = () => {
+    delStorage('token')
+}
+
+export const removeRefreshToken = () => {
+    delStorage('refreshToken')
+}
+

+ 0 - 0
uni.promisify.adaptor.js → js_sdk/uni.promisify.adaptor.js


BIN
nativeplugins/DeviceModule/android/DeviceAPI_ver20240712_release.aar


BIN
nativeplugins/DeviceModule/android/DeviceModule_v1.7.0.aar


BIN
nativeplugins/DeviceModule/android/libs/poi-3.12-android-a.jar


BIN
nativeplugins/DeviceModule/android/libs/poi-ooxml-schemas-3.12-20150511-a.jar


+ 50 - 0
nativeplugins/DeviceModule/package.json

@@ -0,0 +1,50 @@
+{
+    "name": "DeviceModule",
+    "id": "DeviceModule",
+    "version": "1.7.0",
+    "description": "DeviceModule",
+    "_dp_type": "nativeplugin",
+    "_dp_nativeplugin": {
+        "android": {
+            "plugins": [{
+                    "type": "module",
+                    "name": "DeviceModule_RFID",
+                    "class": "io.device.uniplugin.module.RFIDModule"
+                },
+                {
+                    "type": "module",
+                    "name": "DeviceModule_Barcode2D",
+                    "class": "io.device.uniplugin.module.Barcode2DModule"
+                },
+                {
+                    "type": "module",
+                    "name": "DeviceModule_DeviceInfo",
+                    "class": "io.device.uniplugin.module.DeviceInfoModule"
+                },
+                {
+                    "type": "module",
+                    "name": "DeviceModule_Bluetooth",
+                    "class": "io.device.uniplugin.module.BluetoothModule"
+                },
+                {
+                    "type": "module",
+                    "name": "DeviceModule_Export",
+                    "class": "io.device.uniplugin.module.ExportModule"
+                },
+                {
+                    "type": "module",
+                    "name": "DeviceModule_USB",
+                    "class": "io.device.uniplugin.module.USBModule"
+                }
+            ],
+            "dependencies": [],
+            "abis": [
+                "armeabi-v7a|arm64-v8a|x86"
+            ],
+            "hooksClass": "",
+            "integrateType": "aar",
+            "minSdkVersion": "19",
+            "parameters": {}
+        }
+    }
+}

+ 17 - 0
package.json

@@ -0,0 +1,17 @@
+{
+    "dependencies": {
+        "dayjs": "^1.11.10",
+        "js-fast-way": "^0.3.8",
+        "pinia": "^2.1.7",
+        "uni-ajax": "^2.5.1",
+        "vue": "^3.3.11"
+    },
+    "devDependencies": {
+        "@iconify-json/ri": "^1.1.12",
+        "@iconify-json/solar": "^1.1.2",
+        "unocss": "^0.58.0",
+        "unocss-preset-extra": "^0.5.2",
+        "unocss-preset-weapp": "^0.58.0"
+    },
+    "license": "MIT"
+}

+ 25 - 0
store/index.js

@@ -0,0 +1,25 @@
+import {defineStore} from 'pinia'
+import pinia from "../store/init"
+import config from '../config/index';
+import {clearStorage} from "@/utils/storage";
+
+export const useAppStore = defineStore('main', {
+	//getStorage, setStorage,
+    state: () => ({
+        onUpdate: null,
+    }),
+    actions: {
+        setOnUpdate(value) {
+            this.onUpdate = value
+        },
+        //清除缓存和token
+        clearStoreData() {
+            this.onUpdate = null
+            clearStorage()
+        },
+    }
+})
+
+export default function useUserStoreWidthOut() {
+    return useAppStore(pinia);
+}

+ 3 - 0
store/init.js

@@ -0,0 +1,3 @@
+import { createPinia } from 'pinia'
+const store = createPinia()
+export default store

+ 9 - 0
style/app.scss

@@ -0,0 +1,9 @@
+* {
+    margin: 0;
+    padding: 0;
+    box-sizing: border-box;
+}
+
+text {
+    display: inline-block;
+}

+ 0 - 14
uni.scss

@@ -1,17 +1,3 @@
-/**
- * 这里是uni-app内置的常用样式变量
- *
- * uni-app 官方扩展插件及插件市场(https://ext.dcloud.net.cn)上很多三方插件均使用了这些样式变量
- * 如果你是插件开发者,建议你使用scss预处理,并在插件代码中直接使用这些变量(无需 import 这个文件),方便用户通过搭积木的方式开发整体风格一致的App
- *
- */
-
-/**
- * 如果你是App开发者(插件使用者),你可以通过修改这些变量来定制自己的插件主题,实现自定义主题功能
- *
- * 如果你的项目同样使用了scss预处理,你也可以直接在你的 scss 代码中使用如下变量,同时无需 import 这个文件
- */
-
 /* 颜色变量 */
 
 /* 行为相关颜色 */

+ 31 - 0
uno.config.js

@@ -0,0 +1,31 @@
+import {defineConfig, presetUno, presetIcons, presetAttributify} from 'unocss'
+import {presetExtra} from 'unocss-preset-extra';
+import presetWeapp from 'unocss-preset-weapp'
+import {transformerAttributify, transformerClass} from 'unocss-preset-weapp/transformer'
+
+export default defineConfig({
+    shortcuts: {
+        'zu-flex': 'relative flex items-center',
+        'zu-flex-center': 'zu-flex justify-center',
+        'zu-flex-end': 'zu-flex justify-end',
+        'zu-p': 'px-3 py-2',
+        'zu-tr': 'absolute top-0 right-0',
+    },
+    presets: [
+        presetUno(),
+        presetWeapp(),
+        presetIcons({
+            //autoInstall: true, //自动安装图标库
+        }),
+        presetAttributify({
+            prefix: 'un-',      //属性冲突的自定义前缀
+            prefixedOnly: true, //强制使用前缀
+        }),
+        //其它扩展,主要用动画,集成了 animate.css
+        presetExtra(),
+    ],
+    transformers: [
+        transformerAttributify(),
+        transformerClass(),
+    ]
+})

+ 60 - 0
utils/storage.js

@@ -0,0 +1,60 @@
+import {isAllNull} from "js-fast-way"
+import website from '@/config/index'
+
+//获取缓存
+export const getStorage = (key, debug = false) => {
+    let obj = uni.getStorageSync(website.key + '-' + key), content;
+    if (isAllNull(obj)) {
+        return '';
+    }
+    try {
+        obj = JSON.parse(obj);
+    } catch {
+        return obj;
+    }
+    if (debug) {
+        return obj;
+    }
+    if (obj.dataType === 'string') {
+        content = obj.content;
+    } else if (obj.dataType === 'number') {
+        content = Number(obj.content);
+    } else if (obj.dataType === 'boolean') {
+        content = Boolean(obj.content);
+    } else if (obj.dataType === 'object') {
+        content = obj.content;
+    }
+    return content ?? '';
+}
+
+//保存缓存
+export const setStorage = (key, value) => {
+    try {
+        uni.setStorageSync(website.key + '-' + key, JSON.stringify({
+            dataType: typeof (value),
+            content: value ?? '',
+            datetime: new Date().getTime()
+        }));
+    } catch (e) {
+        uni.showToast({
+            title: '本地数据缓存失败',
+            icon: 'none'
+        });
+    }
+}
+
+//删除缓存
+export const delStorage = (key) => {
+    try {
+        uni.removeStorageSync(website.key + '-' + key);
+    } catch {
+    }
+}
+
+
+//清理缓存
+export const clearStorage = () => {
+    try {
+        uni.clearStorageSync();
+    } catch {}
+}

+ 47 - 0
utils/tools.js

@@ -0,0 +1,47 @@
+//确认框
+export const showModal = async ({title, content, confirmText, cancelText}) => {
+    return new Promise((resolve) => {
+        uni.showModal({
+            title: title,
+            content: content,
+            confirmText: confirmText ?? '确定',
+            cancelText: cancelText ?? '取消',
+            success: function (res) {
+                if (res.confirm) {
+                    resolve(true)
+                } else if (res.cancel) {
+                    resolve(false)
+                }
+            }
+        });
+    })
+}
+
+//成功提示
+export const successToast = (title = '成功', duration= 2000) => {
+    uni.showToast({
+        title: title,
+        duration: duration,
+        mask: true
+    });
+}
+
+//失败提示
+export const errorToast = (title = '失败', duration= 1500) => {
+    uni.showToast({
+        title: title,
+        duration: duration,
+        icon: 'none'
+    });
+}
+
+//表单验证
+export const formValidate = async (formRef) => {
+    return new Promise( (resolve) => {
+        formRef.validate().then((res) => {
+            resolve(true)
+        }).catch(err => {
+            resolve(false)
+        })
+    });
+}

+ 45 - 0
utils/utils.js

@@ -0,0 +1,45 @@
+//选择图片文件
+export const chooseImage = (count) => {
+    return new Promise((resolve) => {
+        uni.chooseImage({
+            count: count,
+            sizeType: ['original'],
+            sourceType: ['album', 'camera'],
+            success: ({tempFiles}) => {
+                resolve(tempFiles);
+            },
+            fail: () => {
+                resolve([]);
+            }
+        });
+    })
+}
+
+//选择视频文件
+export const chooseVideo = () => {
+    return new Promise((resolve) => {
+        uni.chooseVideo({
+            sourceType: ['camera', 'album'],
+            success: (res) => {
+                resolve(res);
+            },
+            fail: () => {
+                resolve({});
+            }
+        });
+    })
+}
+
+export const filterSize = (size) => {
+    if (!size) return '';
+    if (size < pow1024(1)) return size + ' B';
+    if (size < pow1024(2)) return (size / pow1024(1)).toFixed(2) + ' KB';
+    if (size < pow1024(3)) return (size / pow1024(2)).toFixed(2) + ' MB';
+    if (size < pow1024(4)) return (size / pow1024(3)).toFixed(2) + ' GB';
+    return (size / pow1024(4)).toFixed(2) + ' TB'
+}
+
+// 求次幂
+function pow1024(num) {
+    return Math.pow(1024, num)
+}

+ 28 - 0
vite.config.js

@@ -0,0 +1,28 @@
+import {defineConfig} from 'vite'
+import uni from "@dcloudio/vite-plugin-uni";
+import Unocss from 'unocss/vite'
+import {resolve} from "path";
+import website from './config/index';
+
+export default defineConfig({
+    resolve: {
+        alias: {
+            '~api': resolve(__dirname, './httpApi/modules'),
+        }
+    },
+    plugins: [
+        uni(),
+        Unocss(),
+    ],
+    server: {
+        ...website.vite,
+        proxy: {
+            '/api': {
+                ws: true,
+                changeOrigin: true,
+                target: website.api,
+                rewrite: (path) => path.replace(new RegExp('^/api'), '/'),
+            }
+        }
+    },
+})