# Ciyon移动端开发框架 Skill指南 ## 框架概述 CiYon是一个基于uniapp的轻量级跨平台移动应用开发框架,采用Vue3 + Vite技术栈,支持小程序、H5、App多端发布。 ## 项目结构 ``` ai_mapshare/ ├── fapp/ciyon_ap/ # uniapp移动端项目 │ ├── pages/ # 页面目录 │ │ ├── main/ # 参考主页面 │ │ ├── me/ # 个人中心 │ │ ├── pub/ # 公共页面 │ │ └── demo/ # 示例页面 │ ├── components/ # 60+自定义组件库 │ ├── util/ # 工具函数库 │ ├── static/ # 静态资源 │ ├── App.vue # 应用入口 │ ├── main.js # 主入口文件 │ ├── pages.json # 页面配置 │ ├── manifest.json # 应用配置 │ └── vite.config.js # Vite配置 ``` ## 技术栈 - **前端**: Vue3 + Vite + Uniapp - **通信**: HTTP POST API(JSON) - **参考页面**: - /fapp/ciyon_ap/pages/demo/curd/demo_list.vue - /fapp/ciyon_ap/pages/demo/curd/demo_edit.vue - /fapp/ciyon_ap/pages/main/index.vue - /fapp/ciyon_ap/pages/main/me.vue ## 开发规范 ### 页面开发规范 - 页面存放在 `pages/` 对应模块目录下 - 页面注册在 `pages.json` 中配置路由 - 使用uniapp标准生命周期 ### 目录及文件名命名规范 - 在`pages/`下新建项目目录 - `/pages/[项目目录]/index.vue`作为首页主页面 - `/pages/[项目目录]/me.vue` 作为个人中心主页面 - `/pages/[项目目录]/xx_xx.vue` 其他页面均要有一定含义,建议与数据表名称相关。模块_功能 - 例如:`order_list.vue` 列表页、`order_info.vue` 详情页、`order_edit.vue` 编辑页、`order_ship.vue` 功能页 - 例如: `user_info.vue`、`user_order.vue`、`user_address.vue` - 页面起名尽量贴合业务,不要用`detail.vue`、`list.vue`、`edit.vue`、`add.vue`等通用名称。 ### vue文件API方法命名规范 - 页面初始化方法一般为`init` - func: 'xx.xx_init' - 列表页,初始化传入once(bool)参数,once=true,首次请求获取初始化数据 this.pagepost.once = !this.init.once; 参考 /fapp/ciyon_ap/pages/demo/curd/demo_list.vue 参考 /fapp/ciyon_ap/pages/demo/curd/demo_edit.vue API参考 /web/ampap/demo/demo.php - 更新 `update`、删除 `delete`、审核 `audit`等方法按此命名。 - 综合举例: - 前端文件: /pages/[项目目录]/[模块]_list.vue - 前端调用: this.callfunc({func:'[模块].[功能]_init'})、this.callfunc({func:'[模块].[功能]_delete'}) - 后端文件: /web/am[项目目录]/[模块].php - 后端函数: json_[功能]_init()、json_[功能]_delete() ### 组件使用规范 组件前缀统一使用 `ciy-`,已提供60+组件: **表单组件**: - `ciy-input` - 基础输入框 - `ciy-textarea` - 文本域 - `ciy-select` - 选择器 - `ciy-radio` - 单选 - `ciy-checkbox` - 复选 - `ciy-checkitem` - 检查项 - `ciy-switch` - 开关 - `ciy-selbool` - 布尔选择 - `ciy-selcas` - 级联选择 - `ciy-selpage` - 页面选择 - `ciy-slider` - 滑块 - `ciy-inputnumber` - 数字输入 - `ciy-inputbet` - 范围输入 - `ciy-inputcyc` - 周期输入 - `ciy-inputdatetime` - 日期时间 - `ciy-inputdaterange` - 日期范围 - `ciy-inputtimepoint` - 时间点 - `ciy-inputunitedit` - 单位编辑 - `ciy-inputocr` - OCR输入 - `ciy-capcode` - 验证码输入 - `ciy-searchbar` - 搜索栏 - `ciy-query` - 查询组件 - `ciy-selmap` - 地图选择位置 - `ciy-mapbox` - 地图展示组件(基于 Leaflet) - `ciy-upload` - 文件上传 **展示组件**: - `ciy-showmoney` - 金额展示 - `ciy-shownum` - 数字展示 - `ciy-showimgs` - 多图片展示 - `ciy-textmore` - 文本展开 - `ciy-chart-pie` - 饼图 - `ciy-markdown` - Markdown渲染 - `ciy-svgimg` - 单图片显示 - `ciy-totalsem` - 总计语义 - `ciy-gesture` - 手势识别 - `ciy-handsign` - 手势识别 - `ciy-audio` - 音频播放 **功能组件**: - `ciy-camera` - 相机(在ciy-aicameraocr中) - `ciy-aivoice` - AI语音 - `ciy-gesture` - 手势识别 - `ciy-handsign` - 手势识别 - `ciy-btreader` - 蓝牙读卡器 - `ciy-header` - 页面头部 - `ciy-tabbar` - 底部导航 - `ciy-dialog` - 弹窗 - `ciy-toast` - 提示 - `ciy-alert` - 警告 - `ciy-popmenu` - 弹出菜单 - `ciy-calendar` - 日历 - `ciy-ratestar` - 评分 - `ciy-segment` - 分段器 - `ciy-swiper` - 轮播 - `ciy-swipelist` - 滑动列表 - `ciy-listend` - 列表底部 - `ciy-movable` - 可移动 **动画组件**: - `ciy-ani` - 动画 - `ciy-aniheight` - 高度动画 - `ciy-anipop` - 弹出动画 **认证组件**: - `ciy-auth` - 认证 **自定义组件**: - `diy-apuser` - AP用户 - `diy-xxlist` - XX列表 **调试组件**: - `ciy-dbg` - 调试 ### API通信规范 **请求封装**: ```javascript // 使用 callfunc 方法调用API await this.callfunc({ func: 'main.index_init', // API函数名,格式:后端API文件名.前端页面名_方法 data: { // 要发送的数据 id: 123, name: 'test' }, srv: 't', // 服务器标识,默认't' loadhide: false, // 是否隐藏加载提示,默认false cache: 0, // 缓存时间(秒),0不缓存,一般不缓存 cachekey: '' // 自定义缓存键 }).then(res => { // 处理响应 }); ``` **API路径规则**: - 前端调用格式:`{func: 'module.method'}` - URL映射:通过 `jsnurl` 配置映射到实际URL - API命名与页面关联:方法名应与前端页面文件名对应,便于识别和维护。格式建议:`{后端API文件名}.{前端页面名}_{操作方法名}` - 示例:`{func: 'aaa.index_init'}` 对应后端API `/web/ambap/aaa.php`、对应移动端 `pages/aaa/index.vue` - 示例:`{func: 'bbb.detail_init'}` 对应后端API `/web/ambap/bbb.php`、对应移动端 `pages/bbb/detail.vue` - 示例: - 前端调用:`{func: 'main.index_init'}` - 另一个示例:`{func: 'login.login_mobile'}` - **重要**:后端函数名必须与前端的 func 参数完全一致,例如前端 `func: 'aimap.index_init'`,后端函数名为 `json_index_init()` **响应格式**: ```javascript // 成功响应 { code: 1, // 1表示成功 // 其他业务数据... } // 失败响应 { code: 非1, // 非1表示失败,2表示需要重新登录 errmsg: '错误信息', // 错误提示 // 其他错误数据... } ``` ### 工具函数 **util/ciy.js** - 核心工具库: **API请求**: - `callfunc(opt)` - 统一API请求方法 - `calltxt(opt)` - 纯文本请求 **存储管理**: - `getstorage(key, def)` - 读取storage - `setstorage(key, val)` - 写入storage - `removestorage(key)` - 删除storage(支持通配符*) - `clearstorage()` - 清空所有storage **用户认证**: - `getauth()` - 获取用户信息,未登录自动调起登录 **提示交互**: - `alert(content)` - 弹窗提示(await) - `toast(content, icon)` - 轻提示(await) - `askmsg(content)` - 询问确认框(await) - `inputmsg(content, def)` - 输入框(await) - `popmenu(options)` - 弹出上拉菜单(await) **页面跳转**: - `gourl(url, type, initdata, initkey)` - 页面跳转 - `http://` - 打开H5页面 - `!` - 打开原型图页面 - `*` - alert提示 - `$` - 需要登录 - `%` - 需要登录且完善信息 - `^` - 需要登录且实名认证 - `&` - 需要登录且绑定银行卡 - `goweb(url, name)` - 带授权打开H5页面 - `goloc(lat, lng, bet)` - 打开地图 - `gophone(phone)` - 拨打电话 **数据处理**: - `json_parse(data)` - 字符串转json - `json_string(data)` - json转字符串 - `toint(val)` - 转整数 - `tofloat(val)` - 转小数 - `tostr(val)` - 转字符串 - `tostamp(val)` - 转时间戳 - `todatetime(val)` - 时间戳转日期时间 - `tofix(val, dec)` - 处理小数显示 - `tounit(val)` - 显示多级单位 - `tocyc(val)` - 显示周期 月/天/分钟 - `tomsk(val)` - 显示文字遮罩 - `totimespan(val)` - 将时间转成 xx天后/xx小时前 - `totimesec(val)` - 将秒数转成 xx天/xx小时 - `totimepoint(val)` - 将数字转成 xx:xx[:xx] - `todayage(val)` - 返回日龄天数 - `tobr(val)` - 将\n替换成
,用于显示多行文本。结合 v-html 使用:`v-html="tobr(item.descs)"` - `topad0(num, len)` - 数字前面补0 - `tonumtho(num)` - 整数部分千分位显示 - `tonumdec(num)` - 小数部分 **类型校验**: - `isfloat0(val)` - 校验float是否0 - `isarray(val)` - 判断是否array - `isobject(val)` - 判断是否object - `islocalmedia(val)` - 判断是否本地文件 - `isimg(val)` - 是否图片 - `isvideo(val)` - 是否视频 - `file_ext(filename)` - 获取文件扩展名 - `file_stor(url)` - db存储的url转云存储的绝对url **字典处理**: - `ccode(catalog, val, key, def)` - 以id查询字典中的值 - `scode(catalog, vals, key)` - 以ids查询字典中的多个name - `mcode(catalog, val)` - 以id查询字典中的多级name - `bcode(catalog, val)` - 以int查询字典中的多个name - `hascode(val, codes)` - 某个数字是否在多个数字中 - `hasstr(str, substr)` - 字符串是否包含另一个字符串 **编码转换**: - `enbase64(str)` - base64编码 - `svg2bg(svg)` - 将svg转成backgroundImage语法 **其他工具**: - `sleep(ms)` - 延迟毫秒(await) - `copyboard(text)` - 拷贝文本 - `getstrparam(str, sep)` - 解析简易参数 - `urlparam(url)` - 解析url - `shareparam(opt)` - 分享链接转换 - `arrayfind(arr, val)` - 从数组中匹配值 - `objdeepmerge(dest, src)` - object合并 - `objtolist(list, obj/id)` - 将object并入list数组,将id从list数组中移除 - `objclone(obj)` - 深度复制obj - `str2date(str)` - 字符串转Date - `bin2hex(bin)` - bin转hex字符串 - `hex2bin(hex)` - hex字符串转bin - `style2obj(style)` - 将style属性转成object - `nopower(power)` - 权限检查 - `getroute()` - 获取当前路由 - `getpage(idx)` - 获取当前/上页页面 - `getrect(selector)` - 获取元素尺寸(await) - `file_upload1(file)` - 上传单个文件返回url(await) - `file_uploads(files)` - 上传多个文件(await) - `go(e, cb)` - golang式异步错误处理 - `goe(e, cb)` - golang式异步错误处理(增强版) **页面控制**: - `pagenoscroll(isno)` - 禁止页面滚动 - `settheme()` - 设置暗黑模式 - `setfont()` - 设置敬老模式 - `setTabbar()` - 设置Tabbar - `executepnt(pntid)` - 触发积分埋点 **加载资源**: - `load_ciydict()` - 获取远程静态dict(await) - `load_svgicon(url)` - 获取远程静态svgicon(await) **扫描功能**: - `scanqr()` - 扫二维码(await) ### 开发流程 **App.vue 全局配置**: - app.globalData.jsnurl.t,配置入口域名的API入口 例如 'https://ciyon.local.ciy.cn/ambap/' - 在development中 配置本地的入口域名的API入口(用于调试,一般以.local.ciy.cn为主体) - app.globalData.tabbarArr,作为底部TabBar定义,全局定义给ciy-tabbar组件使用。 - tabbar虽然自定义,但pages.json需正常配置。且App.vue的globalData.mainpage应指向首页。 - tabbar图标用svg定义,默认双色模式。选中颜色bgsel1/bgsel2,未选中颜色bggray1/bggray2。 - **tabbarArr 配置要点**: - `fullpath` 必须与实际页面路径一致,如 `/pages/aimap/index` - `name` 使用 i18n 代码,需在 `util/lang/*.json` 中同步配置翻译 - 所有 tabbar 页面都必须在模板底部添加 `` 组件 - **语言翻译配置**:所有 tabbar 的 name(如 tabbar.topic、tabbar.msg)需在所有语言文件(zh-Hans.json、en.json、zh-Hant.json、ja.json、fr.json)中添加对应的翻译 **新建页面**: 1. 在 `pages/` 对应模块下创建 `.vue` 文件 2. 在 `pages.json` 中注册页面路由 3. 使用组件和工具函数开发功能 **新建组件**: 1. 在 `components/` 下创建组件目录和文件 2. 组件名使用 `ciy-` 前缀 3. 支持通过 props 传递参数 4. 通过 $emit 触发事件 5. 有用户的明确指令,才能新建组件 **调用API**: 1. 确定API函数名,格式:`模块.方法`,如 `main.index_init` 2. 使用 `callfunc()` 发送请求: ```javascript var retjson = await this.callfunc({ func: 'main.index_init', data: { id: 123 } }); if (retjson.code != 1) return this.alert(retjson.errmsg); // 处理成功响应 ``` 3. 处理返回数据,成功时 `code=1`,失败时有 `errmsg` **首次请求优化**: 页面首次加载通过 `once` 标志位一次性返回所有初始化数据,减少后续翻页重复带出初始化数据: ```javascript async getlist() { this.pagepost.pageno = this.pageno + 1; this.pagepost.once = !this.init.once; var retjson = await this.callfunc({ func: 'demo.index_list', data: this.pagepost }); this.pageno++; if (this.pageno == 1) this.init.list = []; this.init = this.objdeepmerge(this.init, retjson); if (retjson.once) { } } ``` ### 样式规范 - 全局样式: `util/style.css` - 组件内使用 scoped CSS - 使用 rem 单位适配 ### 常用组件 **表单组件**:ciy-input、ciy-select、ciy-radio、ciy-checkbox、ciy-selbool、ciy-inputbet、ciy-upload等 **展示组件**:ciy-showmoney、ciy-showimgs、ciy-markdown等 **功能组件**:ciy-auth、ciy-dialog、ciy-toast、ciy-popmenu等 **导航组件**: - ciy-header - 页面头部(所有页面使用,navigationStyle为custom) - ciy-tabbar - 底部导航(tabbar页面必须添加) - ciy-segment - 分段器(使用 `:lis` 属性传递数组,如 `:lis="[{id:1,name:'选项1'}]"`,不要使用 `:options`) **地图组件**: - ciy-selmap - 国内地图选择组件(微信小程序用) - ciy-mapbox - 通用地图展示选择组件(基于 Leaflet) - 经纬度在数据库中存储时,应乘以 10000000,取整数 - 例如:30.2589121 → 存储为 302589121 - 在前端使用时,除以 10000000 恢复原始值 **ciy-mapbox组件地图瓦片提供商**: - 推荐使用 Esri World Imagery(卫星影像)+ CartoDB Positron Labels(标注层) - Esri World Imagery 提供高质量的卫星影像,适合展示地理位置 - CartoDB 标注层提供清晰的文字标注,可叠加在影像层上方 **复杂查询组件**: - ciy-query - 支持多种输入类型(input、select、checkbox、radio、date、range等) ### 常用配置 **pages.json** - 页面配置: - 页面路由 - 导航栏样式 - 底部TabBar(仅需配置 `pagePath`,其他配置由 App.vue 的 `tabbarArr` 定义) - 全局样式 - 分包配置:主包放置核心页面(如 aimap、pub),其他功能页面放入子包以优化性能 **manifest.json** - 应用配置: **manifest.json** - 应用配置: - 应用信息 - 权限配置 - SDK配置 - 多端打包设置 **vite.config.js** - 构建配置: - 别名配置 - 插件配置 - 构建优化 - 所有页面编译时都带ciy-auth、ciy-alert、ciy-toast、ciy-popmenu组件,无需手写 ## 框架已完成事项(无需开发) ### 注册登录、找回密码功能与后端login.*接口 复用,基本无需修改ciy-auth组件和login API接口 新建,需复制ap_user、ap_usr_*有关表结构。 登录成功,自动同时加载所有字典项到前端,前端缓存到localstorage备用。 ### 默认navigationStyle为custom 使用ciy-header组件定义顶部标题栏。可复制新组件自定义。 使用ciy-tabbar组件定义底部导航栏。可复制新组建自定义样式。已自动隐藏系统自带的默认tabbar。 ### 已完成通用组件 任意页面均支持未登录 弹出登录/注册界面。 弹出框已美化,支持ciy-alert、ciy-toast 弹出菜单已美化,ciy-popmenu组件,支持多种排版方式,突破了默认组件的数量限制。 ### 已给所有page注入通用变量 this.g,为所有缓存的字典项 this.me,为登录的用户完整数据 this.init,作为页面初始化,统一接收后端请求返回的数据。一般用this.init.code!=1作为骨架屏标识。 this.opn,页面传入参数可随意使用,不用在onload另行存储。 this.pageno,翻页页码 this.pagedata,页面间传递数据,对于页面深度点击传参非常有效。可替代vuex/Pinia this.pagepost,页面object变量 ## 注意事项 1. **命名规范**: 组件统一使用 `ciy-` 前缀目录 2. **API调用**: 使用 `callfunc()` 方法,函数名格式为 `模块.方法`,后端函数名必须与前端 func 参数对应 3. **Token管理**: 自动处理Token,无需手动管理,Token存储在 `localStorage` 中 4. **响应格式**: 成功 `{code: 1, ...}`,失败 `{code: 非1, errmsg: '错误信息', ...}` 5. **组件复用**: 优先使用现有组件,避免重复开发 6. **多端适配**: 使用uniapp条件编译处理平台差异 7. **性能优化**: - 使用 `cache` 参数设置缓存时间 - 避免频繁请求 - 使用 `loadhide: true` 取消不必要的加载提示 - 合理使用分包,主包放置核心页面,其他功能放入子包 8. **页面跳转**: 使用 `gourl()` 方法,支持多种特殊前缀($需要登录、*提示等) 9. **数据传递**: 使用 `pagedata` 对象进行页面间数据传递 10. **字典数据**: 通过 `g` 对象访问字典数据,自动同步更新 11. **用户信息**: 通过 `me` 对象访问当前用户信息 12. **路由参数**: 通过 `opn` 对象访问页面URL参数 13. **用户认证**: 注册、登录、找回密码等功能已集成在 `ciy-auth` 组件中,直接复用,无需重复开发 14. **TabBar配置**: - pages.json 中只配置 `pagePath`,其他样式由 App.vue 的 `tabbarArr` 定义 - tabbarArr 中的 `fullpath` 必须与实际页面路径完全一致 - 所有 tabbar 页面必须在模板底部添加 `` - tabbarArr 中的 `name` 需在所有语言文件中配置翻译 15. **组件使用注意**: - ciy-segment 使用 `:lis` 属性传递数组,不要使用 `:options` - 遵循框架定义的属性名称,避免使用非标准属性 ## 编译及自动调试 运行cmd,编译移动端H5 "D:\Program Files\HBuilderX\cli.exe" publish --platform h5 --project "D:\Dreams\ciy\ai_xxx\fapp\ciyon_ap" --webTitle 众产 编译后访问: https://xxx.local.ciy.cn/ 调试