This commit is contained in:
chorblack 2025-04-26 14:01:41 +08:00
commit b7dc29435a
19 changed files with 1543 additions and 0 deletions

27
.gitignore vendored Normal file
View File

@ -0,0 +1,27 @@
.DS_Store
node_modules
/dist
/build
/logs
# sign
# local env files
.env.local
.env.*.local
# Log files
npm-debug.log*
yarn-debug.log*
yarn-error.log*
# Editor directories and files
.idea
.vscode
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw*
.ide
.preview.json

6
.prettierignore Normal file
View File

@ -0,0 +1,6 @@
package.json
manifest.json
README.md
# assets/js
src/assets/js/*.js

36
README.md Normal file
View File

@ -0,0 +1,36 @@
# 手表示例模版
## 文件结构
```
├── sign # 存储 rpk 包签名模块(须自行生成);
│ ├── certificate.pem # 证书文件
│ └── private.pem # 私钥文件
└── src
│ ├── assets # 公用的资源(images/styles/字体...)
│ │ ├──images # 存储 png/jpg/svg 等公共图片资源
│ │ └──styles # 存放 less/css/sass 等公共样式资源
│ ├── pages # 统一存放项目页面级代码
│ ├── app.ux # 应用程序代码的入口文件
│ ├── manifest.json # 配置蓝河应用基本信息
│ └── components # 存放蓝河应用组件
└── package.json # 定义项目需要的各种模块及配置信息
```
### 模版说明
- `Demo` 页面:示例页面;
- `DemoDetail`页面:详情页面;
## 如何使用
- **内置样式处理方案**;「蓝河应用」支持 `sass` 的预编译;这里采取 [dart sass](https://sass-lang.com/documentation) 方案,并内置了部分变量,以及常用混合方法,使得可以轻松开启样式编写、复用、修改等;
- **添加新增页面命令脚本**;如果需要新建页面,只需运行:`yarn gen YourPageName` ,当然,也可以根据需要,自行定定制模板:*/command/gen/template.ux*
- **集成 [Prettier](https://prettier.io/)**;在检测代码中潜在问题的同时,统一团队代码规范、风格(`js``less``scss`等),从而促使写出高质量代码,以提升工作效率(尤其针对团队开发)
## 内置命令
| 命令 | 描述 | 备注 |
|---|---|---|
| `yarn gen ` | 新增「蓝河应用」页面 | 助你高效生成页面,模版可自定义,推荐 ✓|
| `yarn prettier` | 一键美化代码(js/css/less/ux) | 实在是团队开发好帮手,推荐 ✓ |

17
jsconfig.json Normal file
View File

@ -0,0 +1,17 @@
{
"compilerOptions": {
"noImplicitAny": false,
"strict": true,
"noUnusedLocals": true,
"noImplicitThis": true,
"noUnusedParameters": true,
"allowSyntheticDefaultImports": true,
"forceConsistentCasingInFileNames": true,
"esModuleInterop": true,
"resolveJsonModule": true,
"skipLibCheck": true,
"checkJs": true
},
"include": ["src/**/*"],
"exclude": ["node_modules"]
}

41
package.json Normal file
View File

@ -0,0 +1,41 @@
{
"name": "testschedule",
"version": "1.1.0",
"packageManager": "pnpm@7.1.0",
"description": "Watch Template",
"scripts": {
"gen": "node ./scripts/gen/index.js",
"precommit-msg": "echo '🚧 start pre-commit checks ...' && exit 0",
"prettier": "node ./scripts/selfCloseInputTag.js && prettier --write \"src/**/*.{js,ux,less,scss,css}\""
},
"devDependencies": {
"colors": "^1.4.0",
"husky": "^4.3.0",
"lint-staged": "^10.5.1",
"prettier": "^1.15.3",
"prettier-plugin-ux": "^0.3.0"
},
"prettier": {
"singleQuote": true,
"semi": false,
"printWidth": 80,
"proseWrap": "never",
"tabWidth": 2
},
"husky": {
"hooks": {
"pre-commit": "yarn run precommit-msg && lint-staged"
}
},
"lint-staged": {
"**/**.{ux,js,json,pcss,md,vue}": [
"prettier --write",
"git add"
]
},
"keywords": [
"多终端应用",
"手表示例",
"手表模版"
]
}

1013
pnpm-lock.yaml generated Normal file

File diff suppressed because it is too large Load Diff

87
scripts/gen/index.js Normal file
View File

@ -0,0 +1,87 @@
/**
* @desc: gen script commandmake a new page generated by one click.
* @author: nicejade
*/
const fs = require('fs')
const path = require('path')
const colors = require('colors')
const newFolderName = process.argv[2]
String.prototype.firstUpperCase = function() {
return this.replace(/\b(\w)/g, $1 => {
return $1.toLowerCase()
})
}
const resolve = dir => {
return path.join(__dirname, '../..', dir)
}
const successExecPrint = msg => {
console.log(
colors.green(``) +
colors.cyan(`${msg} `) +
colors.green('task has been successfully executed.')
)
}
function createNewPage(newFolderPath) {
const mReg = new RegExp('@PAGE_CLASS_NAME', 'g')
const pageContent = fs.readFileSync(`${__dirname}/template.ux`, 'UTF-8')
const rootClassName = newFolderName
.firstUpperCase()
.replace(/([A-Z])/g, '-$1')
.toLowerCase()
const newContent = pageContent.replace(mReg, rootClassName)
fs.mkdirSync(newFolderPath, 0777)
fs.writeFile(`${newFolderPath}/index.ux`, newContent, error => {
if (error) throw `Something went wrong: ${error}`
})
successExecPrint('Create New Page')
}
function saveRouter2Manifest() {
const manifestPath = resolve('/src/manifest.json')
let manifestConf = fs.readFileSync(manifestPath, 'UTF-8')
manifestConf = JSON.parse(manifestConf)
const routerPages = manifestConf.router.pages
routerPages[`pages/${newFolderName}`] = {
component: 'index'
}
manifestConf = JSON.stringify(manifestConf, null, 2)
fs.writeFile(manifestPath, manifestConf, error => {
if (error) throw `Something went wrong[@saveRouter2Manifest]: ${error}`
})
successExecPrint('Save Router Into Manifest')
}
function main() {
if (!newFolderName) {
return console.warn(
`⚠️ Please enter the name of the page you want to create.`.underline.red
)
}
const folderNameReg = /^[A-Z][[A-Za-z0-9]+$/
if (!folderNameReg.test(newFolderName)) {
return console.warn(
`⚠️ Please enter the standard Folder name. Eg: XyzAbcde.`.underline.red
)
}
const newFolderPath = path.join(__dirname, `../../src/pages/${newFolderName}`)
const isExist = fs.existsSync(newFolderPath)
if (isExist) {
return console.warn(
`⚠️ ${newFolderName} already exists in the /src/pages/ directory.`
.underline.red
)
}
createNewPage(newFolderPath)
saveRouter2Manifest()
}
main()

27
scripts/gen/template.ux Normal file
View File

@ -0,0 +1,27 @@
<template>
<div class="wrapper">
<text class="title">{{ title }}</text>
</div>
</template>
<script>
export default {
data: {
title: '欢迎体验多终端应用开发'
},
onInit() {}
}
</script>
<style lang="scss">
@import './../../assets/styles/style.scss';
.wrapper {
@include flex-box-mixins(column, center, center);
.title {
font-size: 8 * $size-factor;
text-align: center;
color: $black;
}
}
</style>

View File

@ -0,0 +1,36 @@
/**
* @file: selfCloseInputTag.js
* @desc: 遍历指定目录下 .ux 文件将其中 input 标签由 <input **></input> 转换为 <input ** />
* @date: 2019-01-23
*/
const fs = require('fs')
const path = require('path')
const codePath = './src/'
const main = codePath => {
const traversing = cpath => {
const files = fs.readdirSync(cpath)
files.forEach(fileName => {
const fPath = path.join(cpath, fileName)
const stats = fs.statSync(fPath)
stats.isDirectory() && traversing(fPath)
stats.isFile() && fPath.endsWith('.ux') && matchAndReplace(fPath)
})
}
traversing(codePath)
}
const matchAndReplace = path => {
const pageContent = fs.readFileSync(path, 'UTF-8')
const newContent = pageContent.replace(
/(<)([\s]*?)(input\b[^\/]*?)>[\s\S]*?<\/input>/gm,
'$1$3 />'
)
fs.writeFile(path, newContent, error => {
if (error) throw `Something went wrong: ${error}`
})
}
main(codePath)

35
sign/certificate.pem Normal file
View File

@ -0,0 +1,35 @@
-----BEGIN CERTIFICATE-----
MIIGHjCCBAagAwIBAgIJAKhp5sS6vdNrMA0GCSqGSIb3DQEBCwUAMIGjMQswCQYD
VQQGEwJaSDESMBAGA1UECAwJR3VhbmdEb25nMRIwEAYDVQQHDAlTaGVuIHpoZW4x
ITAfBgNVBAoMGEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDETMBEGA1UECwwKT3Bl
cmF0aW9uczEQMA4GA1UEAwwHZGVmYXVsdDEiMCAGCSqGSIb3DQEJARYTZGVmYXVs
dEBkZWZhdWx0LmNvbTAeFw0yNTA0MjYwNTI1MTJaFw0zNTA0MjQwNTI1MTJaMIGj
MQswCQYDVQQGEwJaSDESMBAGA1UECAwJR3VhbmdEb25nMRIwEAYDVQQHDAlTaGVu
IHpoZW4xITAfBgNVBAoMGEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDETMBEGA1UE
CwwKT3BlcmF0aW9uczEQMA4GA1UEAwwHZGVmYXVsdDEiMCAGCSqGSIb3DQEJARYT
ZGVmYXVsdEBkZWZhdWx0LmNvbTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoC
ggIBAMmdDe26LstLddBzmzUgoOGB2vtH2B1x/jKFAEB325PKNS0HIq6hMtLkmyla
/4EqZNVZcxjw6ZXiXZd1dTr74IjRaRdyQJTkfCLyhTbsFdqrYrPO3FhgS2nbqR2g
dYQs9C5W5B4TlHM+LkHUY9hkT4HhiAg+GKPO4gDl6ePzG6SKDQSHgHINh0LXz5Tw
l8OzQMG9mS4kfIXkC87DQoAMySZ6CsgveN2aYbpZVxXIJvsGADHRbk9LhICd2IsU
kw+YvQtg4XShj7ErfL9J4Gp5zufyDycIqqcrYiFVJeqRVI5olH+WGFDoZg2D7wyi
uMxMuspNuxqXxyrhS83YSPxzFGPLI3y5V30p3BlpVTIhraDYtSILTwpNhio48Btz
JA5glNS0Xm/BeM8Uy2sUhJcV4JV2IwDXpDxuAcrWESjCjZxd5J0NEiukQToV7pNe
G/GuIXggvzzgPS2YBBndynpzh5NcKcN5dsltGrpdmx/zzEiv3OhXYi6iOqF/jccY
/hFVFIvqVZZ1uSnE9MOL7ipkeAR4iz8e2JS5osHjHzbhPKjb+Le4kdyNoTzNWkiJ
rSGel6UL4jtVayqTJ1gfo8h8IJoBXa0+I5069jjj7zW2+B8MX0NR3ny7Bparowf/
bMe4v6PP72OrL4tv80oncZOSj5LF7zn5BAngv+eabeFI92UhAgMBAAGjUzBRMB0G
A1UdDgQWBBSBIPL2F+bK7DoSxoo7+YeB7+FVizAfBgNVHSMEGDAWgBSBIPL2F+bK
7DoSxoo7+YeB7+FVizAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IC
AQCi01qnW1v0rzNuOQmbMqO1MiJXD3wBj17dAVeHcvjKyN8BzPDFNS6/Xpuwwu3f
CHx6z6l6kVlGyxz9VE6Q3UVcImA2b8Q7JA1ePT3rry/7pur3yK1G3GmPF+ZELSjc
4+y+3AI2auI/JTJd5Q8rpv460amzwV+oH0gnf9V5MtxkVAKvyVK2RBTBlbYp8Nhg
elYz5PqzcnLw7mbQWEhjQYsetXSkBJMOpIlnRNaGIQOZhpKvywAPQqMtkQW6XSA7
DyWLdxeaLsxyZKsmueLJT+4ekodZcHXmyc7RXhIFJm3Zc+9/xLsRO2rSA4fxZqeq
lk67nwyKomjRxEqZeelmBOERQemnpvRN5Ftyoxkuc/CitttKO6Keg5D7LbrzlwIH
PWxyBET+ffIWPnjUuBOFtOD2aa3LHXdX3L3M83dUO0Nh5XnCQFpv/eY3YZE1vyRM
IZ8n2AscwF7bddWnFXV+2GnPnJQzrH1ns7lu8vYXkAzQ+3ryWJ13ohMOgfTcQbHt
+7Ekr+M31OD4BOXv15oaw5hmxt/6AcmHzWFle7lx2U1ilM4TYGauyGFHCmJPtXhd
xsNy67zHhmSsMGOEFFr7lGF2AL4T8LSEGA6TVfnvlLUQXoeBX/74YmEipj8yqRVX
+kHU1+xXeu8brnaiROmHXDj1QyYoaDj1SDh71+n0P8x6hA==
-----END CERTIFICATE-----

52
sign/private.pem Normal file
View File

@ -0,0 +1,52 @@
-----BEGIN PRIVATE KEY-----
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
IwDw0kiYIvAvClOiqhoMykztAFij0YI=
-----END PRIVATE KEY-----

13
src/app.ux Normal file
View File

@ -0,0 +1,13 @@
<script>
/**
* 应用级别的配置,供所有页面公用
*/
import prompt from '@blueos.window.prompt'
export default {
scheduleFunc(params) {
console.log(`background processing color = ${params.color}`)
prompt.showToast({message:params.color});
},
onCreate() {}
}
</script>

BIN
src/assets/images/logo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

View File

@ -0,0 +1,5 @@
@mixin flex-box-mixins($direction: row, $justify: center, $align-items: center) {
flex-direction: $direction;
justify-content: $justify;
align-items: $align-items;
}

View File

@ -0,0 +1,2 @@
@import './variables.scss';
@import './mixins.scss';

View File

@ -0,0 +1,9 @@
$brand: #09ba07;
$white: #ffffff;
$black: #000000;
$grey: #9393aa;
$red: #fa0101;
$green: #ffff00;
$size-factor: 5px;

38
src/manifest.json Normal file
View File

@ -0,0 +1,38 @@
{
"package": "top.chorblack.testschedule",
"name": "testschedule",
"versionName": "1.0.0",
"versionCode": 1,
"appCategory": [
"other"
],
"icon": "/assets/images/logo.png",
"features": [
{
"name": "blueos.app.appmanager.router"
},
{ "name": "blueos.app.appmanager.schedule" },
{ "name": "blueos.window.prompt" }
],
"deviceTypeList": [
"watch",
"watch-square"
],
"config": {
"designWidth": 466
},
"router": {
"entry": "pages/Demo",
"pages": {
"pages/Demo": {
"component": "index"
},
"pages/DemoDetail": {
"component": "index"
}
}
},
"display": {
"backgroundColor": "#ffffff"
}
}

72
src/pages/Demo/index.ux Normal file
View File

@ -0,0 +1,72 @@
<template>
<div class="wrapper">
<text class="title">{{ title }}</text>
<input
class="btn"
type="button"
value="跳转到详情页"
onclick="onDetailBtnClick" />
<input
class="btn"
type="button"
value="跳转到详情页"
onclick="onCancelClick" />
</div>
</template>
<script>
import schedule from '@blueos.app.appmanager.schedule'
export default {
data: {
title: '👏欢迎体验应用开发',
id:null,
},
onInit() {},
onCancelClick(){
schedule.cancel(this.id);
},
onDetailBtnClick() {
schedule.scheduleJob({
type: 2,
timeout: 2000,
interval: 1000,
triggerMethod: 'scheduleFunc',
params: {
color: 'red',
},
success :(data)=> {
console.log(`handling success, scheduleId = ${data.id}`);
this.id = data.id;
},
fail: function (data, code) {
console.log(`handling fail,code = ${data},${code}`)
}
})
},
}
</script>
<style lang="scss">
@import './../../assets/styles/style.scss';
.wrapper {
@include flex-box-mixins(column, center, center);
.title {
font-size: 7 * $size-factor;
text-align: center;
color: $black;
}
.btn {
width: 55 * $size-factor;
height: 12 * $size-factor;
border-radius: 7 * $size-factor;
background-color: $brand;
color: $white;
font-size: 5 * $size-factor;
margin-top: 7 * $size-factor;
}
}
</style>

View File

@ -0,0 +1,27 @@
<template>
<div class="wrapper">
<text class="title">{{ text }}</text>
</div>
</template>
<script>
export default {
data: {
text: '你好,世界'
}
}
</script>
<style lang="scss">
@import './../../assets/styles/style.scss';
.wrapper {
@include flex-box-mixins(column, center, center);
margin: 0 10 * $size-factor;
.title {
font-size: 8 * $size-factor;
text-align: center;
color: $black;
}
}
</style>