1
0
mirror of https://github.com/chatopera/cosin.git synced 2025-08-01 16:38:02 +08:00

init: frontend monorepo

Signed-off-by: Kaifuny <superbiger.github@gmail.com>
This commit is contained in:
Kaifuny 2023-07-20 00:43:19 +08:00
parent 666f96b2d0
commit b3a7bba279
166 changed files with 7737 additions and 0 deletions

View File

@ -0,0 +1,59 @@
module.exports = {
root: true,
env: {
'vue/setup-compiler-macros': true,
node: true,
},
parser: 'vue-eslint-parser',
parserOptions: {
parser: '@typescript-eslint/parser',
sourceType: 'module',
},
'plugins': [
'@typescript-eslint',
],
extends: [
'eslint:recommended',
'plugin:vue/vue3-recommended',
'plugin:prettier/recommended',
'plugin:@typescript-eslint/recommended',
],
rules: {
'@typescript-eslint/no-unused-vars': 'error',
'no-empty-pattern': 'error',
'no-useless-escape': 'error',
'prettier/prettier': [
'error',
{
useTabs: false,
tabWidth: 2,
singleQuote: true,
trailingComma: 'es5',
printWidth: 80,
semi: false,
spacedComment: true
},
],
'vue/no-mutating-props': 'error',
'vue/no-unused-components': 'error',
'vue/no-useless-template-attributes': 'error',
'@typescript-eslint/no-explicit-any': 'off',
'vue/multi-word-component-names': 'off',
},
ignorePatterns: [
'node_modules',
'build',
'dist',
'public',
'*.d.ts',
'*.cjs',
],
overrides: [
{
files: ['./*.js'],
env: {
node: true,
},
},
],
}

28
contact-frontend/.gitignore vendored Normal file
View File

