diff --git a/Dockerfile b/Dockerfile index 997590c5f877bfec174f65ef514efe5e68139d38..d1186d85a818e43ee86b6ff9647eb1f524b8a58b 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,24 +1,21 @@ FROM gplane/pnpm as Builder -RUN pnpm -v - -RUN mkdir -p /home/openeuler/web -WORKDIR /home/openeuler/web -COPY . /home/openeuler/web - -RUN rm -rf ./app/ru +RUN mkdir -p /home/quick-issue/web +WORKDIR /home/quick-issue/web +COPY . /home/quick-issue/web RUN pnpm install + RUN pnpm build -FROM swr.cn-north-4.myhuaweicloud.com/opensourceway/openeuler/nginx:1.22.0-22.03-lts +FROM nginx:1.20.0 -COPY --from=Builder /home/openeuler/web/app/.vitepress/dist /usr/share/nginx/html/ +COPY --from=Builder /home/quick-issue/web/dist /usr/share/nginx/html/ RUN chmod -R 755 /usr/share/nginx/html -RUN rm -rf /usr/share/nginx/html/ru COPY ./deploy/nginx/nginx.conf /etc/nginx/nginx.conf + ENV RUN_USER nginx ENV RUN_GROUP nginx -EXPOSE 80 +EXPOSE 8080 ENTRYPOINT ["nginx", "-g", "daemon off;"] diff --git a/README.md b/README.md index 9745b2eca3081fb4bd8b1d7f4991217d50dc3ba5..07c077da0ff91f50649b1f4d893a33e59c27aa8f 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,22 @@ The repository of quick-issue 软件架构说明 -#### 安装教程 +```text + app + ├─ .vitepress + ├─ public // 静态资源文件,不参与打包编译 + ├─ src // 业务 + ├─ api // 接口 + ├─ assets // 资源文件 + ├─ components // 组件 + ├─ i18 // 国际化 + ├─ shared // 公用方法/样式 + ├─ stores // 状态管理 + ├─ views // 业务vue文件 + ├─ en // 英文页面 + ├─ ru // 俄文页面 + ├─ zh // 中文页面 +``` 1. xxxx 2. xxxx @@ -21,17 +36,32 @@ The repository of quick-issue #### 参与贡献 -1. Fork 本仓库 -2. 新建 Feat_xxx 分支 -3. 提交代码 -4. 新建 Pull Request +### 命名 +#### 命名形式 -#### 特技 +1. `camelCase`: 驼峰式 +2. `kebab-case`: 短横线连接式 +3. `PascalCase`: 帕斯卡命名式 +4. `Snake`: 下划线连接式 -1. 使用 Readme\_XXX.md 来支持不同的语言,例如 Readme\_en.md, Readme\_zh.md -2. Gitee 官方博客 [blog.gitee.com](https://blog.gitee.com) -3. 你可以 [https://gitee.com/explore](https://gitee.com/explore) 这个地址来了解 Gitee 上的优秀开源项目 -4. [GVP](https://gitee.com/gvp) 全称是 Gitee 最有价值开源项目,是综合评定出的优秀开源项目 -5. Gitee 官方提供的使用手册 [https://gitee.com/help](https://gitee.com/help) -6. Gitee 封面人物是一档用来展示 Gitee 会员风采的栏目 [https://gitee.com/gitee-stars/](https://gitee.com/gitee-stars/) +#### 说明 + +1. 文件夹以及文件命名(除 Vue SFC)采用`kebab-case` +2. Vue SFC 文件命名使用`PascalCase`, 在该文件中使用的 Vue 组件也使用`PascalCase` +3. Vue 组件中`emit`事件使用`kebab-case` +4. 变量以及方法命名使用`camelCase`, 资源文件使用`Snake`表明 light/dark, zh/en/ru,,`eg: homeBanner_light_zh`, 其中风格在前,语言在后 +5. CSS 使用`kebab-case`命名 +6. Icon 组件引入时增加 Icon 前缀,eg:`import IconDownload from '~icons/app/download'` + +### 开发规范 + +1. 所有接口类方法请写在`app/.vitepress/src/api`中,并按照[jsdoc 注释规范](https://www.shouce.ren/api/view/a/13232)给出注释,不同模块接口请按文件进行区分, eg: `api-cve.ts` +2. 公共 utils 方法请按[jsdoc 注释规范](https://www.shouce.ren/api/view/a/13232)给出注释 +3. 变量命名做到见名知义,方法命名使用动词或动宾结构, eg: `import warningImg from '@/assets/icons/warning.png`, `const getUserEmail=()=>{}` +4. 调用接口获取数据请使用`try {} catch(error) {}`进行校验 +5. 约束`for...in`的使用, 可以使用`Object.keys().forEach` +6. 使用`prettier`插件作为格式化工具 +7. 提交之前请先进行 eslint 检查: 执行脚本,运行`pnpm lint`。确认无问题后提交。项目工程的git hooks 已配置相关校验,如`git commit`不成功,请查看相关错误信息,并进行修改 +8. `git commit`信息请尽量参照[相关规范](https://zhuanlan.zhihu.com/p/182553920) +9. 其他注意事项请参考业界相关通用[开发规范说明](https://github.com/airbnb/javascript) diff --git a/auto-imports.d.ts b/auto-imports.d.ts index 2dbe5d93f5ff3a7e001914546283eb0e0e6f1ce8..08908edd6a4136cad144e7a483f291f9d9618be2 100644 --- a/auto-imports.d.ts +++ b/auto-imports.d.ts @@ -1,3 +1,5 @@ // Generated by 'unplugin-auto-import' -export {}; -declare global {} +export {} +declare global { + +} diff --git a/components.d.ts b/components.d.ts index f0c8a79a34e3156d249081caf715dd2717a7a229..a6db607bd6758860c9838c045ed08011f623785c 100644 --- a/components.d.ts +++ b/components.d.ts @@ -1,50 +1,43 @@ // generated by unplugin-vue-components // We suggest you to commit this file into source control // Read more: https://github.com/vuejs/core/pull/3399 -import '@vue/runtime-core'; +import '@vue/runtime-core' -export {}; +export {} declare module '@vue/runtime-core' { export interface GlobalComponents { - AppBanner: typeof import('./src/components/AppBanner.vue')['default']; - AppContent: typeof import('./src/components/AppContent.vue')['default']; - AppEditor: typeof import('./src/components/AppEditor.vue')['default']; - AppFooter: typeof import('./src/components/AppFooter.vue')['default']; - AppHeader: typeof import('./src/components/AppHeader.vue')['default']; - AppPaginationMo: typeof import('./src/components/AppPaginationMo.vue')['default']; - BannerLevel2: typeof import('./src/components/BannerLevel2.vue')['default']; - BannerLevel3: typeof import('./src/components/BannerLevel3.vue')['default']; - BreadCrumbs: typeof import('./src/components/BreadCrumbs.vue')['default']; - ElCard: typeof import('element-plus/es')['ElCard']; - ElCheckbox: typeof import('element-plus/es')['ElCheckbox']; - ElCollapse: typeof import('element-plus/es')['ElCollapse']; - ElCollapseItem: typeof import('element-plus/es')['ElCollapseItem']; - ElDialog: typeof import('element-plus/es')['ElDialog']; - ElDrawer: typeof import('element-plus/es')['ElDrawer']; - ElDropdown: typeof import('element-plus/es')['ElDropdown']; - ElDropdownItem: typeof import('element-plus/es')['ElDropdownItem']; - ElDropdownMenu: typeof import('element-plus/es')['ElDropdownMenu']; - ElForm: typeof import('element-plus/es')['ElForm']; - ElFormItem: typeof import('element-plus/es')['ElFormItem']; - ElInput: typeof import('element-plus/es')['ElInput']; - ElOption: typeof import('element-plus/es')['ElOption']; - ElPagination: typeof import('element-plus/es')['ElPagination']; - ElRadio: typeof import('element-plus/es')['ElRadio']; - ElScrollbar: typeof import('element-plus/es')['ElScrollbar']; - ElSelect: typeof import('element-plus/es')['ElSelect']; - ElSwitch: typeof import('element-plus/es')['ElSwitch']; - ElTable: typeof import('element-plus/es')['ElTable']; - ElTableColumn: typeof import('element-plus/es')['ElTableColumn']; - ElTabPane: typeof import('element-plus/es')['ElTabPane']; - ElTabs: typeof import('element-plus/es')['ElTabs']; - ElTag: typeof import('element-plus/es')['ElTag']; - ElTree: typeof import('element-plus/es')['ElTree']; - ElUpload: typeof import('element-plus/es')['ElUpload']; - HeaderNav: typeof import('./src/components/HeaderNav.vue')['default']; - ONav: typeof import('./src/components/ONav.vue')['default']; - RouterLink: typeof import('vue-router')['RouterLink']; - RouterView: typeof import('vue-router')['RouterView']; - SigLandscapeFeature: typeof import('./src/components/SigLandscapeFeature.vue')['default']; + AppContent: typeof import('./src/components/AppContent.vue')['default'] + AppEditor: typeof import('./src/components/AppEditor.vue')['default'] + AppFooter: typeof import('./src/components/AppFooter.vue')['default'] + AppHeader: typeof import('./src/components/AppHeader.vue')['default'] + ElCard: typeof import('element-plus/es')['ElCard'] + ElCheckbox: typeof import('element-plus/es')['ElCheckbox'] + ElCollapse: typeof import('element-plus/es')['ElCollapse'] + ElCollapseItem: typeof import('element-plus/es')['ElCollapseItem'] + ElDialog: typeof import('element-plus/es')['ElDialog'] + ElDrawer: typeof import('element-plus/es')['ElDrawer'] + ElDropdown: typeof import('element-plus/es')['ElDropdown'] + ElDropdownItem: typeof import('element-plus/es')['ElDropdownItem'] + ElDropdownMenu: typeof import('element-plus/es')['ElDropdownMenu'] + ElForm: typeof import('element-plus/es')['ElForm'] + ElFormItem: typeof import('element-plus/es')['ElFormItem'] + ElInput: typeof import('element-plus/es')['ElInput'] + ElOption: typeof import('element-plus/es')['ElOption'] + ElPagination: typeof import('element-plus/es')['ElPagination'] + ElScrollbar: typeof import('element-plus/es')['ElScrollbar'] + ElSelect: typeof import('element-plus/es')['ElSelect'] + ElSwitch: typeof import('element-plus/es')['ElSwitch'] + ElTable: typeof import('element-plus/es')['ElTable'] + ElTableColumn: typeof import('element-plus/es')['ElTableColumn'] + ElTabPane: typeof import('element-plus/es')['ElTabPane'] + ElTabs: typeof import('element-plus/es')['ElTabs'] + ElTree: typeof import('element-plus/es')['ElTree'] + ElUpload: typeof import('element-plus/es')['ElUpload'] + HeaderNav: typeof import('./src/components/HeaderNav.vue')['default'] + ONav: typeof import('./src/components/ONav.vue')['default'] + RouterLink: typeof import('vue-router')['RouterLink'] + RouterView: typeof import('vue-router')['RouterView'] + SigLandscapeFeature: typeof import('./src/components/SigLandscapeFeature.vue')['default'] } } diff --git a/deploy/nginx/nginx.conf b/deploy/nginx/nginx.conf index 6a6e323ef2af2073a19ceab236304ea7c1c869b5..e806f36284edd2625687dd1269dfdd110bf2cbbc 100644 --- a/deploy/nginx/nginx.conf +++ b/deploy/nginx/nginx.conf @@ -1,40 +1,24 @@ worker_processes auto; -error_log /dev/stdout warn; +error_log /var/log/nginx/error.log warn; pid /var/run/nginx.pid; -load_module /etc/nginx/modules/ngx_http_geoip2_module.so; - worker_rlimit_nofile 4096; events { use epoll; worker_connections 4096; } + http { include /etc/nginx/mime.types; - geoip2 /etc/nginx/geoip/GeoLite2-Country.mmdb { - $geoip2_city_country_code source=$http_true_client_ip country iso_code; - $geoip2_city_country_name source=$http_true_client_ip country names en; - } - - geoip2 /etc/nginx/geoip/GeoLite2-City.mmdb { - $geoip2_city source=$http_true_client_ip city names en; - } - - log_format main '[$time_local] "remote_addr": "$remote_addr"' - '"x_forwarded_for": "$http_x_forwarded_for"' - '"true-client-ip": "$http_true_client_ip"' - '"$request"' - '"geoip2_city_country_code": "$geoip2_city_country_code"' - '"geoip2_city_country_name": "$geoip2_city_country_name"' - '"geoip2_city": "$geoip2_city"' + log_format main '$remote_addr - $remote_user [$time_local] "$request" ' '$status $body_bytes_sent "$http_referer" ' - '"$http_user_agent"'; + '"$http_user_agent" "$http_x_forwarded_for"'; - access_log /dev/stdout main; + access_log /var/log/nginx/access.log main; autoindex off; sendfile on; @@ -75,19 +59,13 @@ http { # charset utf-8; listen 8080; + server_name localhost; charset utf-8; limit_conn perserver 50; if ($request_method = 'OPTIONS') { return 401; } - location = / { - rewrite ^/$ /zh/issues/ redirect; - } - location = /zh/ { - rewrite ^/zh/$ /zh/issues/ redirect; - } - location / { location /assets { # publish every two weeks @@ -97,6 +75,14 @@ http { location / { add_header Cache-Control no-cache; } + + location = / { + rewrite ^/$ /zh/issues/ redirect; + } + location = /zh/ { + rewrite ^/zh/$ /zh/issues/ redirect; + } + location /api-issues/ { # proxy_pass http://119.8.32.82/; proxy_pass https://ipb.osinfra.cn/; @@ -106,10 +92,14 @@ http { } root /usr/share/nginx/html; - index index.html; + index /index.html; # error_page 404 /404.html; } + location ~ ^/(quick-issue) { + try_files $uri /index.html; + } + error_page 500 501 502 503 504 505 /500.html; error_page 401 /401.html; error_page 404 /404.html; diff --git a/index.html b/index.html index 0193f3b4bc3d70b3c9846597bfe355749983d293..9170f28ee49d9a4108c4eb9a6f996ed27730b53d 100644 --- a/index.html +++ b/index.html @@ -1,13 +1,16 @@ -
- - - -