@ -0,0 +1,28 @@
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
lerna-debug.log*
node_modules
.DS_Store
dist
dist-ssr
coverage
*.local
/cypress/videos/
/cypress/screenshots/
# Editor directories and files
.vscode/*
!.vscode/extensions.json
.idea
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?

View File

@ -0,0 +1,12 @@
**/.git
**/node_modules
**/public
**/assets
**/.husky
**/.vscode
**/env
**/dist
**/build
**/coverage
**/*.html

View File

@ -0,0 +1,60 @@
# 春松客服 - 前端项目相关
## 项目结构
```
├── README.md
├── env
│   ├── .env.dev
│   ├── .env.mock
│   ├── .env.release
├── packages
│   ├── apps
│   │   ├── cskefu # web 端
│   ├── assets # 静态资源
│   ├── modules
│   │   ├── composables # 全局 composables
│   │   ├── models # 全局 models
│   │   ├── locales # 本地化数据
│   │   ├── mocks # mock 数据
│   │   ├── services
│   │   │   ├── dashboard # 工作台相关
│   │   │   ├── chat # 客服对话聊天相关
│   │   │   ├── worker-order # 工单模块
│   │   │   ├── seats # 坐席模块
│   │   │   ├── setting # 组织设置相关
│   │   │   ├── system # 系统设置模块
│   │   │   ├── auth # 权限/登录相关
│   ├── plugins # 插件 (开发使用的三方库例如ProseMirror)
│   │   ├── prose-mirror # prose-mirror 插件
│   │   ├── directives # 自定义指令
│   ├── widgets # 小组件
│   │   ├── core
│   │   ├── sdk
│   ├── shared
│   │   ├── ui # 全局 UI 组件
│   │   ├── utils # 全局 utils
├── public
├── scripts
├── tools
│   │   ├── setup-naiveui
│   │   ├── setup-tailwind
```
## How to Develop
### 1. 安装依赖
```bash
pnpm install
```
### 2. 启动项目
```bash
pnpm run dev
```
## License
[春松许可证 v1.0](https://www.cskefu.com/2023/06/25/chunsong-public-license-1-0/)

0
contact-frontend/env/.env.dev vendored Normal file
View File

0
contact-frontend/env/.env.mock vendored Normal file
View File

0
contact-frontend/env/.env.release vendored Normal file
View File

1
contact-frontend/env/vite-env.d.ts vendored Normal file
View File

@ -0,0 +1 @@
/// <reference types="vite/client" />

View File

@ -0,0 +1,54 @@
{
"name": "contact-frontend",
"private": true,
"version": "0.0.0",
"type": "module",
"scripts": {
"dev": "pnpm run -C packages/apps/web dev",
"mock": "vite packages/apps/web",
"build": "",
"build:web": "",
"build:widgets-sdk": "",
"lint": "eslint -c .eslintrc.cjs --ext .ts,.tsx,.vue --ignore-path .gitignore .",
"lint:fix": "eslint -c .eslintrc.cjs --ext .ts,.tsx,.vue --ignore-path .gitignore . --fix",
"test": "",
"test:all": "",
"test:coverage": "",
"prettier": "prettier . --write",
"prepare": "cd .. && husky install"
},
"dependencies": {
"@vicons/ionicons5": "^0.12.0",
"@vueuse/core": "^10.2.1",
"axios": "^1.4.0",
"pinia": "^2.1.4",
"vue": "^3.3.4",
"vue-router": "^4.2.4"
},
"devDependencies": {
"@intlify/unplugin-vue-i18n": "^0.12.0",
"@types/lodash-es": "^4.17.8",
"@types/node": "^20.4.2",
"@typescript-eslint/eslint-plugin": "^6.1.0",
"@typescript-eslint/parser": "^6.0.0",
"@vitejs/plugin-vue": "^4.2.3",
"@vitejs/plugin-vue-jsx": "^3.0.1",
"@vue/eslint-config-prettier": "^7.1.0",
"eslint": "^8.39.0",
"eslint-plugin-prettier": "^5.0.0",
"eslint-plugin-vue": "^9.11.0",
"husky": "^8.0.3",
"lodash-es": "^4.17.21",
"msw": "^1.2.2",
"naive-ui": "^2.34.4",
"prettier": "3.0.0",
"typescript": "^5.0.2",
"vite": "^4.4.0",
"vitest": "^0.33.0",
"vue-i18n": "^9.2.2",
"vue-tsc": "^1.8.3"
},
"msw": {
"workerDirectory": "public"
}
}

View File

@ -0,0 +1,3 @@
# 项目入口
> 多模块集约化入口

View File

@ -0,0 +1,13 @@
<!DOCTYPE html>
<html lang="en" class="h-full bg-gray-100">
<head>
<meta charset="UTF-8" >
<meta name="naive-ui-style" >
<meta name="viewport" content="width=device-width, initial-scale=1.0" >
<title>春松客服</title>
</head>
<body class="h-full">
<div id="app" class="h-full"></div>
<script type="module" src="/src/main.ts"></script>
</body>
</html>

View File

@ -0,0 +1,33 @@
{
"name": "@cskefu/web",
"private": true,
"version": "0.0.0",
"type": "module",
"scripts": {
"dev": "vite",
"build": "vue-tsc && vite build",
"preview": "vite preview"
},
"dependencies": {
"@cskefu/assets": "*",
"@cskefu/i18n": "*",
"@cskefu/models": "*",
"@cskefu/services-auth": "*",
"@cskefu/services-chat": "*",
"@cskefu/services-dashboard": "*",
"@cskefu/services-seats": "*",
"@cskefu/services-organization": "*",
"@cskefu/services-setting": "*",
"@cskefu/services-system": "*",
"@cskefu/services-enterprise": "*",
"@cskefu/services-work-order": "*",
"@cskefu/shared-utils": "*",
"@cskefu/shared-ui": "*"
},
"devDependencies": {
"@cskefu/setup-tailwind": "*",
"tailwindcss": "^3.3.3",
"autoprefixer": "^10.4.14",
"postcss": "^8.4.26"
}
}

View File

@ -0,0 +1,6 @@
module.exports = {
plugins: {
tailwindcss: {},
autoprefixer: {},
},
}

View File

@ -0,0 +1,6 @@
<script setup lang="ts">
import { RouterView } from 'vue-router'
</script>
<template>
<router-view></router-view>
</template>

View File

@ -0,0 +1,3 @@
@tailwind base;
@tailwind components;
@tailwind utilities;

View File

@ -0,0 +1,74 @@
<script setup lang="ts">
import { ref } from 'vue'
import { RouterLink, RouterView, useRouter } from 'vue-router'
import { Nav } from '@cskefu/shared-ui'
import { NSwitch, NIcon, NAlert } from 'naive-ui'
import { SunnyOutline, Moon, Earth } from '@vicons/ionicons5'
import { ROUTE_NAME } from '@cskefu/models'
const navigations = [
{ label: '首页', value: ROUTE_NAME.DASHBOARD_INDEX },
{ label: '对话', value: ROUTE_NAME.CHAT_INDEX },
{ label: '工单', value: ROUTE_NAME.WORK_ORDER_INDEX },
{ label: '坐席', value: ROUTE_NAME.SEATS_INDEX },
{ label: '组织', value: ROUTE_NAME.ORGANIZATION_INDEX },
{ label: '设置', value: ROUTE_NAME.SETTING_INDEX },
]
const dropdownMenus = [
{ label: '个人中心', value: ROUTE_NAME.PROFILE_INDEX },
{ label: '企业设置', value: ROUTE_NAME.ENTERPRISE_INDEX },
{ label: '系统设置', value: ROUTE_NAME.SYSTEM_INDEX },
{ label: '意见反馈', value: 'reedback' },
{ label: '关于我们', value: 'about' },
{ label: '退出登录', value: 'logout' },
]
// TODO url
const current = ref<string>(ROUTE_NAME.DASHBOARD_INDEX)
const router = useRouter()
</script>
<template>
<div class="flex flex-col h-screen bg-gray-100">
<n-alert type="warning" closable class="text-center">
欢迎使用春松客服系统2024-01-01
到期剩余30天如继续试用请联系管理员
</n-alert>
<Nav
v-model:current="current"
avatar-url="https://avatars.githubusercontent.com/u/499270?v=4"
:navigations="navigations"
:dropdown-menus="dropdownMenus"
@update:current="
(name: string) => {
router.push({ name })
}
"
>
<RouterLink class="text-sm text-green-600" to="/index">
使用指南
</RouterLink>
<template #dropMenuAppend>
<div class="flex justify-between items-center">
<div class="flex justify-between items-center space-x-2">
<n-icon :component="Earth" />
<span>中文</span>
</div>
<n-switch size="medium">
<template #checked-icon>
<n-icon :component="Moon" />
</template>
<template #unchecked-icon>
<n-icon :component="SunnyOutline" />
</template>
</n-switch>
</div>
</template>
</Nav>
<div class="grow overflow-hidden">
<router-view></router-view>
</div>
</div>
</template>

View File

@ -0,0 +1,7 @@
import { createApp } from 'vue'
import App from './App.vue'
import './index.css'
import router from './router'
import i18n from '@cskefu/i18n'
createApp(App).use(router).use(i18n).mount('#app')

View File

@ -0,0 +1,48 @@
import { RouteRecordRaw, createRouter, createWebHashHistory } from 'vue-router'
import { ROUTE_NAME } from '@cskefu/models'
import { routes as authRoutes } from '@cskefu/services-auth'
import { routes as dashboardRoutes } from '@cskefu/services-dashboard'
import { routes as settingRoutes } from '@cskefu/services-setting'
import { routes as systemRoutes } from '@cskefu/services-system'
import { routes as seatsRoutes } from '@cskefu/services-seats'
import { routes as organizationRoutes } from '@cskefu/services-organization'
import { routes as chatRoutes } from '@cskefu/services-chat'
import { routes as workOrderRoutes } from '@cskefu/services-work-order'
import { routes as enterpriseRoutes } from '@cskefu/services-enterprise'
import NavLayout from '../layouts/NavLayout.vue'
const routes: RouteRecordRaw[] = [
{
path: '/',
component: () => import('../views/HomeView.vue'),
},
{
path: '/login',
redirect: { name: ROUTE_NAME.AUTH_LOGIN },
},
{
path: '/index',
component: NavLayout,
children: [
...dashboardRoutes,
...chatRoutes,
...workOrderRoutes,
...seatsRoutes,
...organizationRoutes,
...settingRoutes,
...systemRoutes,
...enterpriseRoutes,
],
},
...authRoutes,
]
const router = createRouter({
history: createWebHashHistory(),
routes,
})
export default router

View File

@ -0,0 +1,7 @@
import { ComponentCustomProperties } from './shims-vue-global.d';
declare module "vue" {
export interface ComponentCustomProperties {
$t: (key: string) => string;
}
}

View File

@ -0,0 +1,3 @@
<template>
<div>一个很漂亮的首页</div>
</template>

View File

@ -0,0 +1,12 @@
/** @type {import('tailwindcss').Config} */
// eslint-disable-next-line no-undef
import base from '@cskefu/setup-tailwind'
export default {
...base,
content: [
'./index.html',
'./src/**/*.{vue,js,ts,jsx,tsx}',
'./node_modules/@cskefu/**/*.{vue,js,ts,jsx,tsx}',
],
}

View File

@ -0,0 +1,9 @@
{
"extends": "../../../tsconfig.json",
"include": ["src/**/*.ts", "src/**/*.d.ts", "src/**/*.tsx", "src/**/*.vue"],
"compilerOptions": {
"baseUrl": "./",
"types": ["vite/client", "naive-ui/volar"]
},
"references": [{ "path": "./tsconfig.node.json" }]
}

View File

@ -0,0 +1,10 @@
{
"compilerOptions": {
"composite": true,
"skipLibCheck": true,
"module": "ESNext",
"moduleResolution": "bundler",
"allowSyntheticDefaultImports": true,
},
"include": ["vite.config.ts"]
}

View File

@ -0,0 +1,20 @@
import { resolve } from 'path'
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import vueJsx from '@vitejs/plugin-vue-jsx'
import VueI18nPlugin from '@intlify/unplugin-vue-i18n/vite'
// https://vitejs.dev/config/
export default defineConfig({
publicDir: resolve(__dirname, '../../../public'),
plugins: [
vue(),
vueJsx(),
VueI18nPlugin({
include: [
resolve(__dirname, 'node_modules/@cskefu/locales/src/locales/**'),
],
}),
],
})

View File

@ -0,0 +1 @@
# 项目资源

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 77 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

View File

@ -0,0 +1,6 @@
{
"name": "@cskefu/assets",
"private": true,
"version": "0.0.0",
"type": "module"
}

View File

@ -0,0 +1,14 @@
{
"name": "@cskefu/composables",
"private": true,
"version": "0.0.0",
"type": "module",
"exports": {
".": {
"import": {
"node": "./src/index.ts",
"default": "./src/index.ts"
}
}
}
}

View File

@ -0,0 +1 @@
# 国际化模块

View File

@ -0,0 +1,14 @@
{
"name": "@cskefu/i18n",
"private": true,
"version": "0.0.0",
"type": "module",
"exports": {
".": {
"import": {
"node": "./src/index.ts",
"default": "./src/index.ts"
}
}
}
}

View File

@ -0,0 +1,29 @@
import { App } from 'vue'
import { createI18n } from 'vue-i18n'
const messages = {
'en-US': {
message: {
hello: 'hello world',
},
},
'zh-CN': {
message: {
hello: '你好',
},
},
}
const i18n = createI18n({
legacy: false,
locale: 'zh-CN',
messages,
globalInjection: true,
fallbackLocale: 'zh-CN',
})
const install = (app: App) => {
app.use(i18n)
}
export default install

View File

@ -0,0 +1,5 @@
{
"message": {
"hello": "hello world"
}
}

View File

@ -0,0 +1,5 @@
{
"message": {
"hello": "你好"
}
}

View File

@ -0,0 +1,12 @@
{
"extends": "../../../tsconfig.json",
"include": ["src/**/*.ts"],
"compilerOptions": {
"composite": true,
"skipLibCheck": true,
"module": "ESNext",
"moduleResolution": "bundler",
"resolvePackageJsonExports": false,
"allowSyntheticDefaultImports": true,
}
}

View File

@ -0,0 +1 @@
# Mock 模块

View File

@ -0,0 +1,14 @@
{
"name": "@cskefu/mocks",
"private": true,
"version": "0.0.0",
"type": "module",
"exports": {
".": {
"import": {
"node": "./src/index.ts",
"default": "./src/index.ts"
}
}
}
}

View File

@ -0,0 +1,14 @@
{
"name": "@cskefu/models",
"private": true,
"version": "0.0.0",
"type": "module",
"exports": {
".": {
"import": {
"node": "./src/index.ts",
"default": "./src/index.ts"
}
}
}
}

View File

@ -0,0 +1 @@
export * from './routes'

View File

@ -0,0 +1,59 @@
export enum ROUTE_NAME {
// ==================================================================================
// 公共路由
// ==================================================================================
PROFILE_INDEX = 'PROFILE_INDEX', // 个人中心
NOT_FOUND = 'NOT_FOUND', // 404
FORBIDDEN = 'FORBIDDEN', // 403
SERVER_ERROR = 'SERVER_ERROR', // 500
REDIRECT = 'REDIRECT', // 302
// ==================================================================================
// 模块路由
// ==================================================================================
// 认证模块
AUTH_LOGIN = 'AUTH_LOGIN',
// 看板模块
DASHBOARD_INDEX = 'DASHBOARD_INDEX',
// 对话模块
CHAT_INDEX = 'CHAT_INDEX',
// 工单模块
WORK_ORDER_INDEX = 'WORK_ORDER_INDEX',
// 坐席模块
SEATS_INDEX = 'SEATS_INDEX',
SEATS_DASHBOARD_INDEX = 'SEATS_DASHBOARD_INDEX', // 坐席看板
SEATS_CHATMANAGE_INDEX = 'SEATS_CHATMANAGE_INDEX', // 会话管理
SEATS_LEAVEMANAGE_INDEX = 'SEATS_LEAVEMANAGE_INDEX', // 留言管理
SEATS_SEATSMANAGE_INDEX = 'SEATS_SEATSMANAGE_INDEX', // 坐席管理
SEATS_ROBOTMANAGE_INDEX = 'SEATS_ROBOTMANAGE_INDEX', // 机器人管理
// 组织管理模块
ORGANIZATION_INDEX = 'ORGANIZATION_INDEX',
ORGANIZATION_ADMIN_INDEX = 'ORGANIZATION_ADMIN_INDEX', // 管理员 - 组织管理设置
ORGANIZATION_USERS_INDEX = 'ORGANIZATION_USERS_INDEX', // 账号管理
ORGANIZATION_ROLES_INDEX = 'ORGANIZATION_ROLES_INDEX', // 角色管理
// 设置模块
SETTING_INDEX = 'SETTING_INDEX',
SETTING_KNOWLEDGE_INDEX = 'SETTING_KNOWLEDGE_INDEX', // 知识库
SETTING_WORKORDER_INDEX = 'SETTING_WORKORDER_INDEX', // 工单
SETTING_LEAVEMESSAGE_INDEX = 'ENTERPRISE_LEAVEMESSAGE_INDEX', // 留言
// 企业设置模块
ENTERPRISE_INDEX = 'ENTERPRISE_INDEX',
ENTERPRISE_KEFU_INDEX = 'ENTERPRISE_KEFU_INDEX', // 客服设置
ENTERPRISE_CHANNEL_INDEX = 'ENTERPRISE_CHANNEL_INDEX', // 接入
ENTERPRISE_CHAT_INDEX = 'ENTERPRISE_CHAT_INDEX', // 对话
ENTERPRISE_CUSTOMER_INDEX = 'ENTERPRISE_CUSTOMER_INDEX', // 客户
// 系统设置模块
SYSTEM_INDEX = 'SYSTEM_INDEX',
SYSTEM_INFO_INDEX = 'SYSTEM_INFO_INDEX', // 系统信息
SYSTEM_SOURCE_INDEX = 'SYSTEM_SOURCE_INDEX', // 源数据
SYSTEM_NOTIFICATION_INDEX = 'SYSTEM_NOTIFICATION_INDEX', // 通知
SYSTEM_SOCIAL_INDEX = 'SYSTEM_SOCIAL_INDEX', // 三方登录
SYSTEM_OSS_INDEX = 'SYSTEM_OSS_INDEX', // OSS
SYSTEM_CDN_INDEX = 'SYSTEM_CDN_INDEX', // CDN
SYSTEM_GPT_INDEX = 'SYSTEM_GPT_INDEX', // GPT
SYSTEM_SMS_INDEX = 'SYSTEM_SMS_INDEX', // 短信
SYSTEM_CALL_INDEX = 'SYSTEM_CALL_INDEX', // 呼叫
SYSTEM_LOG_INDEX = 'SYSTEM_LOG_INDEX', // 日志
// =================================================================================
}

View File

@ -0,0 +1,8 @@
{
"extends": "../../../tsconfig.json",
"include": ["src/**/*.ts", "src/**/*.d.ts", "src/**/*.tsx"],
"compilerOptions": {
"baseUrl": "./",
"types": ["vite/client", "naive-ui/volar"],
}
}

View File

@ -0,0 +1 @@
# 登录/认证模块

View File

@ -0,0 +1,29 @@
{
"name": "@cskefu/services-auth",
"private": true,
"version": "0.0.0",
"type": "module",
"dependencies": {
"@cskefu/assets": "*",
"@cskefu/mocks": "*",
"@cskefu/models": "*",
"@cskefu/i18n": "*",
"@cskefu/composables": "*",
"@cskefu/shared-utils": "*",
"@cskefu/shared-ui": "*"
},
"devDependencies": {
"@cskefu/setup-tailwind": "*",
"tailwindcss": "^3.3.3",
"autoprefixer": "^10.4.14",
"postcss": "^8.4.26"
},
"exports": {
".": {
"import": {
"node": "./src/index.ts",
"default": "./src/index.ts"
}
}
}
}

View File

@ -0,0 +1,4 @@
import LoginView from './views/LoginView.vue'
import routes from './routes/index.ts'
export { LoginView, routes }

View File

@ -0,0 +1,25 @@
import { RouteRecordRaw } from 'vue-router'
import { IndexLayout } from '@cskefu/shared-ui'
import { ROUTE_NAME } from '@cskefu/models'
const routes: RouteRecordRaw[] = [
{
path: '/auth',
component: IndexLayout,
redirect: { name: ROUTE_NAME.AUTH_LOGIN },
children: [
{
path: 'login',
name: ROUTE_NAME.AUTH_LOGIN,
component: () => import('../views/LoginView.vue'),
meta: {
title: '登录',
auth: false,
},
},
],
},
]
export default routes

View File

@ -0,0 +1,7 @@
import { ComponentCustomProperties } from './shims-vue-global.d';
declare module "vue" {
export interface ComponentCustomProperties {
$t: (key: string) => string;
}
}

View File

@ -0,0 +1,49 @@
<script setup lang="ts">
import bgUrl from '@cskefu/assets/img/login-bg.svg'
import logoUrl from '@cskefu/assets/img/logo.png'
import { LogoWechat, LogoGithub } from '@vicons/ionicons5'
import { NInput, NButton, NDivider, NIcon } from 'naive-ui'
</script>
<template>
<main class="w-full h-full m-auto flex row align-middle">
<div
class="hidden md:flex items-center justify-center w-1/2 h-full bg-gradient-to-t to-emerald-500 from-10% from-indigo-500 to-90%"
>
<img :src="bgUrl" alt="春松客服" class="w-full" />
</div>
<div
class="flex flex-col justify-center items-center w-full h-full space-y-5 md:w-1/2"
>
<img :src="logoUrl" alt="春松客服" width="300" />
<h1 class="text-xl">{{ $t('message.hello') }}</h1>
<form class="p-2 space-y-5">
<n-input
type="text"
size="large"
:placeholder="`${'用户名'}/${'邮箱'}/${'手机号'}`"
/>
<n-input
type="password"
size="large"
:placeholder="'密码'"
autocomplete
/>
<n-button class="w-full h-10 bg-green-600 text-white">{{
'登录'
}}</n-button>
<n-divider title-placement="center" class="text-sm">
{{ '第三方登录' }}
</n-divider>
<div class="flex justify-center space-x-5">
<n-icon size="32" class="text-green-500">
<logo-wechat />
</n-icon>
<n-icon size="32">
<logo-github />
</n-icon>
</div>
</form>
</div>
</main>
</template>

View File

@ -0,0 +1,9 @@
{
"extends": "../../../../tsconfig.json",
"include": ["src/**/*.ts", "src/**/*.d.ts", "src/**/*.tsx", "src/**/*.vue", "src/index.ts"],
"compilerOptions": {
"baseUrl": "./",
"types": ["vite/client", "naive-ui/volar"],
},
"references": [{ "path": "./tsconfig.node.json" }]
}

View File

@ -0,0 +1,10 @@
{
"compilerOptions": {
"composite": true,
"skipLibCheck": true,
"module": "ESNext",
"moduleResolution": "bundler",
"allowSyntheticDefaultImports": true
},
"include": ["vite.config.ts"]
}

View File

@ -0,0 +1,18 @@
import { resolve } from 'path'
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import vueJsx from '@vitejs/plugin-vue-jsx'
import VueI18nPlugin from '@intlify/unplugin-vue-i18n/vite'
// https://vitejs.dev/config/
export default defineConfig({
publicDir: resolve(__dirname, '../../../../public'),
plugins: [
vue(),
vueJsx(),
VueI18nPlugin({
include: [resolve(__dirname, 'node_modules/@cskefu/locales/**')],
}),
],
})

View File

@ -0,0 +1 @@
# 聊天模块

View File

@ -0,0 +1,29 @@
{
"name": "@cskefu/services-chat",
"private": true,
"version": "0.0.0",
"type": "module",
"dependencies": {
"@cskefu/assets": "*",
"@cskefu/mocks": "*",
"@cskefu/models": "*",
"@cskefu/i18n": "*",
"@cskefu/composables": "*",
"@cskefu/shared-utils": "*",
"@cskefu/shared-ui": "*"
},
"devDependencies": {
"@cskefu/setup-tailwind": "*",
"tailwindcss": "^3.3.3",
"autoprefixer": "^10.4.14",
"postcss": "^8.4.26"
},
"exports": {
".": {
"import": {
"node": "./src/index.ts",
"default": "./src/index.ts"
}
}
}
}

View File

@ -0,0 +1,3 @@
import routes from './routes'
export { routes }

View File

@ -0,0 +1,123 @@
<script setup lang="ts">
import { MenusLayout } from '@cskefu/shared-ui'
import { NMenu } from 'naive-ui'
const menuOptions = [
{
label: '且听风吟',
key: 'hear-the-wind-sing',
href: 'https://baike.baidu.com/item/%E4%B8%94%E5%90%AC%E9%A3%8E%E5%90%9F/3199',
},
{
label: '1973年的弹珠玩具',
key: 'pinball-1973',
children: [
{
label: '鼠',
key: 'rat',
},
],
},
{
label: '寻羊冒险记',
key: 'a-wild-sheep-chase',
},
{
label: '舞,舞,舞',
key: 'dance-dance-dance',
children: [
{
type: 'group',
label: '人物',
key: 'people',
children: [
{
label: '叙事者',
key: 'narrator',
},
{
label: '羊男',
key: 'sheep-man',
},
],
},
{
label: '饮品',
key: 'beverage',
children: [
{
label: '威士忌',
key: 'whisky',
href: 'https://baike.baidu.com/item/%E5%A8%81%E5%A3%AB%E5%BF%8C%E9%85%92/2959816?fromtitle=%E5%A8%81%E5%A3%AB%E5%BF%8C&fromid=573&fr=aladdin',
},
],
},
{
label: '食物',
key: 'food',
children: [
{
label: '三明治',
key: 'sandwich',
},
],
},
{
label: '过去增多,未来减少',
key: 'the-past-increases-the-future-recedes',
},
],
},
{
label: '舞,舞,舞',
key: 'dance-dance-dance',
children: [
{
type: 'group',
label: '人物',
key: 'people',
children: [
{
label: '叙事者',
key: 'narrator',
},
{
label: '羊男',
key: 'sheep-man',
},
],
},
{
label: '饮品',
key: 'beverage',
children: [
{
label: '威士忌',
key: 'whisky',
href: 'https://baike.baidu.com/item/%E5%A8%81%E5%A3%AB%E5%BF%8C%E9%85%92/2959816?fromtitle=%E5%A8%81%E5%A3%AB%E5%BF%8C&fromid=573&fr=aladdin',
},
],
},
{
label: '食物',
key: 'food',
children: [
{
label: '三明治',
key: 'sandwich',
},
],
},
{
label: '过去增多,未来减少',
key: 'the-past-increases-the-future-recedes',
},
],
},
]
</script>
<template>
<MenusLayout>
<n-menu :options="menuOptions" />
</MenusLayout>
</template>

View File

@ -0,0 +1,22 @@
import { RouteRecordRaw } from 'vue-router'
import { ROUTE_NAME } from '@cskefu/models'
import Layout from '../layouts/MenusLayout.vue'
const routes: RouteRecordRaw[] = [
{
path: '/chat',
name: 'chat',
component: Layout,
redirect: '/chat/index',
children: [
{
path: 'index',
name: ROUTE_NAME.CHAT_INDEX,
component: () => import('../views/HomeView.vue'),
},
],
},
]
export default routes

View File

@ -0,0 +1,7 @@
import { ComponentCustomProperties } from './shims-vue-global.d';
declare module "vue" {
export interface ComponentCustomProperties {
$t: (key: string) => string;
}
}

View File

@ -0,0 +1,3 @@
<template>
<div>chat home</div>
</template>

View File

@ -0,0 +1,9 @@
{
"extends": "../../../../tsconfig.json",
"include": ["src/**/*.ts", "src/**/*.d.ts", "src/**/*.tsx", "src/**/*.vue", "src/index.ts"],
"compilerOptions": {
"baseUrl": "./",
"types": ["vite/client", "naive-ui/volar"],
},
"references": [{ "path": "./tsconfig.node.json" }]
}

View File

@ -0,0 +1,10 @@
{
"compilerOptions": {
"composite": true,
"skipLibCheck": true,
"module": "ESNext",
"moduleResolution": "bundler",
"allowSyntheticDefaultImports": true
},
"include": ["vite.config.ts"]
}

View File

@ -0,0 +1,18 @@
import { resolve } from 'path'
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import vueJsx from '@vitejs/plugin-vue-jsx'
import VueI18nPlugin from '@intlify/unplugin-vue-i18n/vite'
// https://vitejs.dev/config/
export default defineConfig({
publicDir: resolve(__dirname, '../../../../public'),
plugins: [
vue(),
vueJsx(),
VueI18nPlugin({
include: [resolve(__dirname, 'node_modules/@cskefu/locales/**')],
}),
],
})

View File

@ -0,0 +1 @@
# 看板模块

View File

@ -0,0 +1,29 @@
{
"name": "@cskefu/services-dashboard",
"private": true,
"version": "0.0.0",
"type": "module",
"dependencies": {
"@cskefu/assets": "*",
"@cskefu/mocks": "*",
"@cskefu/models": "*",
"@cskefu/i18n": "*",
"@cskefu/composables": "*",
"@cskefu/shared-utils": "*",
"@cskefu/shared-ui": "*"
},
"devDependencies": {
"@cskefu/setup-tailwind": "*",
"tailwindcss": "^3.3.3",
"autoprefixer": "^10.4.14",
"postcss": "^8.4.26"
},
"exports": {
".": {
"import": {
"node": "./src/index.ts",
"default": "./src/index.ts"
}
}
}
}

View File

@ -0,0 +1,3 @@
import routes from './routes'
export { routes }

View File

@ -0,0 +1,26 @@
import { RouteRecordRaw } from 'vue-router'
import { IndexLayout } from '@cskefu/shared-ui'
import { ROUTE_NAME } from '@cskefu/models'
const routes: RouteRecordRaw[] = [
{
path: '/dashboard',
name: 'dashboard',
component: IndexLayout,
redirect: { name: ROUTE_NAME.DASHBOARD_INDEX },
children: [
{
path: 'index',
name: ROUTE_NAME.DASHBOARD_INDEX,
component: () => import('../views/DashboardView.vue'),
meta: {
title: '数据看板',
auth: true,
},
},
],
},
]
export default routes

View File

@ -0,0 +1,7 @@
import { ComponentCustomProperties } from './shims-vue-global.d';
declare module "vue" {
export interface ComponentCustomProperties {
$t: (key: string) => string;
}
}

View File

@ -0,0 +1,5 @@
<template>
<div class="dashboard-view">
<h1>Dashboard</h1>
</div>
</template>

View File

@ -0,0 +1,9 @@
{
"extends": "../../../../tsconfig.json",
"include": ["src/**/*.ts", "src/**/*.d.ts", "src/**/*.tsx", "src/**/*.vue", "src/index.ts"],
"compilerOptions": {
"baseUrl": "./",
"types": ["vite/client", "naive-ui/volar"],
},
"references": [{ "path": "./tsconfig.node.json" }]
}

View File

@ -0,0 +1,10 @@
{
"compilerOptions": {
"composite": true,
"skipLibCheck": true,
"module": "ESNext",
"moduleResolution": "bundler",
"allowSyntheticDefaultImports": true
},
"include": ["vite.config.ts"]
}

View File

@ -0,0 +1,18 @@
import { resolve } from 'path'
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import vueJsx from '@vitejs/plugin-vue-jsx'
import VueI18nPlugin from '@intlify/unplugin-vue-i18n/vite'
// https://vitejs.dev/config/
export default defineConfig({
publicDir: resolve(__dirname, '../../../../public'),
plugins: [
vue(),
vueJsx(),
VueI18nPlugin({
include: [resolve(__dirname, 'node_modules/@cskefu/locales/**')],
}),
],
})

View File

@ -0,0 +1 @@
# 坐席模块

View File

@ -0,0 +1,29 @@
{
"name": "@cskefu/services-enterprise",
"private": true,
"version": "0.0.0",
"type": "module",
"dependencies": {
"@cskefu/assets": "*",
"@cskefu/mocks": "*",
"@cskefu/models": "*",
"@cskefu/i18n": "*",
"@cskefu/composables": "*",
"@cskefu/shared-utils": "*",
"@cskefu/shared-ui": "*"
},
"devDependencies": {
"@cskefu/setup-tailwind": "*",
"tailwindcss": "^3.3.3",
"autoprefixer": "^10.4.14",
"postcss": "^8.4.26"
},
"exports": {
".": {
"import": {
"node": "./src/index.ts",
"default": "./src/index.ts"
}
}
}
}

View File

@ -0,0 +1,3 @@
import routes from './routes'
export { routes }

View File

@ -0,0 +1,123 @@
<script setup lang="ts">
import { MenusLayout } from '@cskefu/shared-ui'
import { NMenu } from 'naive-ui'
const menuOptions = [
{
label: '且听风吟',
key: 'hear-the-wind-sing',
href: 'https://baike.baidu.com/item/%E4%B8%94%E5%90%AC%E9%A3%8E%E5%90%9F/3199',
},
{
label: '1973年的弹珠玩具',
key: 'pinball-1973',
children: [
{
label: '鼠',
key: 'rat',
},
],
},
{
label: '寻羊冒险记',
key: 'a-wild-sheep-chase',
},
{
label: '舞,舞,舞',
key: 'dance-dance-dance',
children: [
{
type: 'group',
label: '人物',
key: 'people',
children: [
{
label: '叙事者',
key: 'narrator',
},
{
label: '羊男',
key: 'sheep-man',
},
],
},
{
label: '饮品',
key: 'beverage',
children: [
{
label: '威士忌',
key: 'whisky',
href: 'https://baike.baidu.com/item/%E5%A8%81%E5%A3%AB%E5%BF%8C%E9%85%92/2959816?fromtitle=%E5%A8%81%E5%A3%AB%E5%BF%8C&fromid=573&fr=aladdin',
},
],
},
{
label: '食物',
key: 'food',
children: [
{
label: '三明治',
key: 'sandwich',
},
],
},
{
label: '过去增多,未来减少',
key: 'the-past-increases-the-future-recedes',
},
],
},
{
label: '舞,舞,舞',
key: 'dance-dance-dance',
children: [
{
type: 'group',
label: '人物',
key: 'people',
children: [
{
label: '叙事者',
key: 'narrator',
},
{
label: '羊男',
key: 'sheep-man',
},
],
},
{
label: '饮品',
key: 'beverage',
children: [
{
label: '威士忌',
key: 'whisky',
href: 'https://baike.baidu.com/item/%E5%A8%81%E5%A3%AB%E5%BF%8C%E9%85%92/2959816?fromtitle=%E5%A8%81%E5%A3%AB%E5%BF%8C&fromid=573&fr=aladdin',
},
],
},
{
label: '食物',
key: 'food',
children: [
{
label: '三明治',
key: 'sandwich',
},
],
},
{
label: '过去增多,未来减少',
key: 'the-past-increases-the-future-recedes',
},
],
},
]
</script>
<template>
<MenusLayout>
<n-menu :options="menuOptions" />
</MenusLayout>
</template>

View File

@ -0,0 +1,22 @@
import { RouteRecordRaw } from 'vue-router'
import { ROUTE_NAME } from '@cskefu/models'
import Layout from '../layouts/MenusLayout.vue'
const routes: RouteRecordRaw[] = [
{
path: '/organization',
name: 'organization',
component: Layout,
redirect: '/organization/index',
children: [
{
path: 'index',
name: ROUTE_NAME.ENTERPRISE_INDEX,
component: () => import('../views/HomeView.vue'),
},
],
},
]
export default routes

View File

@ -0,0 +1,7 @@
import { ComponentCustomProperties } from './shims-vue-global';
declare module "vue" {
export interface ComponentCustomProperties {
$t: (key: string) => string;
}
}

View File

@ -0,0 +1,3 @@
<template>
<div>enterprise home</div>
</template>

View File

@ -0,0 +1,9 @@
{
"extends": "../../../../tsconfig.json",
"include": ["src/**/*.ts", "src/**/*.d.ts", "src/**/*.tsx", "src/**/*.vue", "src/index.ts"],
"compilerOptions": {
"baseUrl": "./",
"types": ["vite/client", "naive-ui/volar"],
},
"references": [{ "path": "./tsconfig.node.json" }]
}

View File

@ -0,0 +1,10 @@
{
"compilerOptions": {
"composite": true,
"skipLibCheck": true,
"module": "ESNext",
"moduleResolution": "bundler",
"allowSyntheticDefaultImports": true
},
"include": ["vite.config.ts"]
}

View File

@ -0,0 +1,18 @@
import { resolve } from 'path'
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import vueJsx from '@vitejs/plugin-vue-jsx'
import VueI18nPlugin from '@intlify/unplugin-vue-i18n/vite'
// https://vitejs.dev/config/
export default defineConfig({
publicDir: resolve(__dirname, '../../../../public'),
plugins: [
vue(),
vueJsx(),
VueI18nPlugin({
include: [resolve(__dirname, 'node_modules/@cskefu/locales/**')],
}),
],
})

View File

@ -0,0 +1 @@
# 坐席模块

View File

@ -0,0 +1,29 @@
{
"name": "@cskefu/services-organization",
"private": true,
"version": "0.0.0",
"type": "module",
"dependencies": {
"@cskefu/assets": "*",
"@cskefu/mocks": "*",
"@cskefu/models": "*",
"@cskefu/i18n": "*",
"@cskefu/composables": "*",
"@cskefu/shared-utils": "*",
"@cskefu/shared-ui": "*"
},
"devDependencies": {
"@cskefu/setup-tailwind": "*",
"tailwindcss": "^3.3.3",
"autoprefixer": "^10.4.14",
"postcss": "^8.4.26"
},
"exports": {
".": {
"import": {
"node": "./src/index.ts",
"default": "./src/index.ts"
}
}
}
}

View File

@ -0,0 +1,3 @@
import routes from './routes'
export { routes }

View File

@ -0,0 +1,123 @@
<script setup lang="ts">
import { MenusLayout } from '@cskefu/shared-ui'
import { NMenu } from 'naive-ui'
const menuOptions = [
{
label: '且听风吟',
key: 'hear-the-wind-sing',
href: 'https://baike.baidu.com/item/%E4%B8%94%E5%90%AC%E9%A3%8E%E5%90%9F/3199',
},
{
label: '1973年的弹珠玩具',
key: 'pinball-1973',
children: [
{
label: '鼠',
key: 'rat',
},
],
},
{
label: '寻羊冒险记',
key: 'a-wild-sheep-chase',
},
{
label: '舞,舞,舞',
key: 'dance-dance-dance',
children: [
{
type: 'group',
label: '人物',
key: 'people',
children: [
{
label: '叙事者',
key: 'narrator',
},
{
label: '羊男',
key: 'sheep-man',
},
],
},
{
label: '饮品',
key: 'beverage',
children: [
{
label: '威士忌',
key: 'whisky',
href: 'https://baike.baidu.com/item/%E5%A8%81%E5%A3%AB%E5%BF%8C%E9%85%92/2959816?fromtitle=%E5%A8%81%E5%A3%AB%E5%BF%8C&fromid=573&fr=aladdin',
},
],
},
{
label: '食物',
key: 'food',
children: [
{
label: '三明治',
key: 'sandwich',
},
],
},
{
label: '过去增多,未来减少',
key: 'the-past-increases-the-future-recedes',
},
],
},
{
label: '舞,舞,舞',
key: 'dance-dance-dance',
children: [
{
type: 'group',
label: '人物',
key: 'people',
children: [
{
label: '叙事者',
key: 'narrator',
},
{
label: '羊男',
key: 'sheep-man',
},
],
},
{
label: '饮品',
key: 'beverage',
children: [
{
label: '威士忌',
key: 'whisky',
href: 'https://baike.baidu.com/item/%E5%A8%81%E5%A3%AB%E5%BF%8C%E9%85%92/2959816?fromtitle=%E5%A8%81%E5%A3%AB%E5%BF%8C&fromid=573&fr=aladdin',
},
],
},
{
label: '食物',
key: 'food',
children: [
{
label: '三明治',
key: 'sandwich',
},
],
},
{
label: '过去增多,未来减少',
key: 'the-past-increases-the-future-recedes',
},
],
},
]
</script>
<template>
<MenusLayout>
<n-menu :options="menuOptions" />
</MenusLayout>
</template>

View File

@ -0,0 +1,22 @@
import { RouteRecordRaw } from 'vue-router'
import { ROUTE_NAME } from '@cskefu/models'
import Layout from '../layouts/MenusLayout.vue'
const routes: RouteRecordRaw[] = [
{
path: '/organization',
name: 'organization',
component: Layout,
redirect: '/organization/index',
children: [
{
path: 'index',
name: ROUTE_NAME.ORGANIZATION_INDEX,
component: () => import('../views/HomeView.vue'),
},
],
},
]
export default routes

View File

@ -0,0 +1,7 @@
import { ComponentCustomProperties } from './shims-vue-global';
declare module "vue" {
export interface ComponentCustomProperties {
$t: (key: string) => string;
}
}

View File

@ -0,0 +1,3 @@
<template>
<div>organiaztion home</div>
</template>

View File

@ -0,0 +1,9 @@
{
"extends": "../../../../tsconfig.json",
"include": ["src/**/*.ts", "src/**/*.d.ts", "src/**/*.tsx", "src/**/*.vue", "src/index.ts"],
"compilerOptions": {
"baseUrl": "./",
"types": ["vite/client", "naive-ui/volar"],
},
"references": [{ "path": "./tsconfig.node.json" }]
}

View File

@ -0,0 +1,10 @@
{
"compilerOptions": {
"composite": true,
"skipLibCheck": true,
"module": "ESNext",
"moduleResolution": "bundler",
"allowSyntheticDefaultImports": true
},
"include": ["vite.config.ts"]
}

View File

@ -0,0 +1,18 @@
import { resolve } from 'path'
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import vueJsx from '@vitejs/plugin-vue-jsx'
import VueI18nPlugin from '@intlify/unplugin-vue-i18n/vite'
// https://vitejs.dev/config/
export default defineConfig({
publicDir: resolve(__dirname, '../../../../public'),
plugins: [
vue(),
vueJsx(),
VueI18nPlugin({
include: [resolve(__dirname, 'node_modules/@cskefu/locales/**')],
}),
],
})

View File

@ -0,0 +1 @@
# 坐席模块

View File

@ -0,0 +1,29 @@
{
"name": "@cskefu/services-seats",
"private": true,
"version": "0.0.0",
"type": "module",
"dependencies": {
"@cskefu/assets": "*",
"@cskefu/mocks": "*",
"@cskefu/models": "*",
"@cskefu/i18n": "*",
"@cskefu/composables": "*",
"@cskefu/shared-utils": "*",
"@cskefu/shared-ui": "*"
},
"devDependencies": {
"@cskefu/setup-tailwind": "*",
"tailwindcss": "^3.3.3",
"autoprefixer": "^10.4.14",
"postcss": "^8.4.26"
},
"exports": {
".": {
"import": {
"node": "./src/index.ts",
"default": "./src/index.ts"
}
}
}
}

View File

@ -0,0 +1,3 @@
import routes from './routes'
export { routes }

View File

@ -0,0 +1,123 @@
<script setup lang="ts">
import { MenusLayout } from '@cskefu/shared-ui'
import { NMenu } from 'naive-ui'
const menuOptions = [
{
label: '且听风吟',
key: 'hear-the-wind-sing',
href: 'https://baike.baidu.com/item/%E4%B8%94%E5%90%AC%E9%A3%8E%E5%90%9F/3199',
},
{
label: '1973年的弹珠玩具',
key: 'pinball-1973',
children: [
{
label: '鼠',
key: 'rat',
},
],
},
{
label: '寻羊冒险记',
key: 'a-wild-sheep-chase',
},
{
label: '舞,舞,舞',
key: 'dance-dance-dance',
children: [
{
type: 'group',
label: '人物',
key: 'people',
children: [
{
label: '叙事者',
key: 'narrator',
},
{
label: '羊男',
key: 'sheep-man',
},
],
},
{
label: '饮品',
key: 'beverage',
children: [
{
label: '威士忌',
key: 'whisky',
href: 'https://baike.baidu.com/item/%E5%A8%81%E5%A3%AB%E5%BF%8C%E9%85%92/2959816?fromtitle=%E5%A8%81%E5%A3%AB%E5%BF%8C&fromid=573&fr=aladdin',
},
],
},
{
label: '食物',
key: 'food',
children: [
{
label: '三明治',
key: 'sandwich',
},
],
},
{
label: '过去增多,未来减少',
key: 'the-past-increases-the-future-recedes',
},
],
},
{
label: '舞,舞,舞',
key: 'dance-dance-dance',
children: [
{
type: 'group',
label: '人物',
key: 'people',
children: [
{
label: '叙事者',
key: 'narrator',
},
{
label: '羊男',
key: 'sheep-man',
},
],
},
{
label: '饮品',
key: 'beverage',
children: [
{
label: '威士忌',
key: 'whisky',
href: 'https://baike.baidu.com/item/%E5%A8%81%E5%A3%AB%E5%BF%8C%E9%85%92/2959816?fromtitle=%E5%A8%81%E5%A3%AB%E5%BF%8C&fromid=573&fr=aladdin',
},
],
},
{
label: '食物',
key: 'food',
children: [
{
label: '三明治',
key: 'sandwich',
},
],
},
{
label: '过去增多,未来减少',
key: 'the-past-increases-the-future-recedes',
},
],
},
]
</script>
<template>
<MenusLayout>
<n-menu :options="menuOptions" />
</MenusLayout>
</template>

View File

@ -0,0 +1,22 @@
import { RouteRecordRaw } from 'vue-router'
import { ROUTE_NAME } from '@cskefu/models'
import Layout from '../layouts/MenusLayout.vue'
const routes: RouteRecordRaw[] = [
{
path: '/seats',
name: 'seats',
component: Layout,
redirect: '/seats/index',
children: [
{
path: 'index',
name: ROUTE_NAME.SEATS_INDEX,
component: () => import('../views/HomeView.vue'),
},
],
},
]
export default routes

View File

@ -0,0 +1,7 @@
import { ComponentCustomProperties } from './shims-vue-global.d';
declare module "vue" {
export interface ComponentCustomProperties {
$t: (key: string) => string;
}
}

View File

@ -0,0 +1,3 @@
<template>
<div>seats home</div>
</template>

View File

@ -0,0 +1,9 @@
{
"extends": "../../../../tsconfig.json",
"include": ["src/**/*.ts", "src/**/*.d.ts", "src/**/*.tsx", "src/**/*.vue", "src/index.ts"],
"compilerOptions": {
"baseUrl": "./",
"types": ["vite/client", "naive-ui/volar"],
},
"references": [{ "path": "./tsconfig.node.json" }]
}

View File

@ -0,0 +1,10 @@
{
"compilerOptions": {
"composite": true,
"skipLibCheck": true,
"module": "ESNext",
"moduleResolution": "bundler",
"allowSyntheticDefaultImports": true
},
"include": ["vite.config.ts"]
}

Some files were not shown because too many files have changed in this diff Show More