├── six-arco ├── .eslintignore ├── .env.production ├── .env.development ├── babel.config.js ├── .prettierignore ├── commitlint.config.js ├── src │ ├── utils │ │ ├── env.ts │ │ ├── setup-mock.ts │ │ ├── auth.ts │ │ ├── event.ts │ │ ├── monitor.ts │ │ ├── route-listener.ts │ │ ├── index.ts │ │ └── is.ts │ ├── types │ │ ├── mock.ts │ │ ├── echarts.ts │ │ └── global.ts │ ├── assets │ │ ├── images │ │ │ └── login-banner.png │ │ ├── style │ │ │ ├── breakpoint.less │ │ │ ├── six.less │ │ │ └── global.less │ │ └── logo.svg │ ├── views │ │ ├── dashboard │ │ │ └── workplace │ │ │ │ ├── components │ │ │ │ ├── content-chart.vue │ │ │ │ ├── banner.vue │ │ │ │ ├── carousel.vue │ │ │ │ ├── docs.vue │ │ │ │ ├── recently-visited.vue │ │ │ │ ├── quick-operation.vue │ │ │ │ └── announcement.vue │ │ │ │ └── locale │ │ │ │ ├── zh-CN.ts │ │ │ │ └── en-US.ts │ │ ├── redirect │ │ │ └── index.vue │ │ ├── login │ │ │ ├── locale │ │ │ │ ├── zh-CN.ts │ │ │ │ └── en-US.ts │ │ │ ├── index.vue │ │ │ └── components │ │ │ │ └── banner.vue │ │ ├── not-found │ │ │ └── index.vue │ │ ├── system │ │ │ ├── Organization │ │ │ │ └── components │ │ │ │ │ └── form-save.vue │ │ │ ├── Job │ │ │ │ └── components │ │ │ │ │ └── form-save.vue │ │ │ ├── Tenant │ │ │ │ └── component │ │ │ │ │ └── form-save.vue │ │ │ └── AuthRole │ │ │ │ └── components │ │ │ │ └── form-save.vue │ │ └── basic │ │ │ └── Cron │ │ │ └── components │ │ │ └── form-save.vue │ ├── directive │ │ ├── index.ts │ │ └── permission │ │ │ └── index.ts │ ├── mock │ │ ├── index.ts │ │ └── message-box.ts │ ├── router │ │ ├── routes │ │ │ ├── externalModules │ │ │ │ ├── arco.ts │ │ │ │ └── faq.ts │ │ │ ├── types.ts │ │ │ ├── modules │ │ │ │ ├── tests.ts │ │ │ │ ├── dashboard.ts │ │ │ │ ├── basic.ts │ │ │ │ └── system.ts │ │ │ ├── index.ts │ │ │ └── base.ts │ │ ├── app-menus │ │ │ └── index.ts │ │ ├── constants.ts │ │ ├── guard │ │ │ ├── index.ts │ │ │ ├── userLoginInfo.ts │ │ │ └── permission.ts │ │ ├── typings.d.ts │ │ └── index.ts │ ├── store │ │ ├── modules │ │ │ ├── tab-bar │ │ │ │ ├── types.ts │ │ │ │ └── index.ts │ │ │ ├── user │ │ │ │ └── types.ts │ │ │ └── app │ │ │ │ └── types.ts │ │ └── index.ts │ ├── hooks │ │ ├── themes.ts │ │ ├── loading.ts │ │ ├── visible.ts │ │ ├── locale.ts │ │ ├── user.ts │ │ ├── request.ts │ │ ├── chart-option.ts │ │ ├── responsive.ts │ │ └── permission.ts │ ├── components │ │ ├── tab-bar │ │ │ └── readme.md │ │ ├── footer │ │ │ └── index.vue │ │ ├── message-box │ │ │ └── locale │ │ │ │ ├── zh-CN.ts │ │ │ │ └── en-US.ts │ │ ├── breadcrumb │ │ │ └── index.vue │ │ ├── index.ts │ │ ├── global-setting │ │ │ ├── form-wrapper.vue │ │ │ └── block.vue │ │ ├── chart │ │ │ └── index.vue │ │ ├── editor │ │ │ └── wang.vue │ │ └── menu │ │ │ └── use-menu-tree.ts │ ├── env.d.ts │ ├── config │ │ └── settings.json │ ├── api │ │ ├── user-single.ts │ │ ├── dashboard.ts │ │ ├── basic │ │ │ ├── cron.ts │ │ │ ├── files.ts │ │ │ ├── dict.ts │ │ │ └── code.ts │ │ ├── system │ │ │ ├── auth-relation.ts │ │ │ ├── tenant.ts │ │ │ ├── job.ts │ │ │ ├── organization.ts │ │ │ ├── auth-role.ts │ │ │ ├── logs.ts │ │ │ ├── auth-rule.ts │ │ │ └── user.ts │ │ ├── base.ts │ │ ├── message.ts │ │ ├── user.ts │ │ └── codegen │ │ │ └── tests.ts │ ├── locale │ │ ├── index.ts │ │ ├── zh-CN.ts │ │ ├── en-US.ts │ │ ├── zh-CN │ │ │ └── settings.ts │ │ └── en-US │ │ │ └── settings.ts │ ├── layout │ │ └── page-layout.vue │ ├── App.vue │ └── main.ts ├── .gitignore ├── config │ ├── utils │ │ └── index.ts │ ├── plugin │ │ ├── arcoStyleImport.ts │ │ ├── visualizer.ts │ │ ├── arcoResolver.ts │ │ ├── imagemin.ts │ │ └── compress.ts │ ├── vite.config.dev.ts │ ├── vite.config.prod.ts │ └── vite.config.base.ts ├── .prettierrc.js ├── components.d.ts ├── index.html ├── tsconfig.json ├── .stylelintrc.js └── .eslintrc.js ├── six-go ├── build_linux.bat ├── utils │ ├── token.go │ ├── trans_pointer.go │ ├── md5.go │ ├── base64.go │ ├── filepath.go │ ├── type_password.go │ ├── request │ │ ├── url_values.go │ │ └── request.go │ ├── operator_ternary.go │ ├── tree.go │ ├── response │ │ └── response.go │ └── rand.go ├── extra │ ├── crons │ │ ├── jobs.go │ │ ├── example.go │ │ ├── api.go │ │ ├── enter.go │ │ └── cron.go │ ├── xcache │ │ └── xcache.go │ ├── xredis │ │ ├── config.go │ │ └── redis.go │ └── uploader │ │ ├── local.go │ │ └── uploader.go ├── database │ ├── db │ │ ├── iof.go │ │ ├── model.go │ │ └── db.go │ ├── v_errors │ │ └── errors.go │ ├── dao │ │ ├── soft_delete.go │ │ ├── paginate.go │ │ ├── keyword_like.go │ │ ├── time_range.go │ │ ├── order_by.go │ │ └── migrate.go │ └── models │ │ ├── auth_user_login_storage.go │ │ ├── fn_tenant_identify.go │ │ ├── fn_get_sons.go │ │ ├── auth_relation.go │ │ ├── files.go │ │ ├── cronjobs.go │ │ ├── code_generator.go │ │ ├── job.go │ │ ├── tenant.go │ │ ├── organization.go │ │ └── operate_logs.go ├── app │ └── admin │ │ ├── route │ │ ├── route_operate_logs.go │ │ ├── route_files.go │ │ ├── route_codegen.go │ │ ├── route_cron.go │ │ ├── route_dict.go │ │ ├── tests.go │ │ ├── route_tenant.go │ │ ├── route_job.go │ │ ├── route_organization.go │ │ ├── route_auth_user_single.go │ │ ├── enter.go │ │ └── route_auth.go │ │ ├── middleware │ │ ├── auth.go │ │ ├── is_login.go │ │ └── tenant_di.go │ │ ├── entity │ │ ├── auth_user_join.go │ │ └── auth_log_join_user.go │ │ ├── service │ │ ├── authrule │ │ │ └── menu.go │ │ └── login │ │ │ ├── enter.go │ │ │ └── mysql.go │ │ └── controller │ │ └── operate_logs.go ├── static │ └── generator_tpl │ │ ├── server │ │ ├── create_table.sql.tpl │ │ ├── route.go.tpl │ │ └── model.go.tpl │ │ └── front │ │ ├── api.ts.tpl │ │ └── form.vue.tpl ├── config │ ├── app.go │ ├── config.go │ └── database.go ├── config.yaml └── cmd │ └── gin │ └── main.go ├── .gitignore ├── LICENSE └── README.md /six-arco/.eslintignore: -------------------------------------------------------------------------------- 1 | /*.json 2 | /*.js 3 | dist -------------------------------------------------------------------------------- /six-arco/.env.production: -------------------------------------------------------------------------------- 1 | VITE_API_BASE_URL= '/' 2 | VITE_STYLE_SIZE='mini' -------------------------------------------------------------------------------- /six-arco/.env.development: -------------------------------------------------------------------------------- 1 | VITE_API_BASE_URL= 'http://localhost:3000/' 2 | VITE_STYLE_SIZE='mini' -------------------------------------------------------------------------------- /six-arco/babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | plugins: ['@vue/babel-plugin-jsx'], 3 | }; 4 | -------------------------------------------------------------------------------- /six-arco/.prettierignore: -------------------------------------------------------------------------------- 1 | /dist/* 2 | .local 3 | .output.js 4 | /node_modules/** 5 | 6 | **/*.svg 7 | **/*.sh -------------------------------------------------------------------------------- /six-arco/commitlint.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | extends: ['@commitlint/config-conventional'], 3 | }; 4 | -------------------------------------------------------------------------------- /six-arco/src/utils/env.ts: -------------------------------------------------------------------------------- 1 | const debug = import.meta.env.MODE !== 'production'; 2 | 3 | export default debug; 4 | -------------------------------------------------------------------------------- /six-arco/src/types/mock.ts: -------------------------------------------------------------------------------- 1 | export interface MockParams { 2 | url: string; 3 | type: string; 4 | body: string; 5 | } 6 | -------------------------------------------------------------------------------- /six-go/build_linux.bat: -------------------------------------------------------------------------------- 1 | set GOOS=linux 2 | set GOARCH=amd64 3 | cd .\cmd\gin 4 | go build -tags=jsoniter -o SixAdminServer 5 | 6 | -------------------------------------------------------------------------------- /six-arco/src/assets/images/login-banner.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vainback/six-admin/HEAD/six-arco/src/assets/images/login-banner.png -------------------------------------------------------------------------------- /six-go/utils/token.go: -------------------------------------------------------------------------------- 1 | package utils 2 | 3 | func EncodeToken(uniqueValue string) string { 4 | return Base64Encode(Md5(uniqueValue)) 5 | } 6 | -------------------------------------------------------------------------------- /six-arco/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | .DS_Store 3 | dist 4 | dist-ssr 5 | *.local 6 | node_modules 7 | .DS_Store 8 | dist 9 | dist-ssr 10 | *.local 11 | -------------------------------------------------------------------------------- /six-arco/src/views/dashboard/workplace/components/content-chart.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /six-arco/src/directive/index.ts: -------------------------------------------------------------------------------- 1 | import { App } from 'vue'; 2 | import permission from './permission'; 3 | 4 | export default { 5 | install(Vue: App) { 6 | Vue.directive('permission', permission); 7 | }, 8 | }; 9 | -------------------------------------------------------------------------------- /six-go/extra/crons/jobs.go: -------------------------------------------------------------------------------- 1 | package crons 2 | 3 | import "github.com/robfig/cron/v3" 4 | 5 | // Jobs Key is unique name Value is FuncJob func. 6 | var Jobs = map[string]cron.FuncJob{ 7 | "example": ExampleJob, 8 | } 9 | -------------------------------------------------------------------------------- /six-go/utils/trans_pointer.go: -------------------------------------------------------------------------------- 1 | package utils 2 | 3 | func Pointer[T any](v T) *T { 4 | return &v 5 | } 6 | 7 | func PointerTrueOrNil[T bool](v T) *T { 8 | if v { 9 | return &v 10 | } 11 | return nil 12 | } 13 | -------------------------------------------------------------------------------- /six-arco/src/mock/index.ts: -------------------------------------------------------------------------------- 1 | import Mock from 'mockjs'; 2 | 3 | import './user'; 4 | import './message-box'; 5 | 6 | import '@/views/dashboard/workplace/mock'; 7 | 8 | Mock.setup({ 9 | timeout: '600-1000', 10 | }); 11 | -------------------------------------------------------------------------------- /six-arco/config/utils/index.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Whether to generate package preview 3 | * 是否生成打包报告 4 | */ 5 | export default {}; 6 | 7 | export function isReportMode(): boolean { 8 | return process.env.REPORT === 'true'; 9 | } 10 | -------------------------------------------------------------------------------- /six-arco/.prettierrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | tabWidth: 4, 3 | semi: true, 4 | printWidth: 80, 5 | singleQuote: true, 6 | quoteProps: 'consistent', 7 | htmlWhitespaceSensitivity: 'strict', 8 | vueIndentScriptAndStyle: true, 9 | }; 10 | -------------------------------------------------------------------------------- /six-arco/src/router/routes/externalModules/arco.ts: -------------------------------------------------------------------------------- 1 | export default { 2 | path: 'https://arco.design', 3 | name: 'arcoWebsite', 4 | meta: { 5 | locale: 'menu.arcoWebsite', 6 | icon: 'icon-link', 7 | requiresAuth: true, 8 | order: 8, 9 | }, 10 | }; 11 | -------------------------------------------------------------------------------- /six-arco/src/router/routes/externalModules/faq.ts: -------------------------------------------------------------------------------- 1 | export default { 2 | path: 'https://arco.design/vue/docs/pro/faq', 3 | name: 'faq', 4 | meta: { 5 | locale: 'menu.faq', 6 | icon: 'icon-question-circle', 7 | requiresAuth: true, 8 | order: 9, 9 | }, 10 | }; 11 | -------------------------------------------------------------------------------- /six-go/utils/md5.go: -------------------------------------------------------------------------------- 1 | package utils 2 | 3 | import ( 4 | "crypto/md5" 5 | "fmt" 6 | ) 7 | 8 | func Md5(value string) string { 9 | return fmt.Sprintf("%x", md5.Sum([]byte(value))) 10 | } 11 | 12 | func Md5Byte(value []byte) []byte { 13 | sum := md5.Sum(value) 14 | return sum[:] 15 | } 16 | -------------------------------------------------------------------------------- /six-arco/src/store/modules/tab-bar/types.ts: -------------------------------------------------------------------------------- 1 | export interface TagProps { 2 | title: string; 3 | name: string; 4 | fullPath: string; 5 | query?: any; 6 | ignoreCache?: boolean; 7 | } 8 | 9 | export interface TabBarState { 10 | tagList: TagProps[]; 11 | cacheTabList: Set; 12 | } 13 | -------------------------------------------------------------------------------- /six-go/database/db/iof.go: -------------------------------------------------------------------------------- 1 | package db 2 | 3 | import "gorm.io/gorm" 4 | 5 | type ModelIof interface { 6 | TableName() string // 表名 7 | KeywordFields() []string // 模糊查询字段 8 | FilterSqlBuilder() func(db *gorm.DB) *gorm.DB // 过滤查询 9 | GetId() int64 10 | } 11 | -------------------------------------------------------------------------------- /six-go/database/v_errors/errors.go: -------------------------------------------------------------------------------- 1 | package v_errors 2 | 3 | import ( 4 | "errors" 5 | "fmt" 6 | ) 7 | 8 | var ( 9 | CountsZero = errors.New("ErrorCountsZero") 10 | Unique = func(filedName string) error { 11 | return fmt.Errorf("%s已存在", filedName) 12 | } 13 | DictUnique = errors.New("该值已在同一个字典类型中存在") 14 | ) 15 | -------------------------------------------------------------------------------- /six-arco/src/hooks/themes.ts: -------------------------------------------------------------------------------- 1 | import { computed } from 'vue'; 2 | import { useAppStore } from '@/store'; 3 | 4 | export default function useThemes() { 5 | const appStore = useAppStore(); 6 | const isDark = computed(() => { 7 | return appStore.theme === 'dark'; 8 | }); 9 | return { 10 | isDark, 11 | }; 12 | } 13 | -------------------------------------------------------------------------------- /six-arco/src/types/echarts.ts: -------------------------------------------------------------------------------- 1 | import { CallbackDataParams } from 'echarts/types/dist/shared'; 2 | 3 | export interface ToolTipFormatterParams extends CallbackDataParams { 4 | axisDim: string; 5 | axisIndex: number; 6 | axisType: string; 7 | axisId: string; 8 | axisValue: string; 9 | axisValueLabel: string; 10 | } 11 | -------------------------------------------------------------------------------- /six-arco/src/store/index.ts: -------------------------------------------------------------------------------- 1 | import { createPinia } from 'pinia'; 2 | import useAppStore from './modules/app'; 3 | import useUserStore from './modules/user'; 4 | import useTabBarStore from './modules/tab-bar'; 5 | 6 | const pinia = createPinia(); 7 | 8 | export { useAppStore, useUserStore, useTabBarStore }; 9 | export default pinia; 10 | -------------------------------------------------------------------------------- /six-arco/src/components/tab-bar/readme.md: -------------------------------------------------------------------------------- 1 | ## 组件说明 2 | 3 | 该组件非官方最终设计规范,以单独组件存在。 4 | 5 | 同时仅仅提供最基本的功能,后续进行优化及更改。 6 | 7 | 8 | ## Component description 9 | 10 | The component unofficial final design specification exists as a separate component. 11 | 12 | At the same time, only the most basic functions are provided, and subsequent optimizations and changes will be made. -------------------------------------------------------------------------------- /six-go/database/dao/soft_delete.go: -------------------------------------------------------------------------------- 1 | package dao 2 | 3 | import "gorm.io/gorm" 4 | 5 | type QuerySoftDelete struct { 6 | IsDelete bool `json:"is_delete"` 7 | } 8 | 9 | func (ts QuerySoftDelete) SqlBuilder() func(db *gorm.DB) *gorm.DB { 10 | return func(db *gorm.DB) *gorm.DB { 11 | if !ts.IsDelete { 12 | return db 13 | } 14 | return db.Unscoped() 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /six-go/utils/base64.go: -------------------------------------------------------------------------------- 1 | package utils 2 | 3 | import "encoding/base64" 4 | 5 | func Base64Encode(value string) string { 6 | return base64.StdEncoding.EncodeToString([]byte(value)) 7 | } 8 | 9 | func Base64Decode(b64 string) string { 10 | decodeString, err := base64.StdEncoding.DecodeString(b64) 11 | if err != nil { 12 | return "" 13 | } 14 | return string(decodeString) 15 | } 16 | -------------------------------------------------------------------------------- /six-arco/src/env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | 3 | declare module '*.vue' { 4 | import { DefineComponent } from 'vue'; 5 | // eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/ban-types 6 | const component: DefineComponent<{}, {}, any>; 7 | export default component; 8 | } 9 | interface ImportMetaEnv { 10 | readonly VITE_API_BASE_URL: string; 11 | } 12 | -------------------------------------------------------------------------------- /six-go/app/admin/route/route_operate_logs.go: -------------------------------------------------------------------------------- 1 | package adminRoute 2 | 3 | import ( 4 | "github.com/gin-gonic/gin" 5 | "six-go/app/admin/controller" 6 | ) 7 | 8 | func (r Route) OperateLogs(app *gin.RouterGroup) { 9 | p := app.Group("/logs") 10 | p.POST("/list", controller.OperateLogs.List) 11 | p.POST("/select", controller.OperateLogs.Select) 12 | p.POST("/get", controller.OperateLogs.Get) 13 | } 14 | -------------------------------------------------------------------------------- /six-arco/src/hooks/loading.ts: -------------------------------------------------------------------------------- 1 | import { ref } from 'vue'; 2 | 3 | export default function useLoading(initValue = false) { 4 | const loading = ref(initValue); 5 | const setLoading = (value: boolean) => { 6 | loading.value = value; 7 | }; 8 | const toggle = () => { 9 | loading.value = !loading.value; 10 | }; 11 | return { 12 | loading, 13 | setLoading, 14 | toggle, 15 | }; 16 | } 17 | -------------------------------------------------------------------------------- /six-arco/src/hooks/visible.ts: -------------------------------------------------------------------------------- 1 | import { ref } from 'vue'; 2 | 3 | export default function useVisible(initValue = false) { 4 | const visible = ref(initValue); 5 | const setVisible = (value: boolean) => { 6 | visible.value = value; 7 | }; 8 | const toggle = () => { 9 | visible.value = !visible.value; 10 | }; 11 | return { 12 | visible, 13 | setVisible, 14 | toggle, 15 | }; 16 | } 17 | -------------------------------------------------------------------------------- /six-arco/src/views/redirect/index.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /six-go/extra/xcache/xcache.go: -------------------------------------------------------------------------------- 1 | package xcache 2 | 3 | import "sync" 4 | 5 | var syncCache sync.Map 6 | 7 | func SyncLoad[T any](key string) (v T) { 8 | value, ok := syncCache.Load(key) 9 | if !ok { 10 | return 11 | } 12 | return value.(T) 13 | } 14 | 15 | func SyncStore(key string, value any) { 16 | syncCache.Store(key, value) 17 | } 18 | 19 | func SyncDelete(key string) { 20 | syncCache.Delete(key) 21 | } 22 | -------------------------------------------------------------------------------- /six-arco/src/config/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "theme": "light", 3 | "colorWeak": false, 4 | "navbar": true, 5 | "menu": true, 6 | "topMenu": false, 7 | "hideMenu": false, 8 | "menuCollapse": false, 9 | "footer": false, 10 | "themeColor": "#165DFF", 11 | "menuWidth": 180, 12 | "globalSettings": false, 13 | "device": "desktop", 14 | "tabBar": true, 15 | "menuFromServer": true 16 | } -------------------------------------------------------------------------------- /six-arco/src/router/app-menus/index.ts: -------------------------------------------------------------------------------- 1 | import { appRoutes, appExternalRoutes } from '../routes'; 2 | 3 | const mixinRoutes = [...appRoutes, ...appExternalRoutes]; 4 | 5 | const appClientMenus = mixinRoutes.map((el) => { 6 | const { name, path, meta, redirect, children } = el; 7 | return { 8 | name, 9 | path, 10 | meta, 11 | redirect, 12 | children, 13 | }; 14 | }); 15 | 16 | export default appClientMenus; 17 | -------------------------------------------------------------------------------- /six-go/extra/crons/example.go: -------------------------------------------------------------------------------- 1 | package crons 2 | 3 | import "fmt" 4 | 5 | func ExampleJob() { 6 | //fmt.Println("-------------------") 7 | //fmt.Println("this is example job") 8 | fmt.Println("this is example job") 9 | //fmt.Println("this is example job") 10 | //fmt.Println("this is example job") 11 | //fmt.Println("this is example job") 12 | //fmt.Println("this is example job") 13 | //fmt.Println("-------------------") 14 | } 15 | -------------------------------------------------------------------------------- /six-go/database/db/model.go: -------------------------------------------------------------------------------- 1 | package db 2 | 3 | import ( 4 | "time" 5 | 6 | "gorm.io/gorm" 7 | ) 8 | 9 | type MODEL struct { 10 | Id int64 `json:"id" gorm:"primaryKey"` 11 | CreateTime time.Time `json:"create_time" gorm:"autoCreateTime"` 12 | UpdateTime time.Time `json:"update_time" gorm:"autoUpdateTime"` 13 | } 14 | 15 | type SoftDelete struct { 16 | DeleteTime gorm.DeletedAt `json:"delete_time" gorm:"index"` 17 | } 18 | -------------------------------------------------------------------------------- /six-go/extra/crons/api.go: -------------------------------------------------------------------------------- 1 | package crons 2 | 3 | import "errors" 4 | 5 | var ( 6 | JobNotExists = errors.New("JobNotExists") 7 | ) 8 | 9 | // Start 当开启定时任务时调用 10 | func Start(id int64, name, spec string) error { 11 | if j, ok := Jobs[name]; ok { 12 | return NewCron().AddJob(id, spec, j) 13 | } 14 | return JobNotExists 15 | } 16 | 17 | // Stop 当删除或停止定时任务后 调用 18 | func Stop(id int64) error { 19 | return NewCron().RemoveJob(id) 20 | } 21 | -------------------------------------------------------------------------------- /six-arco/config/plugin/arcoStyleImport.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Theme import 3 | * 样式按需引入 4 | * https://github.com/arco-design/arco-plugins/blob/main/packages/plugin-vite-vue/README.md 5 | * https://arco.design/vue/docs/start 6 | */ 7 | import { vitePluginForArco } from '@arco-plugins/vite-vue'; 8 | 9 | export default function configArcoStyleImportPlugin() { 10 | const arcoResolverPlugin = vitePluginForArco({}); 11 | return arcoResolverPlugin; 12 | } 13 | -------------------------------------------------------------------------------- /six-arco/src/components/footer/index.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | 7 | 17 | -------------------------------------------------------------------------------- /six-arco/components.d.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable */ 2 | /* prettier-ignore */ 3 | // @ts-nocheck 4 | // Generated by unplugin-vue-components 5 | // Read more: https://github.com/vuejs/core/pull/3399 6 | import '@vue/runtime-core' 7 | 8 | export {} 9 | 10 | declare module '@vue/runtime-core' { 11 | export interface GlobalComponents { 12 | RouterLink: typeof import('vue-router')['RouterLink'] 13 | RouterView: typeof import('vue-router')['RouterView'] 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /six-arco/src/assets/style/breakpoint.less: -------------------------------------------------------------------------------- 1 | // ==============breakpoint============ 2 | 3 | // Extra small screen / phone 4 | @screen-xs: 480px; 5 | 6 | // Small screen / tablet 7 | @screen-sm: 576px; 8 | 9 | // Medium screen / desktop 10 | @screen-md: 768px; 11 | 12 | // Large screen / wide desktop 13 | @screen-lg: 992px; 14 | 15 | // Extra large screen / full hd 16 | @screen-xl: 1200px; 17 | 18 | // Extra extra large screen / large desktop 19 | @screen-xxl: 1600px; 20 | -------------------------------------------------------------------------------- /six-go/database/dao/paginate.go: -------------------------------------------------------------------------------- 1 | package dao 2 | 3 | import "gorm.io/gorm" 4 | 5 | type QueryPage struct { 6 | Page int `json:"page"` 7 | Limit int `json:"limit"` 8 | } 9 | 10 | func (ts QueryPage) SqlBuilder() func(db *gorm.DB) *gorm.DB { 11 | if ts.Page <= 0 { 12 | ts.Page = 1 13 | } 14 | 15 | if ts.Limit <= 0 { 16 | ts.Limit = 20 17 | } 18 | return func(db *gorm.DB) *gorm.DB { 19 | return db.Offset((ts.Page - 1) * ts.Limit).Limit(ts.Limit) 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /six-go/static/generator_tpl/server/create_table.sql.tpl: -------------------------------------------------------------------------------- 1 | CREATE TABLE `{{tpl - $table}}` ( 2 | `id` bigint(20) NOT NULL AUTO_INCREMENT, 3 | `create_time` datetime(3) NULL DEFAULT NULL, 4 | `update_time` datetime(3) NULL DEFAULT NULL, 5 | 6 | 7 | 8 | PRIMARY KEY (`id`) USING BTREE, 9 | 10 | ) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = Dynamic; -------------------------------------------------------------------------------- /six-arco/src/router/constants.ts: -------------------------------------------------------------------------------- 1 | export const WHITE_LIST = [ 2 | { name: 'notFound', children: [] }, 3 | { name: 'login', children: [] }, 4 | ]; 5 | 6 | export const NOT_FOUND = { 7 | name: 'notFound', 8 | }; 9 | 10 | export const REDIRECT_ROUTE_NAME = 'Redirect'; 11 | 12 | export const DEFAULT_ROUTE_NAME = 'Workplace'; 13 | 14 | export const DEFAULT_ROUTE = { 15 | title: 'menu.dashboard.workplace', 16 | name: DEFAULT_ROUTE_NAME, 17 | fullPath: '/dashboard/workplace', 18 | }; 19 | -------------------------------------------------------------------------------- /six-arco/config/plugin/visualizer.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Generation packaging analysis 3 | * 生成打包分析 4 | */ 5 | import visualizer from 'rollup-plugin-visualizer'; 6 | import { isReportMode } from '../utils'; 7 | 8 | export default function configVisualizerPlugin() { 9 | if (isReportMode()) { 10 | return visualizer({ 11 | filename: './node_modules/.cache/visualizer/stats.html', 12 | open: true, 13 | gzipSize: true, 14 | brotliSize: true, 15 | }); 16 | } 17 | return []; 18 | } 19 | -------------------------------------------------------------------------------- /six-arco/src/components/message-box/locale/zh-CN.ts: -------------------------------------------------------------------------------- 1 | export default { 2 | 'messageBox.tab.title.message': '消息', 3 | 'messageBox.tab.title.notice': '通知', 4 | 'messageBox.tab.title.todo': '待办', 5 | 'messageBox.tab.button': '清空', 6 | 'messageBox.allRead': '全部已读', 7 | 'messageBox.viewMore': '查看更多', 8 | 'messageBox.noContent': '暂无内容', 9 | 'messageBox.switchRoles': '切换角色', 10 | 'messageBox.userCenter': '用户中心', 11 | 'messageBox.userSettings': '用户设置', 12 | 'messageBox.logout': '退出登录', 13 | }; 14 | -------------------------------------------------------------------------------- /six-go/app/admin/route/route_files.go: -------------------------------------------------------------------------------- 1 | package adminRoute 2 | 3 | import ( 4 | "github.com/gin-gonic/gin" 5 | "six-go/app/admin/controller" 6 | ) 7 | 8 | func (r Route) Files(app *gin.RouterGroup) { 9 | p := app.Group("/files") 10 | p.POST("/list", controller.Files.List) 11 | p.POST("/select", controller.Files.Select) 12 | p.POST("/get", controller.Files.Get) 13 | p.POST("/edit", controller.Files.Update) 14 | p.POST("/save", controller.Files.Save) 15 | p.POST("/del", controller.Files.Delete) 16 | } 17 | -------------------------------------------------------------------------------- /six-go/app/admin/route/route_codegen.go: -------------------------------------------------------------------------------- 1 | package adminRoute 2 | 3 | import ( 4 | "github.com/gin-gonic/gin" 5 | "six-go/app/admin/controller" 6 | ) 7 | 8 | func (r Route) Codegen(app *gin.RouterGroup) { 9 | p := app.Group("/codegen") 10 | p.POST("/list", controller.CodeGenerator.List) 11 | p.POST("/add", controller.CodeGenerator.Add) 12 | p.POST("/save", controller.CodeGenerator.Save) 13 | p.POST("/del", controller.CodeGenerator.Delete) 14 | p.POST("/generator", controller.CodeGenerator.Generator) 15 | } 16 | -------------------------------------------------------------------------------- /six-arco/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Arco Design Pro - 开箱即用的中台前端/设计解决方案 8 | 9 | 10 |
11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /six-arco/src/assets/style/six.less: -------------------------------------------------------------------------------- 1 | .six-container { 2 | width: 100%; 3 | background-color: var(--color-fill-2); 4 | padding: 8px 10px 0 10px; 5 | display: flex; 6 | } 7 | 8 | .six-flex { 9 | display: flex; 10 | } 11 | 12 | .six-flex-between { 13 | width: 100%; 14 | display: flex; 15 | justify-content: space-between; 16 | align-items: center; 17 | } 18 | 19 | .six-flex-center { 20 | width: 100%; 21 | display: flex; 22 | justify-content: center; 23 | align-items: center; 24 | } -------------------------------------------------------------------------------- /six-go/database/models/auth_user_login_storage.go: -------------------------------------------------------------------------------- 1 | package models 2 | 3 | import ( 4 | "six-go/database/db" 5 | ) 6 | 7 | var TableAuthUserLoginStorage AuthUserLoginStorage 8 | 9 | type AuthUserLoginStorage struct { 10 | db.MODEL 11 | Username string `json:"username" gorm:"comment:username"` 12 | Token string `json:"token" gorm:"comment:token"` 13 | Expire int64 `json:"expire" gorm:"column:expire"` 14 | } 15 | 16 | func (data AuthUserLoginStorage) TableName() string { 17 | return "auth_user_login_storage" 18 | } 19 | -------------------------------------------------------------------------------- /six-arco/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ES2020", 4 | "module": "ES2020", 5 | "moduleResolution": "node", 6 | "strict": true, 7 | "jsx": "preserve", 8 | "sourceMap": true, 9 | "resolveJsonModule": true, 10 | "esModuleInterop": true, 11 | "baseUrl": ".", 12 | "paths": { 13 | "@/*": ["src/*"] 14 | }, 15 | "lib": ["es2020", "dom"], 16 | "skipLibCheck": true 17 | }, 18 | "include": ["src/**/*", "src/**/*.vue"], 19 | "exclude": ["node_modules"] 20 | } 21 | -------------------------------------------------------------------------------- /six-go/utils/filepath.go: -------------------------------------------------------------------------------- 1 | package utils 2 | 3 | import "os" 4 | 5 | type FilePath struct { 6 | err error 7 | file os.FileInfo 8 | } 9 | 10 | func NewFilepath(path string) *FilePath { 11 | stat, err := os.Stat(path) 12 | return &FilePath{err: err, file: stat} 13 | } 14 | 15 | func (f *FilePath) Exists() bool { 16 | return f.err == nil 17 | } 18 | 19 | func (f *FilePath) IsDir() bool { 20 | return f.Exists() && f.file.IsDir() 21 | } 22 | 23 | func (f *FilePath) IsFile() bool { 24 | return f.Exists() && !f.file.IsDir() 25 | } 26 | -------------------------------------------------------------------------------- /six-go/app/admin/route/route_cron.go: -------------------------------------------------------------------------------- 1 | package adminRoute 2 | 3 | import ( 4 | "github.com/gin-gonic/gin" 5 | "six-go/app/admin/controller" 6 | ) 7 | 8 | func (r Route) Cron(app *gin.RouterGroup) { 9 | p := app.Group("/cron") 10 | p.POST("/list", controller.Cron.List) 11 | p.POST("/select", controller.Cron.Select) 12 | p.POST("/get", controller.Cron.Get) 13 | p.POST("/add", controller.Cron.Add) 14 | p.POST("/edit", controller.Cron.Update) 15 | p.POST("/save", controller.Cron.Save) 16 | p.POST("/del", controller.Cron.Delete) 17 | } 18 | -------------------------------------------------------------------------------- /six-go/app/admin/route/route_dict.go: -------------------------------------------------------------------------------- 1 | package adminRoute 2 | 3 | import ( 4 | "github.com/gin-gonic/gin" 5 | "six-go/app/admin/controller" 6 | ) 7 | 8 | func (r Route) Dict(app *gin.RouterGroup) { 9 | p := app.Group("/dict") 10 | p.POST("/list", controller.Dict.List) 11 | p.POST("/select", controller.Dict.Select) 12 | p.POST("/get", controller.Dict.Get) 13 | p.POST("/add", controller.Dict.Add) 14 | p.POST("/edit", controller.Dict.Update) 15 | p.POST("/save", controller.Dict.Save) 16 | p.POST("/del", controller.Dict.Delete) 17 | } 18 | -------------------------------------------------------------------------------- /six-go/app/admin/route/tests.go: -------------------------------------------------------------------------------- 1 | package adminRoute 2 | 3 | import ( 4 | "github.com/gin-gonic/gin" 5 | "six-go/app/admin/controller" 6 | ) 7 | 8 | func (r Route) Tests(app *gin.RouterGroup) { 9 | p := app.Group("tests") 10 | p.POST("/list", controller.Tests.List) 11 | p.POST("/select", controller.Tests.Select) 12 | p.POST("/get", controller.Tests.Get) 13 | p.POST("/add", controller.Tests.Add) 14 | p.POST("/edit", controller.Tests.Update) 15 | p.POST("/save", controller.Tests.Save) 16 | p.POST("/del", controller.Tests.Delete) 17 | } 18 | -------------------------------------------------------------------------------- /six-go/extra/crons/enter.go: -------------------------------------------------------------------------------- 1 | package crons 2 | 3 | import ( 4 | "log" 5 | "six-go/database/db" 6 | "six-go/database/models" 7 | ) 8 | 9 | func Init() { 10 | var list []models.CronJob 11 | if err := db.DB().Where("status = ?", true).Find(&list).Error; err != nil { 12 | log.Println(err) 13 | return 14 | } 15 | for _, v := range list { 16 | if cr, ok := Jobs[v.Name]; ok { 17 | if err := NewCron().AddJob(v.Id, v.Times, cr); err != nil { 18 | log.Println(err) 19 | } 20 | } 21 | } 22 | NewCron().Start() 23 | return 24 | } 25 | -------------------------------------------------------------------------------- /six-arco/src/api/user-single.ts: -------------------------------------------------------------------------------- 1 | import axios from "axios"; 2 | import {getToken} from "@/utils/auth"; 3 | import {ref} from "vue"; 4 | 5 | const domain = ref(import.meta.env.VITE_API_BASE_URL) 6 | 7 | const root = 'admin/user/single/' 8 | 9 | export const uploadUrl = `${domain.value}${root}upload` 10 | 11 | export const uploadHeaders = { 12 | "Authorization": `Bearer ${getToken() || ''}`, 13 | "Six-Token": getToken() || '', 14 | } 15 | 16 | export function reqResetPassword(data: any) { 17 | return axios.post(`${root}reset/password`, data); 18 | } -------------------------------------------------------------------------------- /six-arco/src/store/modules/user/types.ts: -------------------------------------------------------------------------------- 1 | export type RoleType = '' | '*' | 'admin' | 'user'; 2 | export interface UserState { 3 | name?: string; 4 | avatar?: string; 5 | job?: string; 6 | organization?: string; 7 | location?: string; 8 | email?: string; 9 | introduction?: string; 10 | personalWebsite?: string; 11 | jobName?: string; 12 | organizationName?: string; 13 | locationName?: string; 14 | phone?: string; 15 | registrationDate?: string; 16 | accountId?: string; 17 | certification?: number; 18 | role: RoleType; 19 | } 20 | -------------------------------------------------------------------------------- /six-arco/src/utils/setup-mock.ts: -------------------------------------------------------------------------------- 1 | import debug from './env'; 2 | 3 | export default ({ mock, setup }: { mock?: boolean; setup: () => void }) => { 4 | if (mock !== false && debug) setup(); 5 | }; 6 | 7 | export const successResponseWrap = (data: unknown) => { 8 | return { 9 | data, 10 | status: 'ok', 11 | msg: '请求成功', 12 | code: 0, 13 | }; 14 | }; 15 | 16 | export const failResponseWrap = (data: unknown, msg: string, code = 2) => { 17 | return { 18 | data, 19 | status: 'fail', 20 | msg, 21 | code, 22 | }; 23 | }; 24 | -------------------------------------------------------------------------------- /six-arco/src/components/message-box/locale/en-US.ts: -------------------------------------------------------------------------------- 1 | export default { 2 | 'messageBox.tab.title.message': 'Message', 3 | 'messageBox.tab.title.notice': 'Notice', 4 | 'messageBox.tab.title.todo': 'Todo', 5 | 'messageBox.tab.button': 'empty', 6 | 'messageBox.allRead': 'All Read', 7 | 'messageBox.viewMore': 'View More', 8 | 'messageBox.noContent': 'No Content', 9 | 'messageBox.switchRoles': 'Switch Roles', 10 | 'messageBox.userCenter': 'User Center', 11 | 'messageBox.userSettings': 'User Settings', 12 | 'messageBox.logout': 'Logout', 13 | }; 14 | -------------------------------------------------------------------------------- /six-go/app/admin/route/route_tenant.go: -------------------------------------------------------------------------------- 1 | package adminRoute 2 | 3 | import ( 4 | "github.com/gin-gonic/gin" 5 | "six-go/app/admin/controller" 6 | ) 7 | 8 | func (r Route) Tenant(app *gin.RouterGroup) { 9 | p := app.Group("/tenant") 10 | p.POST("/list", controller.Tenant.List) 11 | p.POST("/select", controller.Tenant.Select) 12 | p.POST("/get", controller.Tenant.Get) 13 | p.POST("/add", controller.Tenant.Add) 14 | p.POST("/edit", controller.Tenant.Update) 15 | p.POST("/save", controller.Tenant.Save) 16 | p.POST("/del", controller.Tenant.Delete) 17 | } 18 | -------------------------------------------------------------------------------- /six-arco/src/store/modules/app/types.ts: -------------------------------------------------------------------------------- 1 | import type { RouteRecordNormalized } from 'vue-router'; 2 | 3 | export interface AppState { 4 | theme: string; 5 | colorWeak: boolean; 6 | navbar: boolean; 7 | menu: boolean; 8 | topMenu: boolean; 9 | hideMenu: boolean; 10 | menuCollapse: boolean; 11 | footer: boolean; 12 | themeColor: string; 13 | menuWidth: number; 14 | globalSettings: boolean; 15 | device: string; 16 | tabBar: boolean; 17 | menuFromServer: boolean; 18 | serverMenu: RouteRecordNormalized[]; 19 | [key: string]: unknown; 20 | } 21 | -------------------------------------------------------------------------------- /six-arco/config/vite.config.dev.ts: -------------------------------------------------------------------------------- 1 | import { mergeConfig } from 'vite'; 2 | import eslint from 'vite-plugin-eslint'; 3 | import baseConfig from './vite.config.base'; 4 | 5 | export default mergeConfig( 6 | { 7 | mode: 'development', 8 | server: { 9 | open: true, 10 | fs: { 11 | strict: true, 12 | }, 13 | }, 14 | plugins: [ 15 | eslint({ 16 | cache: false, 17 | include: ['src/**/*.ts', 'src/**/*.tsx', 'src/**/*.vue'], 18 | exclude: ['node_modules'], 19 | }), 20 | ], 21 | }, 22 | baseConfig 23 | ); 24 | -------------------------------------------------------------------------------- /six-go/app/admin/route/route_job.go: -------------------------------------------------------------------------------- 1 | package adminRoute 2 | 3 | import ( 4 | "github.com/gin-gonic/gin" 5 | "six-go/app/admin/controller" 6 | ) 7 | 8 | func (r Route) Job(app *gin.RouterGroup) { 9 | p := app.Group("/job") 10 | p.POST("/list", controller.Job.List) 11 | p.POST("/select", controller.Job.Select) 12 | p.POST("/tree-select", controller.Job.TreeSelect) 13 | p.POST("/get", controller.Job.Get) 14 | p.POST("/add", controller.Job.Add) 15 | p.POST("/edit", controller.Job.Update) 16 | p.POST("/save", controller.Job.Save) 17 | p.POST("/del", controller.Job.Delete) 18 | } 19 | -------------------------------------------------------------------------------- /six-arco/src/locale/index.ts: -------------------------------------------------------------------------------- 1 | import { createI18n } from 'vue-i18n'; 2 | import en from './en-US'; 3 | import cn from './zh-CN'; 4 | 5 | export const LOCALE_OPTIONS = [ 6 | { label: '中文', value: 'zh-CN' }, 7 | { label: 'English', value: 'en-US' }, 8 | ]; 9 | const defaultLocale = localStorage.getItem('arco-locale') || 'zh-CN'; 10 | 11 | const i18n = createI18n({ 12 | locale: defaultLocale, 13 | fallbackLocale: 'en-US', 14 | legacy: false, 15 | allowComposition: true, 16 | messages: { 17 | 'en-US': en, 18 | 'zh-CN': cn, 19 | }, 20 | }); 21 | 22 | export default i18n; 23 | -------------------------------------------------------------------------------- /six-arco/src/router/guard/index.ts: -------------------------------------------------------------------------------- 1 | import type { Router } from 'vue-router'; 2 | import { setRouteEmitter } from '@/utils/route-listener'; 3 | import setupUserLoginInfoGuard from './userLoginInfo'; 4 | import setupPermissionGuard from './permission'; 5 | 6 | function setupPageGuard(router: Router) { 7 | router.beforeEach(async (to) => { 8 | // emit route change 9 | setRouteEmitter(to); 10 | }); 11 | } 12 | 13 | export default function createRouteGuard(router: Router) { 14 | setupPageGuard(router); 15 | setupUserLoginInfoGuard(router); 16 | setupPermissionGuard(router); 17 | } 18 | -------------------------------------------------------------------------------- /six-go/static/generator_tpl/front/api.ts.tpl: -------------------------------------------------------------------------------- 1 | import {RequestParam} from "@/api/base"; 2 | import axios from "axios"; 3 | 4 | export interface { 5 | id: number; 6 | create_time?: string; 7 | update_time?: string; 8 | delete_time?: string; 9 | 10 | } 11 | 12 | export const Empty: = { 13 | id: 0, 14 | 15 | } 16 | 17 | const root = 'admin/' 18 | export function req(action: string, data: RequestParam<> | null) { 19 | return axios.post(`${root}/${action}`, data ||{}); 20 | } -------------------------------------------------------------------------------- /six-arco/src/api/dashboard.ts: -------------------------------------------------------------------------------- 1 | import axios from 'axios'; 2 | import type { TableData } from '@arco-design/web-vue/es/table/interface'; 3 | 4 | export interface ContentDataRecord { 5 | x: string; 6 | y: number; 7 | } 8 | 9 | export function queryContentData() { 10 | return axios.get('/api/content-data'); 11 | } 12 | 13 | export interface PopularRecord { 14 | key: number; 15 | clickNumber: string; 16 | title: string; 17 | increases: number; 18 | } 19 | 20 | export function queryPopularList(params: { type: string }) { 21 | return axios.get('/api/popular/list', { params }); 22 | } 23 | -------------------------------------------------------------------------------- /six-go/app/admin/route/route_organization.go: -------------------------------------------------------------------------------- 1 | package adminRoute 2 | 3 | import ( 4 | "github.com/gin-gonic/gin" 5 | "six-go/app/admin/controller" 6 | ) 7 | 8 | func (r Route) Organization(app *gin.RouterGroup) { 9 | p := app.Group("/organization") 10 | p.POST("/list", controller.Organization.List) 11 | p.POST("/tree-select", controller.Organization.TreeSelect) 12 | p.POST("/get", controller.Organization.Get) 13 | p.POST("/add", controller.Organization.Add) 14 | p.POST("/edit", controller.Organization.Update) 15 | p.POST("/save", controller.Organization.Save) 16 | p.POST("/del", controller.Organization.Delete) 17 | } 18 | -------------------------------------------------------------------------------- /six-go/app/admin/middleware/auth.go: -------------------------------------------------------------------------------- 1 | package middleware 2 | 3 | import ( 4 | authService "six-go/app/admin/service/auth" 5 | "strings" 6 | 7 | "github.com/gin-gonic/gin" 8 | "six-go/utils/response" 9 | ) 10 | 11 | func Authorization(c *gin.Context) { 12 | user := SessionUser(c) 13 | if !user.IsRoot { 14 | if len(user.RoleIds) == 0 { 15 | c.Abort() 16 | response.JsonNoAuth(c) 17 | return 18 | } 19 | 20 | route := strings.ReplaceAll(c.Request.URL.Path, "/admin/", "/") 21 | if has := authService.HasAuth(route, user.RoleIds...); !has { 22 | c.Abort() 23 | response.JsonNoAuth(c) 24 | return 25 | } 26 | } 27 | c.Next() 28 | } 29 | -------------------------------------------------------------------------------- /six-arco/src/api/basic/cron.ts: -------------------------------------------------------------------------------- 1 | import {RequestParam} from "@/api/base"; 2 | import axios from "axios"; 3 | 4 | export interface Cron { 5 | id: number; 6 | create_time?: string; 7 | update_time?: string; 8 | delete_time?: string; 9 | name: string; 10 | title: string; 11 | times: string; 12 | status: number; 13 | } 14 | 15 | export const EmptyCron: Cron = { 16 | id: 0, 17 | name: '', 18 | title: '', 19 | times: '', 20 | status: 0 21 | } 22 | 23 | const root = 'admin/cron' 24 | export function reqCron(action: string, data: RequestParam | null) { 25 | return axios.post(`${root}/${action}`, data ||{}); 26 | } -------------------------------------------------------------------------------- /six-arco/src/hooks/locale.ts: -------------------------------------------------------------------------------- 1 | import { computed } from 'vue'; 2 | import { useI18n } from 'vue-i18n'; 3 | import { Message } from '@arco-design/web-vue'; 4 | 5 | export default function useLocale() { 6 | const i18 = useI18n(); 7 | const currentLocale = computed(() => { 8 | return i18.locale.value; 9 | }); 10 | const changeLocale = (value: string) => { 11 | if (i18.locale.value === value) { 12 | return; 13 | } 14 | i18.locale.value = value; 15 | localStorage.setItem('arco-locale', value); 16 | Message.success(i18.t('navbar.action.locale')); 17 | }; 18 | return { 19 | currentLocale, 20 | changeLocale, 21 | }; 22 | } 23 | -------------------------------------------------------------------------------- /six-arco/src/api/system/auth-relation.ts: -------------------------------------------------------------------------------- 1 | import {RequestParam} from "@/api/base"; 2 | import axios from "axios"; 3 | 4 | export interface AuthRelation { 5 | id: number; 6 | rule_id: number; 7 | role_id: number; 8 | tenant_id?: number; 9 | create_time?: string; 10 | update_time?: string; 11 | delete_time?: string; 12 | } 13 | const root = 'admin/auth/relation' 14 | export function getCheckedRule(data: RequestParam) { 15 | return axios.post(`${root}/select/rule`, data); 16 | } 17 | 18 | export function set(role_id: number, rule_ids: number[]) { 19 | return axios.post(`${root}/set`, {role_id: role_id, rule_ids: rule_ids}); 20 | } -------------------------------------------------------------------------------- /six-go/database/dao/keyword_like.go: -------------------------------------------------------------------------------- 1 | package dao 2 | 3 | import ( 4 | "github.com/vainback/six-util/v3" 5 | "gorm.io/gorm" 6 | ) 7 | 8 | type QueryKeyword struct { 9 | Keyword string `json:"keyword"` 10 | } 11 | 12 | func (ts QueryKeyword) SqlBuilder(fields ...string) func(db *gorm.DB) *gorm.DB { 13 | return func(db *gorm.DB) *gorm.DB { 14 | if len(ts.Keyword) == 0 { 15 | return db 16 | } 17 | 18 | sql := six.Strings(fields[0], " like '%", ts.Keyword, "%'") 19 | if len(fields) > 1 { 20 | for _, field := range fields[1:] { 21 | sql.Append(" or ", field, " like '%", ts.Keyword, "%'") 22 | } 23 | } 24 | return db.Where(sql.String()) 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /six-arco/src/api/basic/files.ts: -------------------------------------------------------------------------------- 1 | import {RequestParam} from "@/api/base"; 2 | import axios from "axios"; 3 | import { S } from "mockjs"; 4 | 5 | export interface Files { 6 | id: number; 7 | tenant_id?: number; 8 | create_time?: string; 9 | update_time?: string; 10 | delete_time?: string; 11 | mime: String; 12 | type: string; 13 | url: string; 14 | } 15 | 16 | export const EmptyFile: Files = { 17 | id: 0, 18 | mime: '', 19 | type: '', 20 | url: '' 21 | } 22 | 23 | const root = 'admin/files' 24 | export function reqFiles(action: string, data: RequestParam | null) { 25 | return axios.post(`${root}/${action}`, data ||{}); 26 | } -------------------------------------------------------------------------------- /six-arco/src/router/routes/types.ts: -------------------------------------------------------------------------------- 1 | import { defineComponent } from 'vue'; 2 | import type { RouteMeta, NavigationGuard } from 'vue-router'; 3 | 4 | export type Component = 5 | | ReturnType 6 | | (() => Promise) 7 | | (() => Promise); 8 | 9 | export interface AppRouteRecordRaw { 10 | path: string; 11 | name?: string | symbol; 12 | meta?: RouteMeta; 13 | redirect?: string; 14 | component: Component | string; 15 | children?: AppRouteRecordRaw[]; 16 | alias?: string | string[]; 17 | props?: Record; 18 | beforeEnter?: NavigationGuard | NavigationGuard[]; 19 | fullPath?: string; 20 | } 21 | -------------------------------------------------------------------------------- /six-arco/src/api/system/tenant.ts: -------------------------------------------------------------------------------- 1 | import {RequestParam} from "@/api/base"; 2 | import axios from "axios"; 3 | 4 | export interface Tenant { 5 | id: number; 6 | name: string; 7 | sign: string; 8 | domain: string; 9 | status: number; 10 | create_time?: string; 11 | update_time?: string; 12 | delete_time?: string | null; 13 | } 14 | 15 | export const EmptyTenant: Tenant = { 16 | id: 0, 17 | name: '', 18 | sign: '', 19 | domain: '', 20 | status: 0, 21 | } 22 | 23 | const root = 'admin/tenant' 24 | export function reqTenant(action: string, data: RequestParam | null) { 25 | return axios.post(`${root}/${action}`, data || {}); 26 | } -------------------------------------------------------------------------------- /six-arco/src/utils/auth.ts: -------------------------------------------------------------------------------- 1 | const TOKEN_KEY = 'token'; 2 | 3 | const isLogin = () => { 4 | return !!localStorage.getItem(TOKEN_KEY); 5 | }; 6 | 7 | const getToken = () => { 8 | return localStorage.getItem(TOKEN_KEY); 9 | }; 10 | 11 | const setToken = (token: string) => { 12 | localStorage.setItem(TOKEN_KEY, token); 13 | }; 14 | 15 | const clearToken = () => { 16 | localStorage.removeItem(TOKEN_KEY); 17 | }; 18 | 19 | const getTenantId = () => { 20 | return localStorage.getItem("login.tenant_id"); 21 | } 22 | 23 | const isTenantRoot = () => { 24 | return Number(getTenantId()) === 1; 25 | } 26 | 27 | export { isLogin, getToken, setToken, clearToken, getTenantId, isTenantRoot }; 28 | -------------------------------------------------------------------------------- /six-go/extra/xredis/config.go: -------------------------------------------------------------------------------- 1 | package xredis 2 | 3 | import ( 4 | "github.com/spf13/cast" 5 | "six-go/config" 6 | ) 7 | 8 | const KeyPrefix = "six-admin" 9 | 10 | type _config struct { 11 | data map[string]any 12 | } 13 | 14 | func cfg() *_config { 15 | if data := config.Get("redis"); data != nil { 16 | return &_config{data: cast.ToStringMap(data)} 17 | } 18 | return &_config{data: make(map[string]any)} 19 | } 20 | 21 | func (r *_config) addr() string { 22 | return cast.ToString(r.data["addr"]) 23 | } 24 | 25 | func (r *_config) pass() string { 26 | return cast.ToString(r.data["pass"]) 27 | } 28 | 29 | func (r *_config) db() int { 30 | return cast.ToInt(r.data["db"]) 31 | } 32 | -------------------------------------------------------------------------------- /six-go/static/generator_tpl/server/route.go.tpl: -------------------------------------------------------------------------------- 1 | package adminRoute 2 | 3 | import ( 4 | "github.com/gin-gonic/gin" 5 | "six-go/app/admin/controller" 6 | ) 7 | 8 | func (r Route) (app *gin.RouterGroup) { 9 | p := app.Group("") 10 | p.POST("/list", controller..List) 11 | p.POST("/tree-select", controller..TreeSelect) 12 | p.POST("/select", controller..Select) 13 | p.POST("/get", controller..Get) 14 | p.POST("/add", controller..Add) 15 | p.POST("/edit", controller..Update) 16 | p.POST("/save", controller..Save) 17 | p.POST("/del", controller..Delete) 18 | } -------------------------------------------------------------------------------- /six-arco/src/api/basic/dict.ts: -------------------------------------------------------------------------------- 1 | import {RequestParam} from "@/api/base"; 2 | import axios from "axios"; 3 | 4 | export interface Dict { 5 | id: number; 6 | tenant_id?: number; 7 | create_time?: string; 8 | update_time?: string; 9 | delete_time?: string; 10 | type: string; 11 | label: string; 12 | value: string; 13 | color: string; 14 | is_sync: number; 15 | } 16 | 17 | export const EmptyDict: Dict = { 18 | id: 0, 19 | type: '', 20 | label: '', 21 | value: '', 22 | color: '', 23 | is_sync: 0, 24 | } 25 | 26 | const root = 'admin/dict' 27 | export function reqDict(action: string, data: RequestParam | null) { 28 | return axios.post(`${root}/${action}`, data ||{}); 29 | } -------------------------------------------------------------------------------- /six-go/utils/type_password.go: -------------------------------------------------------------------------------- 1 | package utils 2 | 3 | import ( 4 | "strings" 5 | 6 | "golang.org/x/crypto/bcrypt" 7 | ) 8 | 9 | type Password string 10 | 11 | func (password Password) TrimSpace() Password { 12 | return Password(strings.TrimSpace(string(password))) 13 | } 14 | 15 | func (password Password) Hash() Password { 16 | if password == "" { 17 | return password 18 | } 19 | hash, _ := bcrypt.GenerateFromPassword([]byte(password), 12) 20 | return Password(hash) 21 | } 22 | 23 | func (password Password) Verify(hash Password) bool { 24 | return bcrypt.CompareHashAndPassword([]byte(hash), []byte(password)) == nil 25 | } 26 | 27 | func (password Password) MarshalJSON() ([]byte, error) { 28 | return []byte(`""`), nil 29 | } 30 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # If you prefer the allow list template instead of the deny list, see community template: 2 | # https://github.com/github/gitignore/blob/main/community/Golang/Go.AllowList.gitignore 3 | # 4 | # Binaries for programs and plugins 5 | *.exe 6 | *.exe~ 7 | *.dll 8 | *.so 9 | *.dylib 10 | 11 | # Test binary, built with `go test -c` 12 | *.test 13 | 14 | # Output of the go coverage tool, specifically when used with LiteIDE 15 | *.out 16 | 17 | # Dependency directories (remove the comment below to include it) 18 | # vendor/ 19 | 20 | # Go workspace file 21 | go.work 22 | go.work.sum 23 | 24 | # env file 25 | .env 26 | 27 | .idea/ 28 | .vscode/ 29 | .husky/ 30 | .fleet/ 31 | node_modules/ 32 | vendor/ 33 | uploads/ 34 | tests/ 35 | dist/ -------------------------------------------------------------------------------- /six-go/config/app.go: -------------------------------------------------------------------------------- 1 | package config 2 | 3 | import ( 4 | "fmt" 5 | "strings" 6 | 7 | "github.com/spf13/cast" 8 | ) 9 | 10 | type AppConfig struct { 11 | data map[string]any 12 | } 13 | 14 | func APP() *AppConfig { 15 | if data, ok := _config["app"]; ok { 16 | return &AppConfig{data: cast.ToStringMap(data)} 17 | } 18 | return &AppConfig{data: make(map[string]any)} 19 | } 20 | 21 | func (a *AppConfig) ListenPort() string { 22 | port := strings.TrimSpace(cast.ToString(a.data["port"])) 23 | if port == "" { 24 | return ":8080" 25 | } 26 | return fmt.Sprintf(":%s", port) 27 | } 28 | 29 | func (a *AppConfig) Debug() bool { 30 | debug, ok := a.data["debug"] 31 | if !ok { 32 | return false 33 | } 34 | return cast.ToBool(debug) 35 | } 36 | -------------------------------------------------------------------------------- /six-arco/src/utils/event.ts: -------------------------------------------------------------------------------- 1 | export function addEventListen( 2 | target: Window | HTMLElement, 3 | event: string, 4 | handler: EventListenerOrEventListenerObject, 5 | capture = false 6 | ) { 7 | if ( 8 | target.addEventListener && 9 | typeof target.addEventListener === 'function' 10 | ) { 11 | target.addEventListener(event, handler, capture); 12 | } 13 | } 14 | 15 | export function removeEventListen( 16 | target: Window | HTMLElement, 17 | event: string, 18 | handler: EventListenerOrEventListenerObject, 19 | capture = false 20 | ) { 21 | if ( 22 | target.removeEventListener && 23 | typeof target.removeEventListener === 'function' 24 | ) { 25 | target.removeEventListener(event, handler, capture); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /six-arco/.stylelintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | extends: [ 3 | 'stylelint-config-standard', 4 | 'stylelint-config-rational-order', 5 | 'stylelint-config-prettier', 6 | 'stylelint-config-recommended-vue', 7 | ], 8 | defaultSeverity: 'warning', 9 | plugins: ['stylelint-order'], 10 | rules: { 11 | 'at-rule-no-unknown': [ 12 | true, 13 | { 14 | ignoreAtRules: ['plugin'], 15 | }, 16 | ], 17 | 'rule-empty-line-before': [ 18 | 'always', 19 | { 20 | except: ['after-single-line-comment', 'first-nested'], 21 | }, 22 | ], 23 | 'selector-pseudo-class-no-unknown': [ 24 | true, 25 | { 26 | ignorePseudoClasses: ['deep'], 27 | }, 28 | ], 29 | }, 30 | }; 31 | -------------------------------------------------------------------------------- /six-arco/src/router/routes/modules/tests.ts: -------------------------------------------------------------------------------- 1 | import { DEFAULT_LAYOUT } from '../base'; 2 | import { AppRouteRecordRaw } from '../types'; 3 | 4 | const BASIC: AppRouteRecordRaw = { 5 | path: '/testss', 6 | name: 'Testss', 7 | component: DEFAULT_LAYOUT, 8 | meta: { 9 | locale: '基础设置', 10 | requiresAuth: true, 11 | icon: 'icon-desktop', 12 | order: 98, 13 | }, 14 | children: [ 15 | { 16 | path: 'tests', 17 | name: 'Tests', 18 | component: () => import('@/views/codegen/tests/index.vue'), 19 | meta: { 20 | locale: '字典管理', 21 | requiresAuth: true, 22 | }, 23 | }, 24 | ], 25 | }; 26 | 27 | export default BASIC; 28 | -------------------------------------------------------------------------------- /six-arco/src/utils/monitor.ts: -------------------------------------------------------------------------------- 1 | import { App, ComponentPublicInstance } from 'vue'; 2 | import axios from 'axios'; 3 | 4 | export default function handleError(Vue: App, baseUrl: string) { 5 | if (!baseUrl) { 6 | return; 7 | } 8 | Vue.config.errorHandler = ( 9 | err: unknown, 10 | instance: ComponentPublicInstance | null, 11 | info: string 12 | ) => { 13 | // send error info 14 | axios.post(`${baseUrl}/report-error`, { 15 | err, 16 | instance, 17 | info, 18 | // location: window.location.href, 19 | // message: err.message, 20 | // stack: err.stack, 21 | // browserInfo: getBrowserInfo(), 22 | // user info 23 | // dom info 24 | // url info 25 | // ... 26 | }); 27 | }; 28 | } 29 | -------------------------------------------------------------------------------- /six-arco/src/types/global.ts: -------------------------------------------------------------------------------- 1 | export interface AnyObject { 2 | [key: string]: unknown; 3 | } 4 | 5 | export interface Options { 6 | value: unknown; 7 | label: string; 8 | } 9 | 10 | export interface NodeOptions extends Options { 11 | children?: NodeOptions[]; 12 | } 13 | 14 | export interface GetParams { 15 | body: null; 16 | type: string; 17 | url: string; 18 | } 19 | 20 | export interface PostData { 21 | body: string; 22 | type: string; 23 | url: string; 24 | } 25 | 26 | export interface Pagination { 27 | current: number; 28 | pageSize: number; 29 | total?: number; 30 | } 31 | 32 | export type TimeRanger = [string, string]; 33 | 34 | export interface GeneralChart { 35 | xAxis: string[]; 36 | data: Array<{ name: string; value: number[] }>; 37 | } 38 | -------------------------------------------------------------------------------- /six-arco/src/directive/permission/index.ts: -------------------------------------------------------------------------------- 1 | import { DirectiveBinding } from 'vue'; 2 | import { useUserStore } from '@/store'; 3 | 4 | function checkPermission(el: HTMLElement, binding: DirectiveBinding) { 5 | const { value } = binding; 6 | if ((value as String).trim() != '') { 7 | const hasBtns: string[] = JSON.parse(localStorage.getItem('permission:btns')) || []; 8 | if (!hasBtns.includes(value) && el.parentNode) { 9 | el.parentNode.removeChild(el); 10 | } 11 | } 12 | } 13 | 14 | export default { 15 | mounted(el: HTMLElement, binding: DirectiveBinding) { 16 | checkPermission(el, binding); 17 | }, 18 | updated(el: HTMLElement, binding: DirectiveBinding) { 19 | checkPermission(el, binding); 20 | }, 21 | }; 22 | -------------------------------------------------------------------------------- /six-go/utils/request/url_values.go: -------------------------------------------------------------------------------- 1 | package request 2 | 3 | import ( 4 | "fmt" 5 | "net/url" 6 | ) 7 | 8 | type URLParam struct { 9 | values url.Values 10 | } 11 | 12 | func UrlParam(k string, v ...any) *URLParam { 13 | var p URLParam 14 | p.values = url.Values{ 15 | k: p.strings(v), 16 | } 17 | return &p 18 | } 19 | 20 | func (p *URLParam) Add(k string, v ...any) *URLParam { 21 | p.values[k] = p.strings(v) 22 | return p 23 | } 24 | 25 | func (p *URLParam) Builder() string { 26 | return p.values.Encode() 27 | } 28 | 29 | func (p *URLParam) strings(v []any) []string { 30 | if len(v) == 0 { 31 | return nil 32 | } 33 | vs := make([]string, len(v)) 34 | if len(v) > 0 { 35 | for i, vv := range v { 36 | vs[i] = fmt.Sprint(vv) 37 | } 38 | } 39 | return vs 40 | } 41 | -------------------------------------------------------------------------------- /six-arco/src/api/base.ts: -------------------------------------------------------------------------------- 1 | export interface RequestParam { 2 | page?: number; 3 | limit?: number; 4 | start_time?: string; 5 | end_time?: string; 6 | keyword?: string; 7 | order_by?: OrderBy[]; 8 | is_delete?: boolean; // 真实删除传true 回收站查询传true 9 | model: T; 10 | } 11 | 12 | export interface OrderBy { 13 | field: string; 14 | is_desc: boolean; 15 | } 16 | 17 | // export const defaultRequestParam = 18 | 19 | export function defaultRequestParam(model: T): RequestParam { 20 | return { 21 | page: 1, 22 | limit: 15, 23 | start_time: '', 24 | end_time: '', 25 | keyword: '', 26 | order_by: [{ field: 'id', is_desc: true }], 27 | is_delete: false, 28 | model: model, 29 | }; 30 | } 31 | -------------------------------------------------------------------------------- /six-arco/src/layout/page-layout.vue: -------------------------------------------------------------------------------- 1 | 15 | 16 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /six-go/config.yaml: -------------------------------------------------------------------------------- 1 | app: 2 | port: 3000 3 | debug: true 4 | database: 5 | auto_migrate: false 6 | log_level: info 7 | max_open_conn: 10 8 | max_idle_conn: 10 9 | max_life_time: 14400 10 | dsn: "six:six-123.cmd@tcp(103.91.209.176:3306)/six?charset=utf8mb4&parseTime=True&loc=Local" 11 | redis: 12 | addr: "localhost:6379" 13 | password: "" 14 | db: 0 15 | upload: 16 | type: local 17 | name: md5 # todo 文件名生成方式 可选值 md5|times md5:信息摘要 可保证同一个文件不会重复保存在服务器上 times:纳秒级时间戳 18 | path: uploads 19 | cos: # 腾讯云对象存储 20 | secret_id: 21 | secret_key: 22 | bucket: 23 | region: 24 | oss: # 阿里云对象存储 25 | access_key_id: 26 | access_key_secret: 27 | bucket: 28 | endpoint: 29 | qiniu: # 七牛云对象存储 30 | access_key: 31 | secret_key: 32 | bucket: 33 | url: 34 | region: 35 | -------------------------------------------------------------------------------- /six-arco/src/api/system/job.ts: -------------------------------------------------------------------------------- 1 | import {AuthRule} from "@/api/system/auth-rule"; 2 | import {RequestParam} from "@/api/base"; 3 | import axios from "axios"; 4 | 5 | export interface Job { 6 | id: number; 7 | parent_id: number; 8 | name: string; 9 | description: string; 10 | tenant_id?: number; 11 | create_time?: string; 12 | update_time?: string; 13 | delete_time?: string; 14 | } 15 | 16 | export interface TreeJob extends Job{ 17 | children?: TreeJob[]; 18 | } 19 | const root = 'admin/job' 20 | 21 | export const EmptyJob = { 22 | id: 0, 23 | parent_id: 0, 24 | name: '', 25 | description:'', 26 | } 27 | 28 | export function reqJobs(action: string, data: RequestParam | null) { 29 | return axios.post(`${root}/${action}`, data || {}); 30 | } -------------------------------------------------------------------------------- /six-arco/src/App.vue: -------------------------------------------------------------------------------- 1 | 7 | 8 | 27 | -------------------------------------------------------------------------------- /six-go/database/dao/time_range.go: -------------------------------------------------------------------------------- 1 | package dao 2 | 3 | import ( 4 | "github.com/vainback/six-util/v3" 5 | "strings" 6 | 7 | "gorm.io/gorm" 8 | ) 9 | 10 | type QueryTime struct { 11 | StartTime string `json:"start_time"` 12 | EndTime string `json:"end_time"` 13 | } 14 | 15 | func (ts QueryTime) SqlBuilder(tableName ...string) func(db *gorm.DB) *gorm.DB { 16 | var field = "create_time" 17 | if len(tableName) > 0 { 18 | field = six.Str(tableName[0]).Append(".", field).String() 19 | } 20 | 21 | return func(db *gorm.DB) *gorm.DB { 22 | if start := strings.TrimSpace(ts.StartTime); start != "" { 23 | db = db.Where(field+" > ?", start) 24 | } 25 | 26 | if end := strings.TrimSpace(ts.EndTime); end != "" { 27 | db = db.Where(field+" < ?", end) 28 | } 29 | 30 | return db 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /six-go/utils/operator_ternary.go: -------------------------------------------------------------------------------- 1 | package utils 2 | 3 | import ( 4 | "github.com/vainback/six-util/v3" 5 | "golang.org/x/exp/constraints" 6 | "reflect" 7 | ) 8 | 9 | // Ternary 三元运算 等价于 condition ? a : b 10 | func Ternary[T any](condition bool, a T, b T) T { 11 | if condition { 12 | return a 13 | } 14 | return b 15 | } 16 | 17 | // Binary 二元运算符 等价于 b := a ?: b | a 不为nil 不为空 不为0值时 取a 否则取b 18 | func Binary[T any](a T, b T) T { 19 | vof := reflect.ValueOf(a) 20 | if !vof.IsNil() || !vof.IsZero() { 21 | return a 22 | } 23 | 24 | return b 25 | } 26 | 27 | // BinaryOrdered 二元运算符 等价于 b := a ?: b | a 不为空字符串 不为0 不为false时取a 否则取b 28 | func BinaryOrdered[T constraints.Ordered](a T, b T) T { 29 | x := six.StrX(a) 30 | if !x.IsEmpty() || x.Int() != 0 || x.Bool() { 31 | return a 32 | } 33 | return b 34 | } 35 | -------------------------------------------------------------------------------- /six-arco/src/api/basic/code.ts: -------------------------------------------------------------------------------- 1 | import {RequestParam} from "@/api/base"; 2 | import axios from "axios"; 3 | 4 | export interface Codegen { 5 | id: number; 6 | create_time?: string; 7 | update_time?: string; 8 | delete_time?: string; 9 | table: string; 10 | title: string; 11 | fields: any[] | null; 12 | parent_module: number | null; 13 | is_soft_delete: boolean; 14 | is_tenant: boolean; 15 | } 16 | 17 | export const EmptyCodegen: Codegen = { 18 | id: 0, 19 | table: '', 20 | title: '', 21 | fields: [], 22 | parent_module: null, 23 | is_soft_delete: true, 24 | is_tenant: true, 25 | } 26 | 27 | const root = 'admin/codegen' 28 | export function reqCodegen(action: string, data: RequestParam | null) { 29 | return axios.post(`${root}/${action}`, data ||{}); 30 | } -------------------------------------------------------------------------------- /six-arco/src/hooks/user.ts: -------------------------------------------------------------------------------- 1 | import { useRouter } from 'vue-router'; 2 | import { Message } from '@arco-design/web-vue'; 3 | 4 | import { useUserStore } from '@/store'; 5 | 6 | export default function useUser() { 7 | const router = useRouter(); 8 | const userStore = useUserStore(); 9 | const logout = async (logoutTo?: string) => { 10 | await userStore.logout(); 11 | const currentRoute = router.currentRoute.value; 12 | Message.success('登出成功'); 13 | router.push({ 14 | name: logoutTo && typeof logoutTo === 'string' ? logoutTo : 'login', 15 | query: { 16 | ...router.currentRoute.value.query, 17 | redirect: currentRoute.name as string, 18 | }, 19 | }); 20 | }; 21 | return { 22 | logout, 23 | }; 24 | } 25 | -------------------------------------------------------------------------------- /six-go/database/models/fn_tenant_identify.go: -------------------------------------------------------------------------------- 1 | package models 2 | 3 | import ( 4 | "strings" 5 | 6 | "gorm.io/gorm" 7 | ) 8 | 9 | type TenantIdentify struct { 10 | TenantId int64 `json:"tenant_id" gorm:"column:tenant_id;comment:租户id;index"` 11 | } 12 | 13 | func (data TenantIdentify) FiledName() string { 14 | return "tenant_id" 15 | } 16 | 17 | // SqlBuilder tables 只取第一个参数 18 | func (data TenantIdentify) SqlBuilder(tableName ...string) func(db *gorm.DB) *gorm.DB { 19 | var tableQuery strings.Builder 20 | if len(tableName) > 0 { 21 | tableQuery.WriteString(tableName[0]) 22 | tableQuery.WriteString(".") 23 | } 24 | tableQuery.WriteString("tenant_id = ?") 25 | return func(db *gorm.DB) *gorm.DB { 26 | if data.TenantId > 0 { 27 | db = db.Where(tableQuery.String(), data.TenantId) 28 | } 29 | return db 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /six-arco/config/plugin/arcoResolver.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * If you use the template method for development, you can use the unplugin-vue-components plugin to enable on-demand loading support. 3 | * 按需引入 4 | * https://github.com/antfu/unplugin-vue-components 5 | * https://arco.design/vue/docs/start 6 | * Although the Pro project is full of imported components, this plugin will be used by default. 7 | * 虽然Pro项目中是全量引入组件,但此插件会默认使用。 8 | */ 9 | import Components from 'unplugin-vue-components/vite'; 10 | import { ArcoResolver } from 'unplugin-vue-components/resolvers'; 11 | 12 | export default function configArcoResolverPlugin() { 13 | const arcoResolverPlugin = Components({ 14 | dirs: [], // Avoid parsing src/components. 避免解析到src/components 15 | deep: false, 16 | resolvers: [ArcoResolver()], 17 | }); 18 | return arcoResolverPlugin; 19 | } 20 | -------------------------------------------------------------------------------- /six-arco/src/views/login/locale/zh-CN.ts: -------------------------------------------------------------------------------- 1 | export default { 2 | 'login.form.title': '登录 Arco Design Pro', 3 | 'login.form.userName.errMsg': '用户名不能为空', 4 | 'login.form.password.errMsg': '密码不能为空', 5 | 'login.form.login.errMsg': '登录出错,轻刷新重试', 6 | 'login.form.login.success': '欢迎使用', 7 | 'login.form.userName.placeholder': '用户名:admin', 8 | 'login.form.password.placeholder': '密码:admin', 9 | 'login.form.rememberPassword': '记住密码', 10 | 'login.form.forgetPassword': '忘记密码', 11 | 'login.form.login': '登录', 12 | 'login.form.register': '注册账号', 13 | 'login.banner.slogan1': '开箱即用的高质量模板', 14 | 'login.banner.subSlogan1': '丰富的的页面模板,覆盖大多数典型业务场景', 15 | 'login.banner.slogan2': '内置了常见问题的解决方案', 16 | 'login.banner.subSlogan2': '国际化,路由配置,状态管理应有尽有', 17 | 'login.banner.slogan3': '接入可视化增强工具AUX', 18 | 'login.banner.subSlogan3': '实现灵活的区块式开发', 19 | }; 20 | -------------------------------------------------------------------------------- /six-arco/src/views/not-found/index.vue: -------------------------------------------------------------------------------- 1 | 9 | 10 | 19 | 20 | 31 | -------------------------------------------------------------------------------- /six-arco/src/api/system/organization.ts: -------------------------------------------------------------------------------- 1 | import {AuthRule} from "@/api/system/auth-rule"; 2 | import {RequestParam} from "@/api/base"; 3 | import axios from "axios"; 4 | 5 | export interface Organization { 6 | id: number; 7 | parent_id: number; 8 | name: string; 9 | description: string; 10 | tenant_id?: number; 11 | create_time?: string; 12 | update_time?: string; 13 | delete_time?: string; 14 | } 15 | 16 | export interface TreeOrganization extends Organization{ 17 | children?: TreeOrganization[]; 18 | } 19 | const root = 'admin/organization' 20 | 21 | export const EmptyOrganization = { 22 | id: 0, 23 | parent_id: 0, 24 | name: '', 25 | description:'', 26 | } 27 | 28 | export function reqOrgs(action: string, data: RequestParam | null) { 29 | return axios.post(`${root}/${action}`, data || {}); 30 | } -------------------------------------------------------------------------------- /six-arco/src/router/routes/modules/dashboard.ts: -------------------------------------------------------------------------------- 1 | import { DEFAULT_LAYOUT } from '../base'; 2 | import { AppRouteRecordRaw } from '../types'; 3 | 4 | const DASHBOARD: AppRouteRecordRaw = { 5 | path: '/dashboard', 6 | name: 'dashboard', 7 | component: DEFAULT_LAYOUT, 8 | meta: { 9 | locale: 'menu.dashboard', 10 | requiresAuth: true, 11 | icon: 'icon-dashboard', 12 | order: 0, 13 | }, 14 | children: [ 15 | { 16 | path: 'workplace', 17 | name: 'Workplace', 18 | component: () => import('@/views/dashboard/workplace/index.vue'), 19 | meta: { 20 | locale: 'menu.dashboard.workplace', 21 | requiresAuth: true, 22 | roles: ['*'], 23 | }, 24 | }, 25 | ], 26 | }; 27 | 28 | export default DASHBOARD; 29 | -------------------------------------------------------------------------------- /six-arco/src/components/breadcrumb/index.vue: -------------------------------------------------------------------------------- 1 | 11 | 12 | 24 | 25 | 36 | -------------------------------------------------------------------------------- /six-go/utils/tree.go: -------------------------------------------------------------------------------- 1 | package utils 2 | 3 | import ( 4 | "github.com/spf13/cast" 5 | "github.com/vainback/six-util/v3" 6 | ) 7 | 8 | const ( 9 | TreeIDKey = "id" 10 | TreePIDKey = "parent_id" 11 | TreeChildKey = "children" 12 | ) 13 | 14 | type Tree struct { 15 | list []map[string]any 16 | } 17 | 18 | func NewTree[T any](list []T) *Tree { 19 | return &Tree{six.Structs2SliceMap(list)} 20 | } 21 | 22 | func NewTreeWithMapAny(list []map[string]any) *Tree { 23 | return &Tree{list} 24 | } 25 | 26 | func (t *Tree) Parser(pid int64) []map[string]any { 27 | var tree []map[string]any 28 | for _, v := range t.list { 29 | tPid := cast.ToInt64(v[TreePIDKey]) 30 | if tPid == pid { 31 | child := t.Parser(cast.ToInt64(v[TreeIDKey])) 32 | if len(child) > 0 { 33 | v[TreeChildKey] = child 34 | } 35 | tree = append(tree, v) 36 | } 37 | } 38 | return tree 39 | } 40 | -------------------------------------------------------------------------------- /six-arco/src/api/system/auth-role.ts: -------------------------------------------------------------------------------- 1 | import { RequestParam } from '@/api/base'; 2 | import axios from 'axios'; 3 | import {EmptyJob} from "@/api/system/job"; 4 | 5 | export interface AuthRole { 6 | id: number; 7 | parent_id: number; 8 | title: string; 9 | sign: string; 10 | status: number; 11 | tenant_id?: number; 12 | create_time?: string; 13 | update_time?: string; 14 | delete_time?: string; 15 | } 16 | 17 | export interface TreeAuthRole extends AuthRole { 18 | children?: TreeAuthRole[]; 19 | } 20 | 21 | export const EmptyRole : AuthRole = { 22 | id: 0, 23 | parent_id: 0, 24 | title: '', 25 | sign: '', 26 | status: 0, 27 | } 28 | 29 | const root = 'admin/auth/role'; 30 | 31 | export function reqAuthRole(action: string, data: RequestParam | null) { 32 | return axios.post(`${root}/${action}`, data || {}); 33 | } 34 | -------------------------------------------------------------------------------- /six-arco/src/router/routes/index.ts: -------------------------------------------------------------------------------- 1 | import type { RouteRecordNormalized } from 'vue-router'; 2 | 3 | const modules = import.meta.glob('./modules/*.ts', { eager: true }); 4 | const externalModules = import.meta.glob('./externalModules/*.ts', { 5 | eager: true, 6 | }); 7 | 8 | function formatModules(_modules: any, result: RouteRecordNormalized[]) { 9 | Object.keys(_modules).forEach((key) => { 10 | const defaultModule = _modules[key].default; 11 | if (!defaultModule) return; 12 | const moduleList = Array.isArray(defaultModule) 13 | ? [...defaultModule] 14 | : [defaultModule]; 15 | result.push(...moduleList); 16 | }); 17 | return result; 18 | } 19 | 20 | export const appRoutes: RouteRecordNormalized[] = formatModules(modules, []); 21 | 22 | export const appExternalRoutes: RouteRecordNormalized[] = formatModules( 23 | externalModules, 24 | [] 25 | ); 26 | -------------------------------------------------------------------------------- /six-go/app/admin/route/route_auth_user_single.go: -------------------------------------------------------------------------------- 1 | package adminRoute 2 | 3 | import ( 4 | "github.com/gin-gonic/gin" 5 | "six-go/app/admin/controller" 6 | "six-go/app/admin/middleware" 7 | ) 8 | 9 | func (r SingleRoute) AuthUserSingle(app *gin.RouterGroup) { 10 | p := app.Group("/user/single") 11 | p.POST("/tenant", controller.UserSingle.GetTenant) 12 | p.POST("/login", controller.UserSingle.Login) 13 | 14 | p.Use(middleware.IsLogin) 15 | p.POST("/info", controller.UserSingle.Userinfo) 16 | p.POST("/logout", controller.UserSingle.Logout) 17 | p.POST("/menu", middleware.TenantDI, controller.UserSingle.Menu) 18 | p.POST("/btns", controller.UserSingle.Btns) 19 | 20 | p.Use(middleware.Logs(LogMode)) 21 | p.POST("/update", controller.UserSingle.Update) 22 | p.POST("/reset/password", controller.UserSingle.ResetPassword) 23 | p.POST("/upload", controller.UserSingle.Upload) 24 | } 25 | -------------------------------------------------------------------------------- /six-arco/src/hooks/request.ts: -------------------------------------------------------------------------------- 1 | import { ref, UnwrapRef } from 'vue'; 2 | import { AxiosResponse } from 'axios'; 3 | import { HttpResponse } from '@/api/interceptor'; 4 | import useLoading from './loading'; 5 | 6 | // use to fetch list 7 | // Don't use async function. It doesn't work in async function. 8 | // Use the bind function to add parameters 9 | // example: useRequest(api.bind(null, {})) 10 | 11 | export default function useRequest( 12 | api: () => Promise>, 13 | defaultValue = [] as unknown as T, 14 | isLoading = true 15 | ) { 16 | const { loading, setLoading } = useLoading(isLoading); 17 | const response = ref(defaultValue); 18 | api() 19 | .then((res) => { 20 | response.value = res.data as unknown as UnwrapRef; 21 | }) 22 | .finally(() => { 23 | setLoading(false); 24 | }); 25 | return { loading, response }; 26 | } 27 | -------------------------------------------------------------------------------- /six-go/config/config.go: -------------------------------------------------------------------------------- 1 | package config 2 | 3 | import ( 4 | "fmt" 5 | "log" 6 | 7 | "github.com/fsnotify/fsnotify" 8 | "github.com/spf13/viper" 9 | ) 10 | 11 | var Notices = make(chan bool, 128) 12 | 13 | var _config map[string]any 14 | 15 | func init() { 16 | v := viper.New() 17 | v.AddConfigPath(".") 18 | v.SetConfigType("yaml") 19 | v.SetConfigName("config") 20 | if err := v.ReadInConfig(); err != nil { 21 | log.Fatalln(err) 22 | } 23 | v.WatchConfig() 24 | if err := v.Unmarshal(&_config); err != nil { 25 | log.Fatalln(err) 26 | } 27 | v.OnConfigChange(func(in fsnotify.Event) { 28 | fmt.Println(in.Name, " 配置文件内容被更改。如有必要,请重启程序!") 29 | if err := v.Unmarshal(&_config); err != nil { 30 | log.Println(err) 31 | } 32 | Notices <- true 33 | }) 34 | } 35 | 36 | func Get(key string) any { 37 | val, ok := _config[key] 38 | if !ok { 39 | return nil 40 | } 41 | return val 42 | } 43 | -------------------------------------------------------------------------------- /six-arco/src/utils/route-listener.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Listening to routes alone would waste rendering performance. Use the publish-subscribe model for distribution management 3 | * 单独监听路由会浪费渲染性能。使用发布订阅模式去进行分发管理。 4 | */ 5 | import mitt, { Handler } from 'mitt'; 6 | import type { RouteLocationNormalized } from 'vue-router'; 7 | 8 | const emitter = mitt(); 9 | 10 | const key = Symbol('ROUTE_CHANGE'); 11 | 12 | let latestRoute: RouteLocationNormalized; 13 | 14 | export function setRouteEmitter(to: RouteLocationNormalized) { 15 | emitter.emit(key, to); 16 | latestRoute = to; 17 | } 18 | 19 | export function listenerRouteChange( 20 | handler: (route: RouteLocationNormalized) => void, 21 | immediate = true 22 | ) { 23 | emitter.on(key, handler as Handler); 24 | if (immediate && latestRoute) { 25 | handler(latestRoute); 26 | } 27 | } 28 | 29 | export function removeRouteListener() { 30 | emitter.off(key); 31 | } 32 | -------------------------------------------------------------------------------- /six-arco/config/plugin/imagemin.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Image resource files used to compress the output of the production environment 3 | * 图片压缩 4 | * https://github.com/anncwb/vite-plugin-imagemin 5 | */ 6 | import viteImagemin from 'vite-plugin-imagemin'; 7 | 8 | export default function configImageminPlugin() { 9 | const imageminPlugin = viteImagemin({ 10 | gifsicle: { 11 | optimizationLevel: 7, 12 | interlaced: false, 13 | }, 14 | optipng: { 15 | optimizationLevel: 7, 16 | }, 17 | mozjpeg: { 18 | quality: 20, 19 | }, 20 | pngquant: { 21 | quality: [0.8, 0.9], 22 | speed: 4, 23 | }, 24 | svgo: { 25 | plugins: [ 26 | { 27 | name: 'removeViewBox', 28 | }, 29 | { 30 | name: 'removeEmptyAttrs', 31 | active: false, 32 | }, 33 | ], 34 | }, 35 | }); 36 | return imageminPlugin; 37 | } 38 | -------------------------------------------------------------------------------- /six-arco/src/locale/zh-CN.ts: -------------------------------------------------------------------------------- 1 | import localeMessageBox from '@/components/message-box/locale/zh-CN'; 2 | import localeLogin from '@/views/login/locale/zh-CN'; 3 | 4 | import localeWorkplace from '@/views/dashboard/workplace/locale/zh-CN'; 5 | 6 | import localeSettings from './zh-CN/settings'; 7 | 8 | export default { 9 | 'menu.dashboard': '仪表盘', 10 | 'menu.server.dashboard': '仪表盘-服务端', 11 | 'menu.server.workplace': '工作台-服务端', 12 | 'menu.server.monitor': '实时监控-服务端', 13 | 'menu.list': '列表页', 14 | 'menu.result': '结果页', 15 | 'menu.exception': '异常页', 16 | 'menu.form': '表单页', 17 | 'menu.profile': '详情页', 18 | 'menu.visualization': '数据可视化', 19 | 'menu.user': '个人中心', 20 | 'menu.arcoWebsite': 'Arco Design', 21 | 'menu.faq': '常见问题', 22 | 'navbar.docs': '文档中心', 23 | 'navbar.action.locale': '切换为中文', 24 | ...localeSettings, 25 | ...localeMessageBox, 26 | ...localeLogin, 27 | ...localeWorkplace, 28 | }; 29 | -------------------------------------------------------------------------------- /six-arco/src/router/routes/base.ts: -------------------------------------------------------------------------------- 1 | import type { RouteRecordRaw } from 'vue-router'; 2 | import { REDIRECT_ROUTE_NAME } from '@/router/constants'; 3 | 4 | export const DEFAULT_LAYOUT = () => import('@/layout/default-layout.vue'); 5 | 6 | export const REDIRECT_MAIN: RouteRecordRaw = { 7 | path: '/redirect', 8 | name: 'redirectWrapper', 9 | component: DEFAULT_LAYOUT, 10 | meta: { 11 | requiresAuth: true, 12 | hideInMenu: true, 13 | }, 14 | children: [ 15 | { 16 | path: '/redirect/:path', 17 | name: REDIRECT_ROUTE_NAME, 18 | component: () => import('@/views/redirect/index.vue'), 19 | meta: { 20 | requiresAuth: true, 21 | hideInMenu: true, 22 | }, 23 | }, 24 | ], 25 | }; 26 | 27 | export const NOT_FOUND_ROUTE: RouteRecordRaw = { 28 | path: '/:pathMatch(.*)*', 29 | name: 'notFound', 30 | component: () => import('@/views/not-found/index.vue'), 31 | }; 32 | -------------------------------------------------------------------------------- /six-arco/src/api/system/logs.ts: -------------------------------------------------------------------------------- 1 | import {RequestParam} from "@/api/base"; 2 | import axios from "axios"; 3 | 4 | export interface Log { 5 | id: number; 6 | ip: string; 7 | uid: number; 8 | route: string; 9 | route_name: string; 10 | request_body: string; 11 | response_body: string; 12 | latency: string; 13 | agent: string; 14 | method: string; 15 | tenant_id?: number; 16 | create_time?: string; 17 | update_time?: string; 18 | delete_time?: string; 19 | } 20 | 21 | export const EmptyLog: Log = { 22 | id: 0, 23 | ip: '', 24 | uid: 0, 25 | route: '', 26 | route_name: '', 27 | request_body: '', 28 | response_body: '', 29 | latency: '', 30 | agent: '', 31 | method: '' 32 | } 33 | 34 | const root = 'admin/logs' 35 | export function reqLog(action: string, data: RequestParam | null) { 36 | return axios.post(`${root}/${action}`, data || {}); 37 | } -------------------------------------------------------------------------------- /six-arco/src/api/message.ts: -------------------------------------------------------------------------------- 1 | import axios from 'axios'; 2 | 3 | export interface MessageRecord { 4 | id: number; 5 | type: string; 6 | title: string; 7 | subTitle: string; 8 | avatar?: string; 9 | content: string; 10 | time: string; 11 | status: 0 | 1; 12 | messageType?: number; 13 | } 14 | export type MessageListType = MessageRecord[]; 15 | 16 | export function queryMessageList() { 17 | return axios.post('/api/message/list'); 18 | } 19 | 20 | interface MessageStatus { 21 | ids: number[]; 22 | } 23 | 24 | export function setMessageStatus(data: MessageStatus) { 25 | return axios.post('/api/message/read', data); 26 | } 27 | 28 | export interface ChatRecord { 29 | id: number; 30 | username: string; 31 | content: string; 32 | time: string; 33 | isCollect: boolean; 34 | } 35 | 36 | export function queryChatList() { 37 | return axios.post('/api/chat/list'); 38 | } 39 | -------------------------------------------------------------------------------- /six-go/extra/uploader/local.go: -------------------------------------------------------------------------------- 1 | package uploader 2 | 3 | import ( 4 | "fmt" 5 | "io" 6 | "mime/multipart" 7 | "os" 8 | "path" 9 | ) 10 | 11 | type Local struct { 12 | path string 13 | } 14 | 15 | func newLocal() Uploader { 16 | return &Local{path: conf().path} 17 | } 18 | 19 | func (l *Local) Upload(f *multipart.FileHeader) (res Result) { 20 | res.IsLocal = true 21 | 22 | ext := path.Ext(f.Filename) 23 | open, err := f.Open() 24 | if err != nil { 25 | res.Error = fmt.Errorf("upload err:%v", err) 26 | return 27 | } 28 | 29 | all, err2 := io.ReadAll(open) 30 | if err2 != nil { 31 | res.Error = fmt.Errorf("upload err:%v", err) 32 | return 33 | } 34 | 35 | if conf().name == "md5" { 36 | res.Url = filenameByMd5(all, ext) 37 | } else if conf().name == "times" { 38 | res.Url = filenameByTimes(ext) 39 | } 40 | return 41 | } 42 | 43 | func (l *Local) Remove(filepath string) error { 44 | return os.Remove(filepath) 45 | } 46 | -------------------------------------------------------------------------------- /six-arco/src/views/dashboard/workplace/components/banner.vue: -------------------------------------------------------------------------------- 1 | 11 | 12 | 23 | 24 | 36 | -------------------------------------------------------------------------------- /six-arco/config/plugin/compress.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Used to package and output gzip. Note that this does not work properly in Vite, the specific reason is still being investigated 3 | * gzip压缩 4 | * https://github.com/anncwb/vite-plugin-compression 5 | */ 6 | import type { Plugin } from 'vite'; 7 | import compressPlugin from 'vite-plugin-compression'; 8 | 9 | export default function configCompressPlugin( 10 | compress: 'gzip' | 'brotli', 11 | deleteOriginFile = false 12 | ): Plugin | Plugin[] { 13 | const plugins: Plugin[] = []; 14 | 15 | if (compress === 'gzip') { 16 | plugins.push( 17 | compressPlugin({ 18 | ext: '.gz', 19 | deleteOriginFile, 20 | }) 21 | ); 22 | } 23 | 24 | if (compress === 'brotli') { 25 | plugins.push( 26 | compressPlugin({ 27 | ext: '.br', 28 | algorithm: 'brotliCompress', 29 | deleteOriginFile, 30 | }) 31 | ); 32 | } 33 | return plugins; 34 | } 35 | -------------------------------------------------------------------------------- /six-arco/src/components/index.ts: -------------------------------------------------------------------------------- 1 | import { App } from 'vue'; 2 | import { use } from 'echarts/core'; 3 | import { CanvasRenderer } from 'echarts/renderers'; 4 | import { BarChart, LineChart, PieChart, RadarChart } from 'echarts/charts'; 5 | import { 6 | GridComponent, 7 | TooltipComponent, 8 | LegendComponent, 9 | DataZoomComponent, 10 | GraphicComponent, 11 | } from 'echarts/components'; 12 | import Chart from './chart/index.vue'; 13 | import Breadcrumb from './breadcrumb/index.vue'; 14 | 15 | // Manually introduce ECharts modules to reduce packing size 16 | 17 | use([ 18 | CanvasRenderer, 19 | BarChart, 20 | LineChart, 21 | PieChart, 22 | RadarChart, 23 | GridComponent, 24 | TooltipComponent, 25 | LegendComponent, 26 | DataZoomComponent, 27 | GraphicComponent, 28 | ]); 29 | 30 | export default { 31 | install(Vue: App) { 32 | Vue.component('Chart', Chart); 33 | Vue.component('Breadcrumb', Breadcrumb); 34 | }, 35 | }; 36 | -------------------------------------------------------------------------------- /six-arco/src/components/global-setting/form-wrapper.vue: -------------------------------------------------------------------------------- 1 | 16 | 17 | 40 | -------------------------------------------------------------------------------- /six-arco/src/router/typings.d.ts: -------------------------------------------------------------------------------- 1 | import 'vue-router'; 2 | 3 | declare module 'vue-router' { 4 | interface RouteMeta { 5 | roles?: string[]; // Controls roles that have access to the page 6 | requiresAuth: boolean; // Whether login is required to access the current page (every route must declare) 7 | icon?: string; // The icon show in the side menu 8 | locale?: string; // The locale name show in side menu and breadcrumb 9 | hideInMenu?: boolean; // If true, it is not displayed in the side menu 10 | hideChildrenInMenu?: boolean; // if set true, the children are not displayed in the side menu 11 | activeMenu?: string; // if set name, the menu will be highlighted according to the name you set 12 | order?: number; // Sort routing menu items. If set key, the higher the value, the more forward it is 13 | noAffix?: boolean; // if set true, the tag will not affix in the tab-bar 14 | ignoreCache?: boolean; // if set true, the page will not be cached 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /six-arco/src/api/user.ts: -------------------------------------------------------------------------------- 1 | import axios from 'axios'; 2 | import type { RouteRecordNormalized } from 'vue-router'; 3 | import { UserState } from '@/store/modules/user/types'; 4 | 5 | export interface LoginData { 6 | username: string; 7 | password: string; 8 | } 9 | 10 | export interface LoginRes { 11 | token: string; 12 | } 13 | export function login(data: LoginData) { 14 | return axios.post('/api/user/login', data); 15 | } 16 | 17 | export function logout() { 18 | return axios.post('/api/user/logout'); 19 | } 20 | 21 | export function getUserInfo() { 22 | return axios.post('/api/user/info'); 23 | } 24 | 25 | // export function getMenuList() { 26 | // return axios.post('/api/user/menu'); 27 | // } 28 | 29 | export function getPermissionBtns() { 30 | return axios.post('admin/user/single/btns', {model: {}}); 31 | } 32 | 33 | export function getMenuList() { 34 | return axios.post('admin/user/single/menu', {model: {}}) 35 | } 36 | -------------------------------------------------------------------------------- /six-arco/src/locale/en-US.ts: -------------------------------------------------------------------------------- 1 | import localeMessageBox from '@/components/message-box/locale/en-US'; 2 | import localeLogin from '@/views/login/locale/en-US'; 3 | 4 | import localeWorkplace from '@/views/dashboard/workplace/locale/en-US'; 5 | 6 | import localeSettings from './en-US/settings'; 7 | 8 | export default { 9 | 'menu.dashboard': 'Dashboard', 10 | 'menu.server.dashboard': 'Dashboard-Server', 11 | 'menu.server.workplace': 'Workplace-Server', 12 | 'menu.server.monitor': 'Monitor-Server', 13 | 'menu.list': 'List', 14 | 'menu.result': 'Result', 15 | 'menu.exception': 'Exception', 16 | 'menu.form': 'Form', 17 | 'menu.profile': 'Profile', 18 | 'menu.visualization': 'Data Visualization', 19 | 'menu.user': 'User Center', 20 | 'menu.arcoWebsite': 'Arco Design', 21 | 'menu.faq': 'FAQ', 22 | 'navbar.docs': 'Docs', 23 | 'navbar.action.locale': 'Switch to English', 24 | ...localeSettings, 25 | ...localeMessageBox, 26 | ...localeLogin, 27 | ...localeWorkplace, 28 | }; 29 | -------------------------------------------------------------------------------- /six-arco/src/main.ts: -------------------------------------------------------------------------------- 1 | import { createApp } from 'vue'; 2 | import ArcoVue from '@arco-design/web-vue'; 3 | import ArcoVueIcon from '@arco-design/web-vue/es/icon'; 4 | import globalComponents from '@/components'; 5 | import router from './router'; 6 | import store from './store'; 7 | import i18n from './locale'; 8 | import directive from './directive'; 9 | import './mock'; 10 | import App from './App.vue'; 11 | // Styles are imported via arco-plugin. See config/plugin/arcoStyleImport.ts in the directory for details 12 | // 样式通过 arco-plugin 插件导入。详见目录文件 config/plugin/arcoStyleImport.ts 13 | // https://arco.design/docs/designlab/use-theme-package 14 | import '@/assets/style/global.less'; 15 | import '@/assets/style/six.less'; 16 | import '@/api/interceptor'; 17 | 18 | const app = createApp(App); 19 | 20 | app.use(ArcoVue, {}); 21 | app.use(ArcoVueIcon); 22 | 23 | app.use(router); 24 | app.use(store); 25 | app.use(i18n); 26 | app.use(globalComponents); 27 | app.use(directive); 28 | 29 | app.mount('#app'); 30 | -------------------------------------------------------------------------------- /six-go/database/dao/order_by.go: -------------------------------------------------------------------------------- 1 | package dao 2 | 3 | import ( 4 | "strings" 5 | 6 | "gorm.io/gorm" 7 | ) 8 | 9 | type QueryOrderBys struct { 10 | OrderBy []QueryOrderBy `json:"order_by"` 11 | } 12 | 13 | type QueryOrderBy struct { 14 | Field string `json:"field"` 15 | IsDesc bool `json:"is_desc"` 16 | } 17 | 18 | const OrderByDefault = "create_time desc" 19 | 20 | func (ts QueryOrderBys) SqlBuilder() func(db *gorm.DB) *gorm.DB { 21 | var isDesc = map[bool]string{ 22 | false: "asc", 23 | true: "desc", 24 | } 25 | return func(db *gorm.DB) *gorm.DB { 26 | obl := len(ts.OrderBy) 27 | if obl == 0 { 28 | return db.Order(OrderByDefault) 29 | } 30 | 31 | var sql strings.Builder 32 | for _, orderBy := range ts.OrderBy { 33 | sql.WriteString(ts.OrderBy[0].Field) 34 | sql.WriteString(" ") 35 | sql.WriteString(isDesc[orderBy.IsDesc]) 36 | sql.WriteString(",") 37 | } 38 | orderBySql := strings.Trim(sql.String(), ",") 39 | return db.Order(orderBySql) 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /six-arco/config/vite.config.prod.ts: -------------------------------------------------------------------------------- 1 | import { mergeConfig } from 'vite'; 2 | import baseConfig from './vite.config.base'; 3 | import configCompressPlugin from './plugin/compress'; 4 | import configVisualizerPlugin from './plugin/visualizer'; 5 | import configArcoResolverPlugin from './plugin/arcoResolver'; 6 | import configImageminPlugin from './plugin/imagemin'; 7 | 8 | export default mergeConfig( 9 | { 10 | mode: 'production', 11 | plugins: [ 12 | configCompressPlugin('gzip'), 13 | configVisualizerPlugin(), 14 | configArcoResolverPlugin(), 15 | configImageminPlugin(), 16 | ], 17 | build: { 18 | rollupOptions: { 19 | output: { 20 | manualChunks: { 21 | arco: ['@arco-design/web-vue'], 22 | chart: ['echarts', 'vue-echarts'], 23 | vue: ['vue', 'vue-router', 'pinia', '@vueuse/core', 'vue-i18n'], 24 | }, 25 | }, 26 | }, 27 | chunkSizeWarningLimit: 2000, 28 | }, 29 | }, 30 | baseConfig 31 | ); 32 | -------------------------------------------------------------------------------- /six-go/app/admin/middleware/is_login.go: -------------------------------------------------------------------------------- 1 | package middleware 2 | 3 | import ( 4 | "strings" 5 | 6 | "github.com/gin-gonic/gin" 7 | loginService "six-go/app/admin/service/login" 8 | "six-go/database/models" 9 | "six-go/utils/response" 10 | ) 11 | 12 | func IsLogin(c *gin.Context) { 13 | token := GetHeaderToken(c) 14 | if len(token) == 0 { 15 | response.JsonLogout(c) 16 | return 17 | } 18 | 19 | sessionStorage := loginService.New(token, true).Get() 20 | if !sessionStorage.IsLogin { 21 | response.JsonLogout(c) 22 | return 23 | } 24 | c.Set(SessionUserKey, sessionStorage.Userinfo) 25 | c.Next() 26 | } 27 | 28 | const SessionUserKey = "userinfo" 29 | const HeaderTokenKey = "Six-Token" 30 | 31 | func SessionUser(c *gin.Context) *models.AuthUser { 32 | value, ok := c.Get(SessionUserKey) 33 | if !ok || value == nil { 34 | return nil 35 | } 36 | return value.(*models.AuthUser) 37 | } 38 | 39 | func GetHeaderToken(c *gin.Context) string { 40 | return strings.TrimSpace(c.GetHeader(HeaderTokenKey)) 41 | } 42 | -------------------------------------------------------------------------------- /six-go/database/db/db.go: -------------------------------------------------------------------------------- 1 | package db 2 | 3 | import ( 4 | "log" 5 | 6 | "gorm.io/driver/mysql" 7 | "gorm.io/gorm" 8 | "gorm.io/gorm/logger" 9 | "six-go/config" 10 | ) 11 | 12 | var db *gorm.DB 13 | 14 | func DB() *gorm.DB { 15 | return connect() 16 | } 17 | 18 | func Reconnect() { 19 | connect(true) 20 | } 21 | 22 | func connect(reconnect ...bool) *gorm.DB { 23 | if len(reconnect) == 0 && db != nil { 24 | return db 25 | } 26 | mysqlDriver := mysql.New(mysql.Config{ 27 | DSN: config.DB().DSN(), 28 | DefaultStringSize: 255, 29 | }) 30 | var err error 31 | db, err = gorm.Open(mysqlDriver, &gorm.Config{ 32 | Logger: logger.Default.LogMode(config.DB().LogLevel()), 33 | }) 34 | if err != nil { 35 | log.Println(err) 36 | return nil 37 | } 38 | 39 | if sqlDB, e := db.DB(); e == nil { 40 | sqlDB.SetMaxOpenConns(config.DB().MaxOpenConns()) 41 | sqlDB.SetMaxIdleConns(config.DB().MaxIdleConns()) 42 | sqlDB.SetConnMaxLifetime(config.DB().ConnMaxLifetime()) 43 | } 44 | return db 45 | } 46 | -------------------------------------------------------------------------------- /six-arco/src/utils/index.ts: -------------------------------------------------------------------------------- 1 | type TargetContext = '_self' | '_parent' | '_blank' | '_top'; 2 | 3 | export const openWindow = ( 4 | url: string, 5 | opts?: { target?: TargetContext; [key: string]: any } 6 | ) => { 7 | const { target = '_blank', ...others } = opts || {}; 8 | window.open( 9 | url, 10 | target, 11 | Object.entries(others) 12 | .reduce((preValue: string[], curValue) => { 13 | const [key, value] = curValue; 14 | return [...preValue, `${key}=${value}`]; 15 | }, []) 16 | .join(',') 17 | ); 18 | }; 19 | 20 | export const regexUrl = new RegExp( 21 | '^(?!mailto:)(?:(?:http|https|ftp)://)(?:\\S+(?::\\S*)?@)?(?:(?:(?:[1-9]\\d?|1\\d\\d|2[01]\\d|22[0-3])(?:\\.(?:1?\\d{1,2}|2[0-4]\\d|25[0-5])){2}(?:\\.(?:[0-9]\\d?|1\\d\\d|2[0-4]\\d|25[0-4]))|(?:(?:[a-z\\u00a1-\\uffff0-9]+-?)*[a-z\\u00a1-\\uffff0-9]+)(?:\\.(?:[a-z\\u00a1-\\uffff0-9]+-?)*[a-z\\u00a1-\\uffff0-9]+)*(?:\\.(?:[a-z\\u00a1-\\uffff]{2,})))|localhost)(?::\\d{2,5})?(?:(/|\\?|#)[^\\s]*)?$', 22 | 'i' 23 | ); 24 | 25 | export default null; 26 | -------------------------------------------------------------------------------- /six-arco/src/router/index.ts: -------------------------------------------------------------------------------- 1 | import {createRouter, createWebHashHistory, createWebHistory} from 'vue-router'; 2 | import NProgress from 'nprogress'; // progress bar 3 | import 'nprogress/nprogress.css'; 4 | 5 | import { appRoutes } from './routes'; 6 | import { REDIRECT_MAIN, NOT_FOUND_ROUTE } from './routes/base'; 7 | import createRouteGuard from './guard'; 8 | 9 | NProgress.configure({ showSpinner: false }); // NProgress Configuration 10 | 11 | const router = createRouter({ 12 | // history: createWebHistory(), 13 | history: createWebHashHistory(), 14 | routes: [ 15 | { 16 | path: '/', 17 | redirect: 'login', 18 | }, 19 | { 20 | path: '/login', 21 | name: 'login', 22 | component: () => import('@/views/login/index.vue'), 23 | meta: { 24 | requiresAuth: false, 25 | }, 26 | }, 27 | ...appRoutes, 28 | REDIRECT_MAIN, 29 | NOT_FOUND_ROUTE, 30 | ], 31 | scrollBehavior() { 32 | return { top: 0 }; 33 | }, 34 | }); 35 | 36 | createRouteGuard(router); 37 | 38 | export default router; 39 | -------------------------------------------------------------------------------- /six-arco/src/hooks/chart-option.ts: -------------------------------------------------------------------------------- 1 | import { computed } from 'vue'; 2 | import { EChartsOption } from 'echarts'; 3 | import { useAppStore } from '@/store'; 4 | 5 | // for code hints 6 | // import { SeriesOption } from 'echarts'; 7 | // Because there are so many configuration items, this provides a relatively convenient code hint. 8 | // When using vue, pay attention to the reactive issues. It is necessary to ensure that corresponding functions can be triggered, TypeScript does not report errors, and code writing is convenient. 9 | interface optionsFn { 10 | (isDark: boolean): EChartsOption; 11 | } 12 | 13 | export default function useChartOption(sourceOption: optionsFn) { 14 | const appStore = useAppStore(); 15 | const isDark = computed(() => { 16 | return appStore.theme === 'dark'; 17 | }); 18 | // echarts support https://echarts.apache.org/zh/theme-builder.html 19 | // It's not used here 20 | // TODO echarts themes 21 | const chartOption = computed(() => { 22 | return sourceOption(isDark.value); 23 | }); 24 | return { 25 | chartOption, 26 | }; 27 | } 28 | -------------------------------------------------------------------------------- /six-go/app/admin/route/enter.go: -------------------------------------------------------------------------------- 1 | package adminRoute 2 | 3 | import ( 4 | "reflect" 5 | 6 | "github.com/gin-gonic/gin" 7 | "six-go/app/admin/middleware" 8 | ) 9 | 10 | // LogMode 不记录Log 11 | //const LogMode = middleware.LogModeClosed 12 | 13 | // LogMode 全量记录 几乎完全记录请求和响应body 14 | const LogMode = middleware.LogModeFull 15 | 16 | // LogMode 简单记录 不记录请求和响应body 17 | //const LogMode = middleware.LogModeSimple 18 | 19 | type Route struct { 20 | auths map[string]string 21 | } 22 | 23 | type SingleRoute struct{} 24 | 25 | var singleRoute SingleRoute 26 | 27 | func Routers(app *gin.RouterGroup) { 28 | var route = Route{} 29 | 30 | singleRoute.AuthUserSingle(app) 31 | 32 | app.Use(middleware.IsLogin) 33 | app.Use(middleware.TenantDI) 34 | 35 | app.Use(middleware.Logs(LogMode)) 36 | 37 | app.Use(middleware.Authorization) 38 | 39 | routeType := reflect.TypeOf(route) 40 | routeTypeValue := reflect.ValueOf(route) 41 | appValue := reflect.ValueOf(app) 42 | for i := 0; i < routeType.NumMethod(); i++ { 43 | methodValue := routeTypeValue.Method(i) 44 | methodValue.Call([]reflect.Value{appValue}) 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2025 vainback 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /six-arco/src/locale/zh-CN/settings.ts: -------------------------------------------------------------------------------- 1 | export default { 2 | 'settings.title': '页面配置', 3 | 'settings.themeColor': '主题色', 4 | 'settings.content': '内容区域', 5 | 'settings.search': '搜索', 6 | 'settings.language': '语言', 7 | 'settings.navbar': '导航栏', 8 | 'settings.menuWidth': '菜单宽度 (px)', 9 | 'settings.navbar.theme.toLight': '点击切换为亮色模式', 10 | 'settings.navbar.theme.toDark': '点击切换为暗黑模式', 11 | 'settings.navbar.screen.toFull': '点击切换全屏模式', 12 | 'settings.navbar.screen.toExit': '点击退出全屏模式', 13 | 'settings.navbar.alerts': '消息通知', 14 | 'settings.menu': '菜单栏', 15 | 'settings.topMenu': '顶部菜单栏', 16 | 'settings.tabBar': '多页签', 17 | 'settings.footer': '底部', 18 | 'settings.otherSettings': '其他设置', 19 | 'settings.colorWeak': '色弱模式', 20 | 'settings.alertContent': 21 | '配置之后仅是临时生效,要想真正作用于项目,点击下方的 "复制配置" 按钮,将配置替换到 settings.json 中即可。', 22 | 'settings.copySettings': '复制配置', 23 | 'settings.copySettings.message': 24 | '复制成功,请粘贴到 src/settings.json 文件中', 25 | 'settings.close': '关闭', 26 | 'settings.color.tooltip': 27 | '根据主题颜色生成的 10 个梯度色(将配置复制到项目中,主题色才能对亮色 / 暗黑模式同时生效)', 28 | 'settings.menuFromServer': '菜单来源于后台', 29 | }; 30 | -------------------------------------------------------------------------------- /six-arco/src/views/dashboard/workplace/components/carousel.vue: -------------------------------------------------------------------------------- 1 | 15 | 16 | 25 | -------------------------------------------------------------------------------- /six-go/database/dao/migrate.go: -------------------------------------------------------------------------------- 1 | package dao 2 | 3 | import ( 4 | "log" 5 | "six-go/database/db" 6 | "six-go/database/models" 7 | "six-go/utils" 8 | ) 9 | 10 | func AutoMigrate() { 11 | err := db.DB().AutoMigrate( 12 | &models.AuthRule{}, 13 | &models.AuthRole{}, 14 | &models.AuthRelation{}, 15 | &models.AuthUser{}, 16 | &models.AuthUserLoginStorage{}, 17 | &models.CronJob{}, 18 | &models.Dict{}, 19 | &models.Files{}, 20 | &models.Job{}, 21 | &models.OperateLog{}, 22 | &models.Organization{}, 23 | &models.Tenant{}, 24 | &models.CodeGenerator{}, 25 | //&models.Tests{}, 26 | ) 27 | if err != nil { 28 | log.Println("auto migrate error:", err) 29 | } 30 | 31 | // 写入Root用户 32 | db.DB().FirstOrCreate(&models.AuthUser{ 33 | MODEL: db.MODEL{Id: 1}, 34 | TenantIdentify: models.TenantIdentify{TenantId: 1}, 35 | Username: "admin", 36 | Password: utils.Password.Hash("123456"), 37 | Nickname: "six-root", 38 | Status: 1, 39 | RoleIds: []int64{-20240929}, 40 | IsRoot: true, 41 | OrganizationId: 1, 42 | JobId: 1, 43 | }, "id = ?", 1) 44 | } 45 | -------------------------------------------------------------------------------- /six-arco/src/hooks/responsive.ts: -------------------------------------------------------------------------------- 1 | import { onMounted, onBeforeMount, onBeforeUnmount } from 'vue'; 2 | import { useDebounceFn } from '@vueuse/core'; 3 | import { useAppStore } from '@/store'; 4 | import { addEventListen, removeEventListen } from '@/utils/event'; 5 | 6 | const WIDTH = 992; // https://arco.design/vue/component/grid#responsivevalue 7 | 8 | function queryDevice() { 9 | const rect = document.body.getBoundingClientRect(); 10 | return rect.width - 1 < WIDTH; 11 | } 12 | 13 | export default function useResponsive(immediate?: boolean) { 14 | const appStore = useAppStore(); 15 | function resizeHandler() { 16 | if (!document.hidden) { 17 | const isMobile = queryDevice(); 18 | appStore.toggleDevice(isMobile ? 'mobile' : 'desktop'); 19 | appStore.toggleMenu(isMobile); 20 | } 21 | } 22 | const debounceFn = useDebounceFn(resizeHandler, 100); 23 | onMounted(() => { 24 | if (immediate) debounceFn(); 25 | }); 26 | onBeforeMount(() => { 27 | addEventListen(window, 'resize', debounceFn); 28 | }); 29 | onBeforeUnmount(() => { 30 | removeEventListen(window, 'resize', debounceFn); 31 | }); 32 | } 33 | -------------------------------------------------------------------------------- /six-arco/src/components/chart/index.vue: -------------------------------------------------------------------------------- 1 | 9 | 10 | 46 | 47 | 48 | -------------------------------------------------------------------------------- /six-arco/src/api/system/auth-rule.ts: -------------------------------------------------------------------------------- 1 | import axios from "axios"; 2 | import {RequestParam} from "@/api/base"; 3 | 4 | export interface TreeAuthRule extends AuthRule{ 5 | children?: TreeAuthRule[]; 6 | } 7 | 8 | export interface AuthRule { 9 | id: number; 10 | parent_id: number; 11 | type: string; 12 | component: string; 13 | name: string; 14 | path: string; 15 | authPrefix?: string; // 兼容前端样式 后端不需要的字段 16 | auth: string; 17 | api_route: string; 18 | locale: string; 19 | icon: string; 20 | order: number; 21 | status: number; 22 | create_time?: string; 23 | update_time?: string; 24 | delete_time?: string; 25 | } 26 | 27 | 28 | export const EmptyRule: AuthRule = { 29 | id: 0, 30 | parent_id: 0, 31 | type: '', 32 | component: '', 33 | name: '', 34 | path: '', 35 | auth: '', 36 | api_route: '', 37 | locale: '', 38 | icon: '', 39 | order: 0, 40 | status: 0, 41 | } 42 | 43 | const root = 'admin/auth/rule' 44 | 45 | export function reqAuthRule(action: string, data: RequestParam | null) { 46 | return axios.post(`${root}/${action}`, data || {}); 47 | } 48 | 49 | -------------------------------------------------------------------------------- /six-arco/src/views/dashboard/workplace/components/docs.vue: -------------------------------------------------------------------------------- 1 | 36 | 37 | 43 | -------------------------------------------------------------------------------- /six-arco/src/views/login/locale/en-US.ts: -------------------------------------------------------------------------------- 1 | export default { 2 | 'login.form.title': 'Login to Arco Design Pro', 3 | 'login.form.userName.errMsg': 'Username cannot be empty', 4 | 'login.form.password.errMsg': 'Password cannot be empty', 5 | 'login.form.login.errMsg': 'Login error, refresh and try again', 6 | 'login.form.login.success': 'welcome to use', 7 | 'login.form.userName.placeholder': 'Username: admin', 8 | 'login.form.password.placeholder': 'Password: admin', 9 | 'login.form.rememberPassword': 'Remember password', 10 | 'login.form.forgetPassword': 'Forgot password', 11 | 'login.form.login': 'login', 12 | 'login.form.register': 'register account', 13 | 'login.banner.slogan1': 'Out-of-the-box high-quality template', 14 | 'login.banner.subSlogan1': 15 | 'Rich page templates, covering most typical business scenarios', 16 | 'login.banner.slogan2': 'Built-in solutions to common problems', 17 | 'login.banner.subSlogan2': 18 | 'Internationalization, routing configuration, state management everything', 19 | 'login.banner.slogan3': 'Access visualization enhancement tool AUX', 20 | 'login.banner.subSlogan3': 'Realize flexible block development', 21 | }; 22 | -------------------------------------------------------------------------------- /six-arco/src/router/guard/userLoginInfo.ts: -------------------------------------------------------------------------------- 1 | import type { Router, LocationQueryRaw } from 'vue-router'; 2 | import NProgress from 'nprogress'; // progress bar 3 | 4 | import { useUserStore } from '@/store'; 5 | import { isLogin } from '@/utils/auth'; 6 | 7 | export default function setupUserLoginInfoGuard(router: Router) { 8 | router.beforeEach(async (to, from, next) => { 9 | NProgress.start(); 10 | const userStore = useUserStore(); 11 | if (isLogin()) { 12 | if (userStore.role) { 13 | next(); 14 | } else { 15 | try { 16 | await userStore.info(); 17 | next(); 18 | } catch (error) { 19 | await userStore.logout(); 20 | next({ 21 | name: 'login', 22 | query: { 23 | redirect: to.name, 24 | ...to.query, 25 | } as LocationQueryRaw, 26 | }); 27 | } 28 | } 29 | } else { 30 | if (to.name === 'login') { 31 | next(); 32 | return; 33 | } 34 | next({ 35 | name: 'login', 36 | query: { 37 | redirect: to.name, 38 | ...to.query, 39 | } as LocationQueryRaw, 40 | }); 41 | } 42 | }); 43 | } 44 | -------------------------------------------------------------------------------- /six-arco/src/views/dashboard/workplace/components/recently-visited.vue: -------------------------------------------------------------------------------- 1 | 22 | 23 | 39 | 40 | 45 | -------------------------------------------------------------------------------- /six-go/database/models/fn_get_sons.go: -------------------------------------------------------------------------------- 1 | package models 2 | 3 | import ( 4 | "github.com/spf13/cast" 5 | "gorm.io/gorm" 6 | "six-go/database/db" 7 | ) 8 | 9 | type Son struct { 10 | root []int64 11 | list []map[string]any 12 | } 13 | 14 | func NewSon(id ...int64) *Son { 15 | return &Son{root: id, list: nil} 16 | } 17 | 18 | func (s *Son) GetIds(model db.ModelIof, where ...func(db *gorm.DB) *gorm.DB) []int64 { 19 | if len(s.root) == 0 { 20 | return nil 21 | } 22 | 23 | var list []map[string]any 24 | tx := db.DB().Table(model.TableName()) 25 | if len(where) > 0 { 26 | tx = tx.Scopes(where...) 27 | } 28 | if err := tx.Scan(&list).Error; err != nil { 29 | return nil 30 | } 31 | s.list = list 32 | var sons []int64 33 | for _, v := range s.root { 34 | sons = append(sons, s.parserSons(v)...) 35 | } 36 | return sons 37 | } 38 | 39 | func (s *Son) parserSons(id int64) []int64 { 40 | if len(s.list) == 0 { 41 | return nil 42 | } 43 | var sons []int64 44 | for _, v := range s.list { 45 | vid := cast.ToInt64(v["id"]) 46 | if cast.ToInt64(v["parent_id"]) == id { 47 | if childs := s.parserSons(vid); len(childs) > 0 { 48 | sons = append(sons, childs...) 49 | } 50 | sons = append(sons, vid) 51 | } 52 | } 53 | return sons 54 | } 55 | -------------------------------------------------------------------------------- /six-arco/src/views/dashboard/workplace/components/quick-operation.vue: -------------------------------------------------------------------------------- 1 | 24 | 25 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /six-go/database/models/auth_relation.go: -------------------------------------------------------------------------------- 1 | package models 2 | 3 | import ( 4 | "github.com/vainback/six-util/v3" 5 | "gorm.io/gorm" 6 | "six-go/database/db" 7 | ) 8 | 9 | var TableAuthRelation AuthRelation 10 | 11 | // AuthRelation 角色 - 菜单规则 关联表 12 | type AuthRelation struct { 13 | db.MODEL 14 | TenantIdentify 15 | RoleId int64 `json:"role_id"` 16 | RuleId int64 `json:"rule_id"` 17 | } 18 | 19 | func (data AuthRelation) TableName() string { 20 | return "auth_relation" 21 | } 22 | 23 | func (data AuthRelation) HasTableName(filed string) string { 24 | return six.Strings(data.TableName(), ".", filed).String() 25 | } 26 | 27 | func (data AuthRelation) KeywordFields() []string { 28 | return []string{} 29 | } 30 | 31 | func (data AuthRelation) FilterSqlBuilder() func(db *gorm.DB) *gorm.DB { 32 | return func(db *gorm.DB) *gorm.DB { 33 | if data.Id > 0 { 34 | return db.Where(data.HasTableName("id")+" = ?", data.Id) 35 | } 36 | if data.RoleId != 0 { 37 | db = db.Where(data.HasTableName("role_id")+" = ?", data.RoleId) 38 | } 39 | if data.RuleId != 0 { 40 | db = db.Where(data.HasTableName("rule_id")+" = ?", data.RuleId) 41 | } 42 | 43 | return db.Scopes(data.TenantIdentify.SqlBuilder(data.TableName())) 44 | } 45 | } 46 | 47 | func (data AuthRelation) GetId() int64 { 48 | return data.Id 49 | } 50 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Six-Admin多租户中后台管理系统 2 | 3 | ``` 4 | 采用MIT协议,商业化完全免费且无需保留任何商标,如需采用,感谢您留下宝贵的Star 5 | ``` 6 | 7 | ## 一、预览(演示)地址 8 | 9 | [演示地址](https://dl.sorks.cn/admin) 10 | 11 | [文档地址](http://ddd.sorks.cn:4999/web/#/671910255/189282755) 12 | 13 | ### 已开放功能模块如下 14 | - 权限管理 15 | - 用户管理 16 | - 菜单管理 17 | - 组织架构 18 | - 职位管理 19 | - 日志记录 20 | - 字典管理 21 | - 文件管理 【本地,COS, OSS, 七牛】 22 | - 定时任务 23 | - 代码生成 24 | 25 | ## 二、技术栈 26 | 27 | ### 版本要求 28 | 29 | ``` go 30 | 31 | Go Version >= 1.23 32 | 至少保证 Go 1.23 以上 需开启环境变量 GOEXPERIMENT=aliastypeparams 33 | 或更新至 Go 1.24 以上 34 | 设置 go mod 代理为:GOPROXY=https://goproxy.cn,direct 35 | 36 | node version >= 18.0 37 | npm建议安装nrm包 随时切换代理 38 | 39 | 40 | 已对 COS OSS 七牛云 进行简单适配 41 | ``` 42 | 43 | ### 后端技术栈 44 | [1. Gin - Web 框架](https://gin-gonic.com/zh-cn/docs/) 45 | 46 | [2. Gorm - 数据库操作ORM框架](https://gorm.io/zh_CN/docs/) 47 | 48 | [3. ozzo-validation - 验证器](https://github.com/go-ozzo/ozzo-validation) 49 | 50 | [4. go-redis - Redis链接库](https://github.com/redis/go-redis/v9) 51 | 52 | [5. robfig-cron - 定时任务](https://github.com/robfig/cron/v3) 53 | 54 | [6. viper - 配置文件解析库](https://github.com/spf13/viper) 55 | 56 | [7. cast - 类型转换库](https://github.com/spf13/cast) 57 | 58 | ### 前端UI框架 59 | [Arco Design Pro Vue](https://arco.design/vue/docs/pro/start) 60 | 61 | 62 | ``` 63 | 缺点:虽然Arco已经做了国际化,由于个人原因,SixAdmin未对国际化做兼容 64 | ``` 65 | 66 | 67 | -------------------------------------------------------------------------------- /six-arco/src/assets/logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /six-arco/config/vite.config.base.ts: -------------------------------------------------------------------------------- 1 | import { resolve } from 'path'; 2 | import { defineConfig } from 'vite'; 3 | import vue from '@vitejs/plugin-vue'; 4 | import vueJsx from '@vitejs/plugin-vue-jsx'; 5 | import svgLoader from 'vite-svg-loader'; 6 | import configArcoStyleImportPlugin from './plugin/arcoStyleImport'; 7 | 8 | export default defineConfig({ 9 | plugins: [ 10 | vue(), 11 | vueJsx(), 12 | svgLoader({ svgoConfig: {} }), 13 | configArcoStyleImportPlugin(), 14 | ], 15 | resolve: { 16 | alias: [ 17 | { 18 | find: '@', 19 | replacement: resolve(__dirname, '../src'), 20 | }, 21 | { 22 | find: 'assets', 23 | replacement: resolve(__dirname, '../src/assets'), 24 | }, 25 | { 26 | find: 'vue-i18n', 27 | replacement: 'vue-i18n/dist/vue-i18n.cjs.js', // Resolve the i18n warning issue 28 | }, 29 | { 30 | find: 'vue', 31 | replacement: 'vue/dist/vue.esm-bundler.js', // compile template 32 | }, 33 | ], 34 | extensions: ['.ts', '.js'], 35 | }, 36 | define: { 37 | 'process.env': {}, 38 | }, 39 | css: { 40 | preprocessorOptions: { 41 | less: { 42 | modifyVars: { 43 | hack: `true; @import (reference) "${resolve( 44 | 'src/assets/style/breakpoint.less' 45 | )}";`, 46 | }, 47 | javascriptEnabled: true, 48 | }, 49 | }, 50 | }, 51 | }); 52 | -------------------------------------------------------------------------------- /six-go/static/generator_tpl/server/model.go.tpl: -------------------------------------------------------------------------------- 1 | package models 2 | 3 | import ( 4 | "errors" 5 | validation "github.com/go-ozzo/ozzo-validation" 6 | "github.com/vainback/six-util/v3" 7 | "gorm.io/gorm" 8 | "six-go/database/db" 9 | ) 10 | 11 | var Table 12 | 13 | type struct { 14 | db.MODEL 15 | 16 | 17 | 18 | } 19 | 20 | func (data ) TableName() string { 21 | return "" 22 | } 23 | 24 | func (data ) HasTableName(filed string) string { 25 | return six.Strings(data.TableName(), ".", filed).String() 26 | } 27 | 28 | func (data ) KeywordFields() []string { 29 | return 30 | } 31 | 32 | func (data ) FilterSqlBuilder() func(db *gorm.DB) *gorm.DB { 33 | return func(db *gorm.DB) *gorm.DB { 34 | return db 35 | } 36 | } 37 | 38 | func (data ) GetId() int64 { 39 | return data.Id 40 | } 41 | 42 | func (data ) Valid(idRequired ...bool) error { 43 | if len(idRequired) > 0 && idRequired[0] { 44 | if data.Id <= 0 { 45 | return errors.New("id is required") 46 | } 47 | } 48 | 49 | return 50 | } 51 | 52 | 53 | func (data ) HasChildren() (childNums int64, err error) { 54 | err = db.DB().Model(&{}).Where("parent_id = ?", data.Id).Count(&childNums).Error 55 | return 56 | } 57 | -------------------------------------------------------------------------------- /six-arco/src/locale/en-US/settings.ts: -------------------------------------------------------------------------------- 1 | export default { 2 | 'settings.title': 'Settings', 3 | 'settings.themeColor': 'Theme Color', 4 | 'settings.content': 'Content Setting', 5 | 'settings.search': 'Search', 6 | 'settings.language': 'Language', 7 | 'settings.navbar': 'Navbar', 8 | 'settings.menuWidth': 'Menu Width (px)', 9 | 'settings.navbar.theme.toLight': 'Click to use light mode', 10 | 'settings.navbar.theme.toDark': 'Click to use dark mode', 11 | 'settings.navbar.screen.toFull': 'Click to switch to full screen mode', 12 | 'settings.navbar.screen.toExit': 'Click to exit the full screen mode', 13 | 'settings.navbar.alerts': 'alerts', 14 | 'settings.menu': 'Menu', 15 | 'settings.topMenu': 'Top Menu', 16 | 'settings.tabBar': 'Tab Bar', 17 | 'settings.footer': 'Footer', 18 | 'settings.otherSettings': 'Other Settings', 19 | 'settings.colorWeak': 'Color Weak', 20 | 'settings.alertContent': 21 | 'After the configuration is only temporarily effective, if you want to really affect the project, click the "Copy Settings" button below and replace the configuration in settings.json.', 22 | 'settings.copySettings': 'Copy Settings', 23 | 'settings.copySettings.message': 24 | 'Copy succeeded, please paste to file src/settings.json.', 25 | 'settings.close': 'Close', 26 | 'settings.color.tooltip': 27 | '10 gradient colors generated according to the theme color', 28 | 'settings.menuFromServer': 'Menu From Server', 29 | }; 30 | -------------------------------------------------------------------------------- /six-go/utils/request/request.go: -------------------------------------------------------------------------------- 1 | package request 2 | 3 | import ( 4 | "bytes" 5 | "encoding/json" 6 | jsoniter "github.com/json-iterator/go" 7 | "io" 8 | "net/http" 9 | ) 10 | 11 | func Get(uri string, values *URLParam, result any) error { 12 | resp, err := http.Get(uri + "?" + values.Builder()) 13 | if err != nil { 14 | return err 15 | } 16 | defer func() { 17 | _ = resp.Body.Close() 18 | }() 19 | 20 | resultBytes, err := io.ReadAll(resp.Body) 21 | if err != nil { 22 | return err 23 | } 24 | 25 | return jsoniter.Unmarshal(resultBytes, result) 26 | } 27 | 28 | func Post(uri string, data any, result any) error { 29 | dataBytes, err := json.Marshal(data) 30 | if err != nil { 31 | return err 32 | } 33 | 34 | resp, err := http.Post(uri, "application/json", bytes.NewReader(dataBytes)) 35 | if err != nil { 36 | return err 37 | } 38 | defer func() { 39 | _ = resp.Body.Close() 40 | }() 41 | 42 | resultBytes, err := io.ReadAll(resp.Body) 43 | if err != nil { 44 | return err 45 | } 46 | 47 | return jsoniter.Unmarshal(resultBytes, result) 48 | } 49 | 50 | func PostForm(uri string, data *URLParam, result any) error { 51 | resp, err := http.PostForm(uri, data.values) 52 | if err != nil { 53 | return err 54 | } 55 | defer func() { 56 | _ = resp.Body.Close() 57 | }() 58 | resultBytes, err := io.ReadAll(resp.Body) 59 | if err != nil { 60 | return err 61 | } 62 | return jsoniter.Unmarshal(resultBytes, result) 63 | } 64 | -------------------------------------------------------------------------------- /six-go/app/admin/middleware/tenant_di.go: -------------------------------------------------------------------------------- 1 | package middleware 2 | 3 | import ( 4 | "bytes" 5 | jsoniter "github.com/json-iterator/go" 6 | "io" 7 | 8 | "github.com/gin-gonic/gin" 9 | "github.com/spf13/cast" 10 | "six-go/utils/response" 11 | ) 12 | 13 | // TenantDI 对request body params 校验/注入 session user tenant_id 参数 14 | func TenantDI(c *gin.Context) { 15 | requestBodyBytes, err := io.ReadAll(c.Request.Body) 16 | if err != nil { 17 | c.Abort() 18 | response.JsonError(c, response.ErrorParamsParser, err) 19 | return 20 | } 21 | var requestBody map[string]any 22 | if err = jsoniter.Unmarshal(requestBodyBytes, &requestBody); err != nil { 23 | c.Abort() 24 | response.JsonError(c, response.ErrorParamsParser, err) 25 | return 26 | } 27 | 28 | sessionUser := SessionUser(c) 29 | 30 | requestBodyModel, ok := requestBody["model"] 31 | if ok { 32 | m := cast.ToStringMap(requestBodyModel) 33 | if tenantId, tok := m["tenant_id"]; tok { 34 | if cast.ToInt64(m["id"]) > 0 && cast.ToInt64(tenantId) != sessionUser.TenantId { 35 | c.Abort() 36 | response.JsonError(c, "操作被禁止", nil) 37 | return 38 | } 39 | } 40 | m["tenant_id"] = sessionUser.TenantId 41 | requestBody["model"] = m 42 | } 43 | 44 | bodyBytes, err := jsoniter.Marshal(requestBody) 45 | if err != nil { 46 | c.Abort() 47 | response.JsonError(c, "参数序列化失败", err) 48 | return 49 | } 50 | c.Request.Body = io.NopCloser(bytes.NewBuffer(bodyBytes)) 51 | 52 | c.Next() 53 | } 54 | -------------------------------------------------------------------------------- /six-go/extra/crons/cron.go: -------------------------------------------------------------------------------- 1 | package crons 2 | 3 | import ( 4 | "fmt" 5 | "github.com/robfig/cron/v3" 6 | "log" 7 | "six-go/extra/xredis" 8 | "sync" 9 | ) 10 | 11 | type Cron struct { 12 | container sync.Map // 定时任务池 13 | cron *cron.Cron 14 | } 15 | 16 | type job struct { 17 | id cron.EntryID 18 | name string 19 | spec string 20 | job cron.Job 21 | } 22 | 23 | var clock *Cron 24 | 25 | func NewCron() *Cron { 26 | if clock == nil { 27 | clock = &Cron{ 28 | cron: cron.New(cron.WithSeconds()), 29 | } 30 | } 31 | return clock 32 | } 33 | 34 | func (c *Cron) AddJob(ormId int64, spec string, cmd cron.Job) error { 35 | if err := c.RemoveJob(ormId); err != nil { 36 | return err 37 | } 38 | 39 | id, err := c.cron.AddJob(spec, cmd) 40 | if err != nil { 41 | return err 42 | } 43 | return xredis.Set(c.storeKey(ormId), int64(id)) 44 | } 45 | 46 | func (c *Cron) RemoveJob(ormId int64) error { 47 | id := xredis.GetInt(c.storeKey(ormId)) 48 | if id > 0 { 49 | if err := xredis.Del(c.storeKey(ormId)); err != nil { 50 | log.Println("remove job err:", err) 51 | } 52 | c.cron.Remove(cron.EntryID(id)) 53 | c.Restart() 54 | } 55 | return nil 56 | } 57 | 58 | func (c *Cron) Start() { 59 | c.cron.Start() 60 | } 61 | 62 | func (c *Cron) Stop() { 63 | c.cron.Stop() 64 | } 65 | 66 | func (c *Cron) Restart() { 67 | c.Stop() 68 | c.Start() 69 | } 70 | 71 | func (c *Cron) storeKey(ormId int64) string { 72 | return fmt.Sprintf("six-admin:cron:x-%d", ormId) 73 | } 74 | -------------------------------------------------------------------------------- /six-arco/src/views/dashboard/workplace/locale/zh-CN.ts: -------------------------------------------------------------------------------- 1 | export default { 2 | 'menu.dashboard.workplace': '工作台', 3 | 'workplace.welcome': '欢迎回来!', 4 | 'workplace.balance': '余额(元)', 5 | 'workplace.order.pending': '待支付', 6 | 'workplace.order.pendingRenewal': '待续费订单', 7 | 'workplace.onlineContent': '线上总内容', 8 | 'workplace.putIn': '投放中内容', 9 | 'workplace.newDay': '日新增评论', 10 | 'workplace.newFromYesterday': '较昨日新增', 11 | 'workplace.minute': '分钟', 12 | 'workplace.docs': '帮助文档', 13 | 'workplace.docs.productOverview': '产品概要', 14 | 'workplace.docs.userGuide': '使用指南', 15 | 'workplace.docs.workflow': '接入流程', 16 | 'workplace.docs.interfaceDocs': '接口文档', 17 | 'workplace.contentManagement': '内容管理', 18 | 'workplace.contentStatistical': '内容分析', 19 | 'workplace.advanced': '高级管理', 20 | 'workplace.onlinePromotion': '线上推广', 21 | 'workplace.contentPutIn': '内容投放', 22 | 'workplace.announcement': '公告', 23 | 'workplace.recently.visited': '最近访问', 24 | 'workplace.record.nodata': '暂无数据', 25 | 'workplace.quick.operation': '快捷操作', 26 | 'workplace.quickOperation.setup': '管理', 27 | 'workplace.allProject': '所有项目', 28 | 'workplace.loadMore': '加载更多', 29 | 'workplace.viewMore': '查看更多', 30 | 'workplace.contentData': '内容数据', 31 | 'workplace.popularContent': '线上热门内容', 32 | 'workplace.popularContent.text': '文本', 33 | 'workplace.popularContent.image': '图片', 34 | 'workplace.popularContent.video': '视频', 35 | 'workplace.categoriesPercent': '内容类型占比', 36 | 'workplace.pecs': '个', 37 | }; 38 | -------------------------------------------------------------------------------- /six-go/cmd/gin/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "log" 5 | "net/http" 6 | "six-go/extra/crons" 7 | 8 | "github.com/gin-gonic/gin" 9 | adminRoute "six-go/app/admin/route" 10 | "six-go/config" 11 | "six-go/database/dao" 12 | "six-go/database/db" 13 | ) 14 | 15 | func init() { 16 | go func() { 17 | if config.DB().AutoMigrate() { 18 | dao.AutoMigrate() 19 | } 20 | 21 | // 自动拉取数据库定时任务 自动 添加到定时服务中 22 | crons.Init() 23 | 24 | select { 25 | case <-config.Notices: 26 | db.Reconnect() 27 | } 28 | }() 29 | 30 | } 31 | 32 | func main() { 33 | if config.APP().Debug() { 34 | gin.SetMode(gin.DebugMode) 35 | } 36 | app := gin.Default() 37 | app.Use(CORS) 38 | 39 | app.StaticFS("uploads", http.Dir("./uploads")) 40 | 41 | app.LoadHTMLFiles("dist/index.html") 42 | app.StaticFS("assets", http.Dir("./dist/assets")) 43 | app.GET("/admin/", func(c *gin.Context) { 44 | c.HTML(http.StatusOK, "index.html", nil) 45 | }) 46 | 47 | adminRoute.Routers(app.Group("/admin")) 48 | 49 | log.Fatalln(app.Run(config.APP().ListenPort())) 50 | } 51 | 52 | func CORS(c *gin.Context) { 53 | c.Header("Access-Control-Allow-Origin", "*") 54 | c.Header("Access-Control-Allow-Methods", "GET,POST,PUT,DELETE,OPTIONS") 55 | c.Header("Access-Control-Allow-Headers", "*") 56 | c.Header("Access-Control-Expose-Headers", "*") 57 | c.Header("Access-Control-Allow-Credentials", "true") 58 | if c.Request.Method == "OPTIONS" { 59 | c.AbortWithStatus(http.StatusNoContent) 60 | return 61 | } 62 | c.Next() 63 | } 64 | -------------------------------------------------------------------------------- /six-go/app/admin/entity/auth_user_join.go: -------------------------------------------------------------------------------- 1 | package entity 2 | 3 | import ( 4 | "fmt" 5 | "github.com/vainback/six-util/v3" 6 | "strings" 7 | 8 | "gorm.io/gorm" 9 | "six-go/database/models" 10 | ) 11 | 12 | type AuthUserJoinJob struct { 13 | models.AuthUser 14 | Job models.Job `json:"job" gorm:"embedded;embeddedPrefix:job_"` 15 | } 16 | 17 | func (e AuthUserJoinJob) TableName() string { 18 | return e.AuthUser.TableName() 19 | } 20 | 21 | func (e AuthUserJoinJob) KeywordFields() []string { 22 | return append(e.AuthUser.KeywordFields(), e.Job.KeywordFields()...) 23 | } 24 | 25 | func (e AuthUserJoinJob) FilterSqlBuilder() func(db *gorm.DB) *gorm.DB { 26 | return func(db *gorm.DB) *gorm.DB { 27 | return db.Scopes(e.AuthUser.FilterSqlBuilder()).Scopes(e.Job.FilterSqlBuilder()) 28 | } 29 | } 30 | 31 | func (e AuthUserJoinJob) Fields() string { 32 | var fields = []string{ 33 | six.Strings(e.AuthUser.TableName(), ".*").String(), 34 | six.Strings(e.Job.TableName(), ".name as job_name").String(), 35 | } 36 | return strings.Join(fields, ",") 37 | } 38 | 39 | func (e AuthUserJoinJob) LeftJoin() func(db *gorm.DB) *gorm.DB { 40 | return func(db *gorm.DB) *gorm.DB { 41 | return db.Table(e.AuthUser.TableName()). 42 | Joins(fmt.Sprintf("LEFT JOIN %s ON %s.id = %s.job_id", e.Job.TableName(), e.Job.TableName(), e.AuthUser.TableName())) 43 | } 44 | } 45 | 46 | func (e AuthUserJoinJob) Select() func(db *gorm.DB) *gorm.DB { 47 | return func(db *gorm.DB) *gorm.DB { 48 | return db.Select(e.Fields()) 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /six-arco/src/api/codegen/tests.ts: -------------------------------------------------------------------------------- 1 | import {RequestParam} from "@/api/base"; 2 | import axios from "axios"; 3 | 4 | export interface Tests { 5 | id: number; 6 | create_time?: string; 7 | update_time?: string; 8 | delete_time?: string; 9 | te_str: string; 10 | te_int: number; 11 | te_bigint: number; 12 | te_float: number; 13 | te_decimal: number; 14 | te_select: string; 15 | te_select_many: string[]; 16 | te_radio: string; 17 | te_checkbox: string[]; 18 | te_switch: boolean; 19 | te_timepicker: string | null; 20 | te_datepicker: string | null; 21 | te_datetimepicker: string | null; 22 | te_image_one: string[]; 23 | te_image_many: string[]; 24 | te_video: string[]; 25 | te_file: string[]; 26 | te_text: string; 27 | te_editor: string; 28 | } 29 | 30 | export const EmptyTests: Tests = { 31 | id: 0, 32 | te_str: '', 33 | te_int: 0, 34 | te_bigint: 0, 35 | te_float: 0, 36 | te_decimal: 0, 37 | te_select: '', 38 | te_select_many: [], 39 | te_radio: '', 40 | te_checkbox: [], 41 | te_switch: false, 42 | te_timepicker: null, 43 | te_datepicker: null, 44 | te_datetimepicker: null, 45 | te_image_one: [], 46 | te_image_many: [], 47 | te_video: [], 48 | te_file: [], 49 | te_text: '', 50 | te_editor: '', 51 | } 52 | 53 | const root = 'admin/tests' 54 | export function reqTests(action: string, data: RequestParam | null) { 55 | return axios.post(`${root}/${action}`, data ||{}); 56 | } -------------------------------------------------------------------------------- /six-go/app/admin/service/authrule/menu.go: -------------------------------------------------------------------------------- 1 | package authruleService 2 | 3 | import "six-go/database/models" 4 | 5 | type MenuMeta struct { 6 | Title string `json:"locale,omitempty"` 7 | Icon string `json:"icon,omitempty"` 8 | Roles []string `json:"roles"` 9 | KeepAlive *bool `json:"ignoreCache,omitempty"` 10 | Order int `json:"order"` 11 | RequiresAuth bool `json:"requiresAuth"` 12 | } 13 | 14 | type Menu struct { 15 | Key int64 `json:"key"` 16 | Title string `json:"title"` 17 | Path string `json:"path,omitempty"` 18 | Name string `json:"name,omitempty"` 19 | Redirect string `json:"redirect,omitempty"` 20 | Component string `json:"component,omitempty"` 21 | Meta MenuMeta `json:"meta"` 22 | Children []Menu `json:"children,omitempty"` 23 | } 24 | 25 | func ParserMenu(list []models.AuthRuleForMenu, pid int64) []Menu { 26 | var tree []Menu 27 | for _, v := range list { 28 | val := Menu{ 29 | Key: v.Id, 30 | Title: v.Locale, 31 | Path: v.Path, 32 | Name: v.Name, 33 | Component: v.Component, 34 | Meta: MenuMeta{ 35 | Title: v.Locale, 36 | Icon: v.Icon, 37 | Roles: v.Roles, 38 | Order: v.Order, 39 | RequiresAuth: true, 40 | }, 41 | } 42 | 43 | if v.ParentId == pid { 44 | child := ParserMenu(list, v.Id) 45 | if len(child) > 0 { 46 | val.Children = child 47 | } 48 | tree = append(tree, val) 49 | } 50 | } 51 | return tree 52 | } 53 | -------------------------------------------------------------------------------- /six-arco/src/utils/is.ts: -------------------------------------------------------------------------------- 1 | const opt = Object.prototype.toString; 2 | 3 | export function isArray(obj: any): obj is any[] { 4 | return opt.call(obj) === '[object Array]'; 5 | } 6 | 7 | export function isObject(obj: any): obj is { [key: string]: any } { 8 | return opt.call(obj) === '[object Object]'; 9 | } 10 | 11 | export function isString(obj: any): obj is string { 12 | return opt.call(obj) === '[object String]'; 13 | } 14 | 15 | export function isNumber(obj: any): obj is number { 16 | return opt.call(obj) === '[object Number]' && obj === obj; // eslint-disable-line 17 | } 18 | 19 | export function isRegExp(obj: any) { 20 | return opt.call(obj) === '[object RegExp]'; 21 | } 22 | 23 | export function isFile(obj: any): obj is File { 24 | return opt.call(obj) === '[object File]'; 25 | } 26 | 27 | export function isBlob(obj: any): obj is Blob { 28 | return opt.call(obj) === '[object Blob]'; 29 | } 30 | 31 | export function isUndefined(obj: any): obj is undefined { 32 | return obj === undefined; 33 | } 34 | 35 | export function isNull(obj: any): obj is null { 36 | return obj === null; 37 | } 38 | 39 | export function isFunction(obj: any): obj is (...args: any[]) => any { 40 | return typeof obj === 'function'; 41 | } 42 | 43 | export function isEmptyObject(obj: any): boolean { 44 | return isObject(obj) && Object.keys(obj).length === 0; 45 | } 46 | 47 | export function isExist(obj: any): boolean { 48 | return obj || obj === 0; 49 | } 50 | 51 | export function isWindow(el: any): el is Window { 52 | return el === window; 53 | } 54 | -------------------------------------------------------------------------------- /six-go/database/models/files.go: -------------------------------------------------------------------------------- 1 | package models 2 | 3 | import ( 4 | "errors" 5 | "github.com/vainback/six-util/v3" 6 | "gorm.io/gorm" 7 | "six-go/database/db" 8 | ) 9 | 10 | var TableFiles Files 11 | 12 | type Files struct { 13 | db.MODEL 14 | db.SoftDelete 15 | TenantIdentify 16 | Mime string `json:"mime" gorm:"index"` // 1 图片 2 视频 3 音频 4 其他文件 17 | Type string `json:"type" gorm:"index"` // 存储方式 local | remote 本地|远端 18 | Url string `json:"url"` // 文件url 19 | } 20 | 21 | func (data Files) TableName() string { 22 | return "files" 23 | } 24 | 25 | func (data Files) HasTableName(filed string) string { 26 | return six.Strings(data.TableName(), ".", filed).String() 27 | } 28 | 29 | func (data Files) KeywordFields() []string { 30 | return []string{} 31 | } 32 | 33 | func (data Files) FilterSqlBuilder() func(db *gorm.DB) *gorm.DB { 34 | return func(db *gorm.DB) *gorm.DB { 35 | if data.Id > 0 { 36 | return db.Where(data.HasTableName("id")+" = ?", data.Id) 37 | } 38 | 39 | if data.Mime != "" { 40 | return db.Where(data.HasTableName("id")+" = ?", data.Mime) 41 | } 42 | 43 | if data.Type != "" { 44 | return db.Where(data.HasTableName("id")+" = ?", data.Type) 45 | } 46 | 47 | return db.Scopes(data.TenantIdentify.SqlBuilder(data.TableName())) 48 | } 49 | } 50 | 51 | func (data Files) GetId() int64 { 52 | return data.Id 53 | } 54 | 55 | func (data Files) Valid(idRequired ...bool) error { 56 | if len(idRequired) > 0 && idRequired[0] { 57 | if data.Id <= 0 { 58 | return errors.New("id is required") 59 | } 60 | } 61 | return nil 62 | } 63 | -------------------------------------------------------------------------------- /six-go/app/admin/entity/auth_log_join_user.go: -------------------------------------------------------------------------------- 1 | package entity 2 | 3 | import ( 4 | "fmt" 5 | "github.com/vainback/six-util/v3" 6 | "strings" 7 | 8 | "gorm.io/gorm" 9 | "six-go/database/models" 10 | ) 11 | 12 | type LogJoinUser struct { 13 | models.OperateLog 14 | User models.AuthUser `json:"user" gorm:"embedded;embeddedPrefix:user_"` 15 | } 16 | 17 | func (e LogJoinUser) TableName() string { 18 | return e.OperateLog.TableName() 19 | } 20 | 21 | func (e LogJoinUser) KeywordFields() []string { 22 | return append(e.OperateLog.KeywordFields(), e.User.KeywordFields()...) 23 | } 24 | 25 | func (e LogJoinUser) FilterSqlBuilder() func(db *gorm.DB) *gorm.DB { 26 | return func(db *gorm.DB) *gorm.DB { 27 | return db.Scopes(e.OperateLog.FilterSqlBuilder()).Scopes(e.User.FilterSqlBuilder()) 28 | } 29 | } 30 | 31 | func (e LogJoinUser) Fields() string { 32 | var fields = []string{ 33 | six.Strings(e.OperateLog.TableName(), ".*").String(), 34 | six.Strings(e.User.TableName(), ".username as user_username").String(), 35 | six.Strings(e.User.TableName(), ".nickname as user_nickname").String(), 36 | } 37 | return strings.Join(fields, ",") 38 | } 39 | 40 | func (e LogJoinUser) LeftJoin() func(db *gorm.DB) *gorm.DB { 41 | return func(db *gorm.DB) *gorm.DB { 42 | return db.Table(e.OperateLog.TableName()). 43 | Joins(fmt.Sprintf("LEFT JOIN %s ON %s.id = %s.uid", e.User.TableName(), e.User.TableName(), e.OperateLog.TableName())) 44 | } 45 | } 46 | 47 | func (e LogJoinUser) Select() func(db *gorm.DB) *gorm.DB { 48 | return func(db *gorm.DB) *gorm.DB { 49 | return db.Select(e.Fields()) 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /six-arco/src/router/routes/modules/basic.ts: -------------------------------------------------------------------------------- 1 | import { DEFAULT_LAYOUT } from '../base'; 2 | import { AppRouteRecordRaw } from '../types'; 3 | 4 | const BASIC: AppRouteRecordRaw = { 5 | path: '/basic', 6 | name: 'Basic', 7 | component: DEFAULT_LAYOUT, 8 | meta: { 9 | locale: '基础设置', 10 | requiresAuth: true, 11 | icon: 'icon-desktop', 12 | order: 98, 13 | }, 14 | children: [ 15 | { 16 | path: 'dict', 17 | name: 'Dict', 18 | component: () => import('@/views/basic/Dict/index.vue'), 19 | meta: { 20 | locale: '字典管理', 21 | requiresAuth: true, 22 | }, 23 | }, 24 | { 25 | path: 'files', 26 | name: 'Files', 27 | component: () => import('@/views/basic/Files/index.vue'), 28 | meta: { 29 | locale: '文件管理', 30 | requiresAuth: true, 31 | }, 32 | }, 33 | { 34 | path: 'cron', 35 | name: 'Cron', 36 | component: () => import('@/views/basic/Cron/index.vue'), 37 | meta: { 38 | locale: '定时任务', 39 | requiresAuth: true, 40 | }, 41 | }, 42 | { 43 | path: 'code', 44 | name: 'Code', 45 | component: () => import('@/views/basic/Codegen/index.vue'), 46 | meta: { 47 | locale: '代码生成', 48 | requiresAuth: true, 49 | }, 50 | }, 51 | ], 52 | }; 53 | 54 | export default BASIC; 55 | -------------------------------------------------------------------------------- /six-arco/src/api/system/user.ts: -------------------------------------------------------------------------------- 1 | import axios from "axios"; 2 | import user from "@/store/modules/user"; 3 | import {Tenant} from "@/api/system/tenant"; 4 | import {RequestParam} from "@/api/base"; 5 | import {AuthRule} from "@/api/system/auth-rule"; 6 | 7 | export interface LoginData { 8 | tenant_id: number; 9 | username: string; 10 | password: string; 11 | } 12 | 13 | export interface LoginRes { 14 | token: string; 15 | userinfo: Userinfo; 16 | } 17 | 18 | export interface Userinfo { 19 | id: number; 20 | username: string; 21 | nickname: string; 22 | password: string; 23 | status: number; 24 | role_ids: number[] | null; 25 | is_root: boolean | null; 26 | organization_id: number | null; 27 | job_id: number | null; 28 | tenant_id?: number; 29 | create_time?: string; 30 | update_time?: string; 31 | delete_time?: string; 32 | } 33 | 34 | export const EmptyUser: Userinfo = { 35 | id: 0, 36 | username: '', 37 | nickname: '', 38 | password: '', 39 | status: 0, 40 | role_ids: null, 41 | is_root: null, 42 | organization_id: null, 43 | job_id: null, 44 | tenant_id: 0, 45 | } 46 | 47 | const userSingle = 'admin/user/single' 48 | 49 | export function login(data: RequestParam) { 50 | return axios.post(`${userSingle}/login`, data); 51 | } 52 | 53 | export function tenant() { 54 | return axios.post(`${userSingle}/tenant`); 55 | } 56 | 57 | const root = 'admin/auth/user' 58 | export function reqUser(action: string, data: RequestParam | null) { 59 | return axios.post(`${root}/${action}`, data || {}); 60 | } 61 | -------------------------------------------------------------------------------- /six-arco/src/hooks/permission.ts: -------------------------------------------------------------------------------- 1 | import { RouteLocationNormalized, RouteRecordRaw } from 'vue-router'; 2 | import { useUserStore } from '@/store'; 3 | 4 | export default function usePermission() { 5 | const userStore = useUserStore(); 6 | return { 7 | accessRouter(route: RouteLocationNormalized | RouteRecordRaw) { 8 | let ok: boolean = false 9 | ok = !route.meta?.requiresAuth || !route.meta?.roles || route.meta?.roles?.includes('*') 10 | if (ok) return ok; 11 | 12 | // const userRoles = userStore.role.split(',') 13 | const userRoles = localStorage.getItem("userRole")?.split(',') || [] 14 | for (const role of userRoles) { 15 | if (route.meta?.roles?.includes(role)) { 16 | return true; 17 | } 18 | } 19 | return false; 20 | }, 21 | findFirstPermissionRoute(_routers: any, role = 'admin') { 22 | const cloneRouters = [..._routers]; 23 | while (cloneRouters.length) { 24 | const firstElement = cloneRouters.shift(); 25 | if ( 26 | firstElement?.meta?.roles?.find((el: string[]) => { 27 | return el.includes('*') || el.includes(role); 28 | }) 29 | ) 30 | return { name: firstElement.name }; 31 | if (firstElement?.children) { 32 | cloneRouters.push(...firstElement.children); 33 | } 34 | } 35 | return null; 36 | }, 37 | // You can add any rules you want 38 | }; 39 | } 40 | -------------------------------------------------------------------------------- /six-arco/src/views/system/Organization/components/form-save.vue: -------------------------------------------------------------------------------- 1 | 19 | 47 | 48 | -------------------------------------------------------------------------------- /six-go/app/admin/service/login/enter.go: -------------------------------------------------------------------------------- 1 | package loginService 2 | 3 | import ( 4 | "errors" 5 | "time" 6 | 7 | "six-go/database/models" 8 | ) 9 | 10 | func New(token string, keepalive ...bool) Driver { 11 | var loginStorage RedisDriver 12 | loginStorage.token = token 13 | if len(keepalive) > 0 && keepalive[0] { 14 | // 调用保活函数 15 | loginStorage.keepalive() 16 | } 17 | return loginStorage 18 | } 19 | 20 | func ClearAll(username string) { 21 | var loginStorage RedisDriver 22 | loginStorage.username = username 23 | loginStorage.ClearAll() 24 | } 25 | 26 | // Driver 任何存储登录状态的驱动只要实现该接口 即可无缝切换 只需要将 LoginStorage 函数中变量 loginStorage 的类型 修改为实现 该接口的 Struct 即可 27 | type Driver interface { 28 | IsLogin() (isLogin bool) 29 | Get() (userinfo StorageValue) 30 | Set(userinfo *models.AuthUser) error 31 | keepalive() 32 | Clear() 33 | ClearAll() 34 | } 35 | 36 | type sessionConfig struct { 37 | // userLimit 设备登录限制数 userLimit = 1 单设备登录 38 | userLimit int 39 | 40 | // userLimitOverMode 登录人数溢出模式 41 | // 阻塞模式:userLimitOverModeBlock 会阻止第 userLimit + 1 个用户登录 42 | // 覆盖模式: userLimitOverModeCover 会覆盖最早过期的用户 43 | userLimitOverMode int 44 | 45 | // expireTime 过期时间 46 | expireTime time.Duration 47 | } 48 | 49 | type StorageValue struct { 50 | expire int64 51 | IsLogin bool 52 | Userinfo *models.AuthUser 53 | } 54 | 55 | const ( 56 | userLimitOverModeBlock = 0 57 | userLimitOverModeCover = 1 58 | ) 59 | 60 | var ( 61 | ErrorLoginBlocked = errors.New("该账号登录设备超出系统限制,请在其他设备退出登录后重试。") 62 | ) 63 | 64 | var loginConfig = sessionConfig{ 65 | userLimit: 9999, 66 | userLimitOverMode: userLimitOverModeCover, 67 | expireTime: time.Hour * 24 * 7, // 默认每个token登录有效期保活7天 68 | } 69 | -------------------------------------------------------------------------------- /six-arco/src/views/system/Job/components/form-save.vue: -------------------------------------------------------------------------------- 1 | 19 | 48 | 49 | -------------------------------------------------------------------------------- /six-go/static/generator_tpl/front/form.vue.tpl: -------------------------------------------------------------------------------- 1 | 15 | 52 | 53 | -------------------------------------------------------------------------------- /six-arco/src/views/dashboard/workplace/locale/en-US.ts: -------------------------------------------------------------------------------- 1 | export default { 2 | 'menu.dashboard.workplace': 'Workplace', 3 | 'workplace.welcome': 'Welcome!', 4 | 'workplace.balance': 'Balance (CNY)', 5 | 'workplace.order.pending': 'Pending', 6 | 'workplace.order.pendingRenewal': 'Renewal Order', 7 | 'workplace.onlineContent': 'Online Content', 8 | 'workplace.putIn': 'Put In', 9 | 'workplace.newDay': 'Daily Additional Comments', 10 | 'workplace.newFromYesterday': 'New From Yesterday', 11 | 'workplace.minute': 'Min', 12 | 'workplace.docs': 'Documents', 13 | 'workplace.docs.productOverview': 'Product Overview', 14 | 'workplace.docs.userGuide': 'User Guide', 15 | 'workplace.docs.workflow': 'Workflow', 16 | 'workplace.docs.interfaceDocs': 'Interface Docs', 17 | // 18 | 'workplace.contentManagement': 'Content Management', 19 | 'workplace.contentStatistical': 'Content Statistical', 20 | 'workplace.advanced': 'Advanced', 21 | 'workplace.onlinePromotion': 'Online Promotion', 22 | 'workplace.contentPutIn': 'Put In', 23 | 'workplace.announcement': 'Announcement', 24 | 'workplace.recently.visited': 'Recently Visited', 25 | 'workplace.record.nodata': 'No data', 26 | 'workplace.quick.operation': 'Quick Operation', 27 | 'workplace.quickOperation.setup': 'Setup', 28 | 'workplace.allProject': 'All', 29 | 'workplace.loadMore': 'More', 30 | 'workplace.viewMore': 'More', 31 | 'workplace.contentData': 'Content Data', 32 | 'workplace.popularContent': 'Popular Content', 33 | 'workplace.popularContent.text': 'text', 34 | 'workplace.popularContent.image': 'image', 35 | 'workplace.popularContent.video': 'video', 36 | 'workplace.categoriesPercent': 'Categories Percent', 37 | 'workplace.pecs': 'pecs', 38 | }; 39 | -------------------------------------------------------------------------------- /six-go/extra/uploader/uploader.go: -------------------------------------------------------------------------------- 1 | package uploader 2 | 3 | import ( 4 | "crypto/md5" 5 | "fmt" 6 | "mime/multipart" 7 | "time" 8 | 9 | "github.com/spf13/cast" 10 | "six-go/config" 11 | ) 12 | 13 | type Uploader interface { 14 | Upload(f *multipart.FileHeader) Result 15 | Remove(path string) error 16 | } 17 | 18 | type Result struct { 19 | Error error `json:"error"` 20 | Url string `json:"url"` 21 | IsLocal bool `json:"is_local"` 22 | } 23 | 24 | type _config struct { 25 | typ string 26 | name string 27 | path string 28 | err error 29 | } 30 | 31 | const ( 32 | defaultUploadType = "local" 33 | defaultUploadPath = "uploads" 34 | defaultUploadName = "md5" 35 | ) 36 | 37 | func conf() *_config { 38 | var cfg = &_config{} 39 | 40 | m := cast.ToStringMapString(config.Get("upload")) 41 | 42 | typ, ok := m["type"] 43 | if !ok { 44 | cfg.typ = defaultUploadType 45 | } else { 46 | cfg.typ = typ 47 | } 48 | 49 | name, nok := m["name"] 50 | if !nok { 51 | cfg.name = defaultUploadName 52 | } else { 53 | cfg.name = name 54 | } 55 | 56 | if cfg.typ == "local" { 57 | if path, pok := m["path"]; !pok || path == "" { 58 | cfg.path = defaultUploadPath 59 | } else { 60 | cfg.path = path 61 | } 62 | } 63 | return cfg 64 | } 65 | 66 | var mode = map[string]Uploader{ 67 | "local": newLocal(), 68 | "cos": newCos(), 69 | "oss": newOss(), 70 | "qiniu": newQiniu(), 71 | } 72 | 73 | func New() Uploader { 74 | return mode[conf().typ] 75 | } 76 | 77 | func filenameByMd5(f []byte, ext string) string { 78 | return fmt.Sprintf("%s/%x", conf().path, md5.Sum(f)) + ext 79 | } 80 | 81 | func filenameByTimes(ext string) string { 82 | timeFormat := "20060102150405.000000000" 83 | return conf().path + "/" + time.Now().Format(timeFormat) + ext 84 | } 85 | -------------------------------------------------------------------------------- /six-arco/src/views/dashboard/workplace/components/announcement.vue: -------------------------------------------------------------------------------- 1 | 21 | 22 | 51 | 52 | 72 | -------------------------------------------------------------------------------- /six-go/app/admin/route/route_auth.go: -------------------------------------------------------------------------------- 1 | package adminRoute 2 | 3 | import ( 4 | "github.com/gin-gonic/gin" 5 | "six-go/app/admin/controller" 6 | ) 7 | 8 | func (r Route) AuthRule(app *gin.RouterGroup) { 9 | p := app.Group("/auth/rule") 10 | p.POST("/list", controller.AuthRule.List) 11 | p.POST("/tree-select", controller.AuthRule.TreeSelect) 12 | p.POST("/select", controller.AuthRule.Select) 13 | p.POST("/get", controller.AuthRule.Get) 14 | p.POST("/add", controller.AuthRule.Add) 15 | p.POST("/edit", controller.AuthRule.Update) 16 | p.POST("/save", controller.AuthRule.Save) 17 | p.POST("/del", controller.AuthRule.Delete) 18 | } 19 | 20 | func (r Route) AuthRole(app *gin.RouterGroup) { 21 | p := app.Group("/auth/role") 22 | p.POST("/list", controller.AuthRole.List) 23 | p.POST("/select", controller.AuthRole.Select) 24 | p.POST("/tree-select", controller.AuthRole.TreeSelect) 25 | p.POST("/get", controller.AuthRole.Get) 26 | p.POST("/add", controller.AuthRole.Add) 27 | p.POST("/edit", controller.AuthRole.Update) 28 | p.POST("/save", controller.AuthRole.Save) 29 | p.POST("/del", controller.AuthRole.Delete) 30 | } 31 | 32 | func (r Route) AuthRelation(app *gin.RouterGroup) { 33 | p := app.Group("/auth/relation") 34 | p.POST("/select/group/role", controller.AuthRelation.SelectGroupRole) // map[role_id][]{rule_ids} 角色、拥有哪些规则 35 | p.POST("/select/group/rule", controller.AuthRelation.SelectGroupRule) // map[rule_id][]{role_ids} 规则、属于哪些角色 36 | p.POST("/select/rule", controller.AuthRelation.SelectRuleIdsWithRoleId) 37 | p.POST("/set", controller.AuthRelation.Set) 38 | } 39 | 40 | func (r Route) AuthUser(app *gin.RouterGroup) { 41 | p := app.Group("/auth/user") 42 | p.POST("/list", controller.AuthUser.List) 43 | p.POST("/select", controller.AuthUser.Select) 44 | p.POST("/get", controller.AuthUser.Get) 45 | p.POST("/add", controller.AuthUser.Add) 46 | p.POST("/edit", controller.AuthUser.Update) 47 | p.POST("/save", controller.AuthUser.Save) 48 | p.POST("/del", controller.AuthUser.Delete) 49 | } 50 | -------------------------------------------------------------------------------- /six-go/database/models/cronjobs.go: -------------------------------------------------------------------------------- 1 | package models 2 | 3 | import ( 4 | "errors" 5 | validation "github.com/go-ozzo/ozzo-validation" 6 | "github.com/vainback/six-util/v3" 7 | "gorm.io/gorm" 8 | "six-go/database/db" 9 | ) 10 | 11 | var TableCronJob CronJob 12 | 13 | type CronJob struct { 14 | db.MODEL 15 | db.SoftDelete 16 | Name string `json:"name"` // 唯一标识 17 | Title string `json:"title"` // 标题 18 | Times string `json:"times"` // 定时表达式 19 | Status int `json:"status" gorm:"type:tinyint(1);comment:状态 -1 禁用 1启用"` 20 | } 21 | 22 | func (data CronJob) TableName() string { 23 | return "cron_jobs" 24 | } 25 | 26 | func (data CronJob) HasTableName(filed string) string { 27 | return six.Strings(data.TableName(), ".", filed).String() 28 | } 29 | 30 | func (data CronJob) KeywordFields() []string { 31 | return six.Arrays( 32 | data.HasTableName("name"), 33 | data.HasTableName("title"), 34 | ) 35 | } 36 | 37 | func (data CronJob) FilterSqlBuilder() func(db *gorm.DB) *gorm.DB { 38 | return func(db *gorm.DB) *gorm.DB { 39 | if data.Id > 0 { 40 | return db.Where(data.HasTableName("id")+" = ?", data.Id) 41 | } 42 | if data.Name != "" { 43 | db = db.Where(data.HasTableName("type")+" = ?", data.Name) 44 | } 45 | if data.Title != "" { 46 | db = db.Where(data.HasTableName("label")+" LIKE ?", "%"+data.Title+"%") 47 | } 48 | 49 | if data.Status != 0 { 50 | db = db.Where("status = ?", data.Status) 51 | } 52 | return db 53 | } 54 | } 55 | 56 | func (data CronJob) GetId() int64 { 57 | return data.Id 58 | } 59 | 60 | func (data CronJob) Valid(idRequired ...bool) error { 61 | if len(idRequired) > 0 && idRequired[0] { 62 | if data.Id <= 0 { 63 | return errors.New("id is required") 64 | } 65 | } 66 | 67 | return validation.ValidateStruct(&data, 68 | validation.Field(&data.Name, validation.Required.Error("唯一标识不能为空")), 69 | validation.Field(&data.Title, validation.Required.Error("标题不能为空")), 70 | validation.Field(&data.Times, validation.Required.Error("定时时间不能为空")), 71 | ) 72 | } 73 | -------------------------------------------------------------------------------- /six-arco/src/components/editor/wang.vue: -------------------------------------------------------------------------------- 1 | 22 | 63 | -------------------------------------------------------------------------------- /six-arco/src/components/global-setting/block.vue: -------------------------------------------------------------------------------- 1 | 15 | 16 | 61 | 62 | 80 | -------------------------------------------------------------------------------- /six-go/app/admin/controller/operate_logs.go: -------------------------------------------------------------------------------- 1 | package controller 2 | 3 | import ( 4 | "errors" 5 | 6 | "github.com/gin-gonic/gin" 7 | "gorm.io/gorm" 8 | "six-go/app/admin/entity" 9 | "six-go/app/admin/middleware" 10 | "six-go/database/dao" 11 | "six-go/database/models" 12 | "six-go/utils/response" 13 | ) 14 | 15 | type OperateLogsController struct { 16 | dao.Query[models.OperateLog] 17 | } 18 | 19 | var OperateLogs = new(OperateLogsController) 20 | 21 | func (ts *OperateLogsController) List(c *gin.Context) { 22 | var query = new(dao.Query[entity.LogJoinUser]) 23 | if err := c.ShouldBindBodyWithJSON(query); err != nil { 24 | response.JsonError(c, response.ErrorParamsParser, err) 25 | return 26 | } 27 | query.M.User.TenantId = middleware.SessionUser(c).TenantId 28 | 29 | var total int64 30 | var list []entity.LogJoinUser 31 | if err := query.DB().Query().JoinList(&list, &total, query.M.LeftJoin(), query.M.Select()); err != nil { 32 | response.JsonError(c, response.ErrorDbSelect, err) 33 | } else { 34 | response.JsonPage(c, response.OkDbSelect, list, total) 35 | } 36 | } 37 | 38 | func (ts *OperateLogsController) Select(c *gin.Context) { 39 | if err := c.ShouldBindBodyWithJSON(ts); err != nil { 40 | response.JsonError(c, response.ErrorParamsParser, err) 41 | return 42 | } 43 | 44 | var list []models.OperateLog 45 | if err := ts.DB().Query().Find(&list); err != nil { 46 | response.JsonError(c, response.ErrorDbSelect, err) 47 | } else { 48 | response.Json(c, response.OkDbSelect, list) 49 | } 50 | } 51 | 52 | func (ts *OperateLogsController) Get(c *gin.Context) { 53 | if err := c.ShouldBindBodyWithJSON(ts); err != nil { 54 | response.JsonError(c, response.ErrorParamsParser, err) 55 | return 56 | } 57 | 58 | var row models.OperateLog 59 | if err := ts.DB().Query().First(&row); err != nil { 60 | if errors.Is(err, gorm.ErrRecordNotFound) { 61 | response.JsonError(c, response.ErrorDbNotFound, err) 62 | return 63 | } 64 | response.JsonError(c, response.ErrorDbSelect, err) 65 | } else { 66 | response.Json(c, response.OkDbSelect, row) 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /six-go/config/database.go: -------------------------------------------------------------------------------- 1 | package config 2 | 3 | import ( 4 | "log" 5 | "strings" 6 | "time" 7 | 8 | "github.com/spf13/cast" 9 | "gorm.io/gorm/logger" 10 | ) 11 | 12 | type DatabaseConfig struct { 13 | data map[string]any 14 | } 15 | 16 | func DB() *DatabaseConfig { 17 | if db, ok := _config["database"]; ok { 18 | return &DatabaseConfig{data: cast.ToStringMap(db)} 19 | } 20 | return &DatabaseConfig{data: make(map[string]any)} 21 | } 22 | 23 | func (d *DatabaseConfig) AutoMigrate() bool { 24 | maxOpen, ok := d.data["auto_migrate"] 25 | if !ok { 26 | return false 27 | } 28 | return cast.ToBool(maxOpen) 29 | } 30 | 31 | func (d *DatabaseConfig) LogLevel() logger.LogLevel { 32 | logLevel, ok := d.data["log_level"] 33 | if !ok { 34 | return 1 35 | } 36 | 37 | switch cast.ToString(logLevel) { 38 | case "error": 39 | return logger.Error 40 | case "warn": 41 | return logger.Warn 42 | case "info": 43 | return logger.Info 44 | default: 45 | return logger.Silent 46 | } 47 | } 48 | 49 | func (d *DatabaseConfig) MaxOpenConns() int { 50 | maxOpen, ok := d.data["max_open_conn"] 51 | if !ok { 52 | return 10 53 | } 54 | 55 | maxNum := cast.ToInt(maxOpen) 56 | if maxNum <= 0 { 57 | return 10 58 | } 59 | return maxNum 60 | } 61 | 62 | func (d *DatabaseConfig) MaxIdleConns() int { 63 | maxIdle, ok := d.data["max_idle_conn"] 64 | if !ok { 65 | return 10 66 | } 67 | maxNum := cast.ToInt(maxIdle) 68 | if maxNum <= 0 { 69 | return 10 70 | } 71 | return maxNum 72 | } 73 | 74 | func (d *DatabaseConfig) ConnMaxLifetime() time.Duration { 75 | connMaxLife, ok := d.data["conn_max_life_time"] 76 | if !ok { 77 | return 86400 * time.Second 78 | } 79 | connMaxLifeNum := cast.ToInt64(connMaxLife) 80 | if connMaxLifeNum <= 0 { 81 | return 86400 * time.Second 82 | } 83 | return time.Duration(connMaxLifeNum) * time.Second 84 | } 85 | 86 | func (d *DatabaseConfig) DSN() string { 87 | dsn := strings.TrimSpace(cast.ToString(d.data["dsn"])) 88 | if dsn == "" { 89 | log.Println("database dsn is empty. at config/database.go line 87") 90 | return "" 91 | } 92 | return dsn 93 | } 94 | -------------------------------------------------------------------------------- /six-go/extra/xredis/redis.go: -------------------------------------------------------------------------------- 1 | package xredis 2 | 3 | import ( 4 | "context" 5 | "log" 6 | "time" 7 | 8 | "github.com/redis/go-redis/v9" 9 | ) 10 | 11 | var ( 12 | ctx = context.Background() 13 | client *redis.Client 14 | ) 15 | 16 | func Client() *redis.Client { 17 | return do() 18 | } 19 | 20 | func do() *redis.Client { 21 | if client == nil { 22 | client = redis.NewClient(&redis.Options{ 23 | Addr: cfg().addr(), 24 | Password: cfg().pass(), 25 | DB: cfg().db(), 26 | }) 27 | } 28 | 29 | if err := client.Ping(ctx).Err(); err != nil { 30 | log.Println("redis ping err:", err) 31 | } 32 | 33 | return client 34 | } 35 | 36 | func Ping() error { 37 | return do().Ping(ctx).Err() 38 | } 39 | 40 | func IsExpire(key string, seconds int64) bool { 41 | result := HasExpireSeconds(key) 42 | return result == -1 || result > float64(seconds) 43 | } 44 | 45 | func HasExpireSeconds(key string) float64 { 46 | result, err := do().TTL(ctx, key).Result() 47 | if err != nil { 48 | return -2 49 | } 50 | return result.Seconds() 51 | } 52 | 53 | func GetString(key string) string { 54 | result, err := do().Get(ctx, key).Result() 55 | if err != nil { 56 | return "" 57 | } 58 | return result 59 | } 60 | 61 | func GetInt(key string) int64 { 62 | result, err := do().Get(ctx, key).Int64() 63 | if err != nil { 64 | return 0 65 | } 66 | return result 67 | } 68 | 69 | func Set(key string, value any) error { 70 | return do().Set(ctx, key, value, -1).Err() 71 | } 72 | 73 | // SetExp expiration 传入的值必须携带单位 例如:time.Second * 60 既有效期60秒 time.Hour * 3 既有效期3小时 74 | func SetExp(key string, value any, expiration time.Duration) error { 75 | return do().Set(ctx, key, value, expiration).Err() 76 | } 77 | 78 | func Del(key string) error { 79 | return do().Del(ctx, key).Err() 80 | } 81 | 82 | func Expire(key string, exp time.Duration) error { 83 | return do().Expire(ctx, key, exp).Err() 84 | } 85 | 86 | func Push(key string, values ...any) error { 87 | return do().RPush(ctx, key, values...).Err() 88 | } 89 | 90 | func Pop(key string) (string, error) { 91 | return do().LPop(ctx, key).Result() 92 | } 93 | -------------------------------------------------------------------------------- /six-go/database/models/code_generator.go: -------------------------------------------------------------------------------- 1 | package models 2 | 3 | import ( 4 | "errors" 5 | "gorm.io/gorm" 6 | "six-go/database/db" 7 | ) 8 | 9 | var TableCodeGenerator CodeGenerator 10 | 11 | type CodeGenerator struct { 12 | db.MODEL 13 | db.SoftDelete 14 | Table string `json:"table" gorm:"column:table"` 15 | Fields *[]CodeGeneratorFields `json:"fields" gorm:"column:fields;serializer:json;type:longtext"` 16 | Title string `json:"title" gorm:"column:title"` // 菜单名称 17 | ParentModule int64 `json:"parent_module" gorm:"column:parent_module"` // 父级菜单id 18 | IsSoftDelete bool `json:"is_soft_delete" gorm:"column:is_soft_delete"` 19 | IsTenant bool `json:"is_tenant" gorm:"column:is_tenant"` 20 | } 21 | 22 | type CodeGeneratorFields struct { 23 | Title string `json:"title"` // 展示名 24 | Name string `json:"name"` // 字段名 25 | Type string `json:"type"` // 字段类型 int int64 uint uint64 string float64 decimal select radio checkbox switch textarea 上传图片 多图上传 上传文件 时间选择器 日期选择器 日期时间选择器 富文本 26 | Default *string `json:"default"` // 字段默认值 nil 为 null 非nil is not null 27 | Index string `json:"index"` // 索引 可选值为 unique | index 28 | Comment string `json:"comment"` // 注释 29 | IsKeyword bool `json:"is_keyword"` 30 | IsRequired bool `json:"is_required"` 31 | DictType string `json:"dict_type"` // 字典类型 32 | } 33 | 34 | func (data CodeGenerator) KeywordFields() []string { 35 | return []string{"`table`", "title"} 36 | } 37 | 38 | func (data CodeGenerator) FilterSqlBuilder() func(db *gorm.DB) *gorm.DB { 39 | return func(db *gorm.DB) *gorm.DB { 40 | return db 41 | } 42 | } 43 | 44 | func (data CodeGenerator) GetId() int64 { 45 | return data.Id 46 | } 47 | 48 | func (data CodeGenerator) TableName() string { 49 | return "code_generator" 50 | } 51 | 52 | func (data CodeGenerator) Valid(idRequired ...bool) error { 53 | if len(idRequired) > 0 && idRequired[0] { 54 | if data.Id <= 0 { 55 | return errors.New("id is required") 56 | } 57 | } 58 | 59 | return nil 60 | } 61 | -------------------------------------------------------------------------------- /six-go/database/models/job.go: -------------------------------------------------------------------------------- 1 | package models 2 | 3 | import ( 4 | "errors" 5 | "github.com/vainback/six-util/v3" 6 | 7 | validation "github.com/go-ozzo/ozzo-validation" 8 | "gorm.io/gorm" 9 | "six-go/database/db" 10 | ) 11 | 12 | var TableJob Job 13 | 14 | type Job struct { 15 | db.MODEL 16 | db.SoftDelete 17 | TenantIdentify 18 | ParentId int64 `json:"parent_id"` 19 | Name string `json:"name"` 20 | Description string `json:"description"` 21 | } 22 | 23 | func (data Job) TableName() string { 24 | return "jobs" 25 | } 26 | 27 | func (data Job) HasTableName(filed string) string { 28 | return six.Strings(data.TableName(), ".", filed).String() 29 | } 30 | 31 | func (data Job) KeywordFields() []string { 32 | return six.Arrays( 33 | data.HasTableName("name"), 34 | data.HasTableName("description"), 35 | ) 36 | } 37 | 38 | func (data Job) FilterSqlBuilder() func(db *gorm.DB) *gorm.DB { 39 | return func(db *gorm.DB) *gorm.DB { 40 | if data.Id > 0 { 41 | return db.Where(data.HasTableName("id")+" = ?", data.Id) 42 | } 43 | if data.ParentId != 0 { 44 | db = db.Where(data.HasTableName("parent_id")+" = ?", data.ParentId) 45 | } 46 | if data.Name != "" { 47 | db = db.Where(data.HasTableName("title")+" LIKE ?", "%"+data.Name+"%") 48 | } 49 | if data.Description != "" { 50 | db = db.Where(data.HasTableName("sign")+" LIKE ?", "%"+data.Description+"%") 51 | } 52 | 53 | return db.Scopes(data.TenantIdentify.SqlBuilder(data.TableName())) 54 | } 55 | } 56 | 57 | func (data Job) GetId() int64 { 58 | return data.Id 59 | } 60 | 61 | func (data Job) Valid(idRequired ...bool) error { 62 | if len(idRequired) > 0 && idRequired[0] { 63 | if data.Id <= 0 { 64 | return errors.New("id is required") 65 | } 66 | } 67 | 68 | return validation.ValidateStruct(&data, 69 | validation.Field(&data.ParentId, validation.Min(0).Error("上级职位不合法")), 70 | validation.Field(&data.Name, validation.Required.Error("角色名称必填")), 71 | ) 72 | } 73 | 74 | func (data Job) HasChildren() (childNums int64, err error) { 75 | err = db.DB().Model(&Job{}).Where("parent_id = ?", data.Id).Count(&childNums).Error 76 | return 77 | } 78 | -------------------------------------------------------------------------------- /six-go/database/models/tenant.go: -------------------------------------------------------------------------------- 1 | package models 2 | 3 | import ( 4 | "errors" 5 | validation "github.com/go-ozzo/ozzo-validation" 6 | "github.com/vainback/six-util/v3" 7 | "gorm.io/gorm" 8 | "six-go/database/db" 9 | ) 10 | 11 | var TableTenant Tenant 12 | 13 | type Tenant struct { 14 | db.MODEL 15 | db.SoftDelete 16 | Name string `json:"name" gorm:"comment:租户名"` 17 | Sign string `json:"sign" gorm:"unique;comment:租户唯一标识"` 18 | Domain string `json:"domain" gorm:"comment:单独的域名"` 19 | Status int `json:"status" gorm:"type:tinyint(1);comment:状态 -1 禁用 1启用"` 20 | } 21 | 22 | func (data Tenant) TableName() string { 23 | return "tenant" 24 | } 25 | 26 | func (data Tenant) HasTableName(filed string) string { 27 | return six.Strings(data.TableName(), ".", filed).String() 28 | } 29 | 30 | func (data Tenant) KeywordFields() []string { 31 | return six.Arrays( 32 | data.HasTableName("name"), 33 | data.HasTableName("sign"), 34 | data.HasTableName("domain"), 35 | ) 36 | } 37 | 38 | func (data Tenant) FilterSqlBuilder() func(db *gorm.DB) *gorm.DB { 39 | return func(db *gorm.DB) *gorm.DB { 40 | if data.Id > 0 { 41 | return db.Where(data.HasTableName("id")+" = ?", data.Id) 42 | } 43 | if data.Name != "" { 44 | db = db.Where(data.HasTableName("name")+" like ?", "%"+data.Name+"%") 45 | } 46 | if data.Sign != "" { 47 | db = db.Where(data.HasTableName("sign")+" like ?", "%"+data.Sign+"%") 48 | } 49 | if data.Domain != "" { 50 | db = db.Where(data.HasTableName("domain")+" like ?", "%"+data.Domain+"%") 51 | } 52 | 53 | if data.Status != 0 { 54 | db = db.Where(data.HasTableName("status")+" = ?", data.Status) 55 | } 56 | return db 57 | } 58 | } 59 | 60 | func (data Tenant) GetId() int64 { 61 | return data.Id 62 | } 63 | 64 | func (data Tenant) Valid(idRequired ...bool) error { 65 | if len(idRequired) > 0 && idRequired[0] { 66 | if data.Id <= 0 { 67 | return errors.New("id is required") 68 | } 69 | } 70 | 71 | return validation.ValidateStruct(&data, 72 | validation.Field(&data.Name, validation.Required.Error("租户名必须填写")), 73 | validation.Field(&data.Sign, validation.Required.Error("租户Sign必须填写")), 74 | ) 75 | } 76 | -------------------------------------------------------------------------------- /six-go/app/admin/service/login/mysql.go: -------------------------------------------------------------------------------- 1 | package loginService 2 | 3 | import ( 4 | "time" 5 | 6 | "six-go/database/db" 7 | "six-go/database/models" 8 | ) 9 | 10 | type MysqlDriver struct { 11 | token string 12 | username string 13 | } 14 | 15 | func (ts MysqlDriver) IsLogin() (isLogin bool) { 16 | isLogin = ts.Get().IsLogin 17 | return 18 | } 19 | 20 | func (ts MysqlDriver) Get() (storageValue StorageValue) { 21 | var value models.AuthUserLoginStorage 22 | if err := db.DB().First(&value, "token = ?", ts.token).Error; err != nil { 23 | return 24 | } 25 | 26 | var user models.AuthUser 27 | if err := db.DB().First(&user, "username = ?", value.Username).Error; err != nil { 28 | return 29 | } 30 | 31 | return StorageValue{ 32 | IsLogin: true, 33 | Userinfo: &user, 34 | } 35 | } 36 | 37 | func (ts MysqlDriver) Set(userinfo *models.AuthUser) error { 38 | var alreadyTokens []models.AuthUserLoginStorage 39 | if err := db.DB().Where("token = ?", ts.token).Order("expire asc").Find(&alreadyTokens).Error; err != nil { 40 | return err 41 | } 42 | 43 | if len(alreadyTokens) >= loginConfig.userLimit { 44 | switch loginConfig.userLimitOverMode { 45 | case userLimitOverModeBlock: // 阻塞模式 46 | return ErrorLoginBlocked 47 | default: // 默认为覆盖模式 移除最早过期的用户 48 | (MysqlDriver{token: alreadyTokens[0].Token}).Clear() 49 | } 50 | } 51 | 52 | return db.DB().Create(&models.AuthUserLoginStorage{ 53 | Username: userinfo.Username, 54 | Token: ts.token, 55 | Expire: time.Now().Add(loginConfig.expireTime).Unix(), 56 | }).Error 57 | } 58 | 59 | func (ts MysqlDriver) keepalive() { 60 | // 清除所有已失效的token 61 | _ = db.DB().Delete(&models.AuthUserLoginStorage{}, "expire <= ?", time.Now().Unix()).Error 62 | // 保活当前token 63 | _ = db.DB().Model(&models.AuthUserLoginStorage{}).Where("token = ?", ts.token).Update("expire", time.Now().Add(loginConfig.expireTime).Unix()).Error 64 | } 65 | 66 | // Clear 清除指定token 67 | func (ts MysqlDriver) Clear() { 68 | _ = db.DB().Delete(&models.AuthUserLoginStorage{Token: ts.token}).Error 69 | } 70 | 71 | func (ts MysqlDriver) ClearAll() { 72 | _ = db.DB().Delete(&models.AuthUserLoginStorage{Username: ts.username}).Error 73 | } 74 | -------------------------------------------------------------------------------- /six-arco/src/assets/style/global.less: -------------------------------------------------------------------------------- 1 | * { 2 | box-sizing: border-box; 3 | } 4 | 5 | html, 6 | body { 7 | width: 100%; 8 | height: 100%; 9 | margin: 0; 10 | padding: 0; 11 | font-size: 14px; 12 | background-color: var(--color-bg-1); 13 | -moz-osx-font-smoothing: grayscale; 14 | -webkit-font-smoothing: antialiased; 15 | } 16 | 17 | .echarts-tooltip-diy { 18 | background: linear-gradient( 19 | 304.17deg, 20 | rgba(253, 254, 255, 0.6) -6.04%, 21 | rgba(244, 247, 252, 0.6) 85.2% 22 | ) !important; 23 | border: none !important; 24 | backdrop-filter: blur(10px) !important; 25 | /* Note: backdrop-filter has minimal browser support */ 26 | 27 | border-radius: 6px !important; 28 | .content-panel { 29 | display: flex; 30 | justify-content: space-between; 31 | padding: 0 9px; 32 | background: rgba(255, 255, 255, 0.8); 33 | width: 164px; 34 | height: 32px; 35 | line-height: 32px; 36 | box-shadow: 6px 0px 20px rgba(34, 87, 188, 0.1); 37 | border-radius: 4px; 38 | margin-bottom: 4px; 39 | } 40 | .tooltip-title { 41 | margin: 0 0 10px 0; 42 | } 43 | p { 44 | margin: 0; 45 | } 46 | .tooltip-title, 47 | .tooltip-value { 48 | font-size: 13px; 49 | line-height: 15px; 50 | display: flex; 51 | align-items: center; 52 | text-align: right; 53 | color: #1d2129; 54 | font-weight: bold; 55 | } 56 | .tooltip-item-icon { 57 | display: inline-block; 58 | margin-right: 8px; 59 | width: 10px; 60 | height: 10px; 61 | border-radius: 50%; 62 | } 63 | } 64 | 65 | .general-card { 66 | border-radius: 4px; 67 | border: none; 68 | & > .arco-card-header { 69 | height: auto; 70 | padding: 20px; 71 | border: none; 72 | } 73 | & > .arco-card-body { 74 | padding: 0 20px 20px 20px; 75 | } 76 | } 77 | 78 | .split-line { 79 | border-color: rgb(var(--gray-2)); 80 | } 81 | 82 | .arco-table-cell { 83 | .circle { 84 | display: inline-block; 85 | margin-right: 4px; 86 | width: 6px; 87 | height: 6px; 88 | border-radius: 50%; 89 | background-color: rgb(var(--blue-6)); 90 | &.pass { 91 | background-color: rgb(var(--green-6)); 92 | } 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /six-arco/src/views/system/Tenant/component/form-save.vue: -------------------------------------------------------------------------------- 1 | 33 | 61 | 62 | -------------------------------------------------------------------------------- /six-go/database/models/organization.go: -------------------------------------------------------------------------------- 1 | package models 2 | 3 | import ( 4 | "errors" 5 | validation "github.com/go-ozzo/ozzo-validation" 6 | "github.com/vainback/six-util/v3" 7 | "gorm.io/gorm" 8 | "six-go/database/db" 9 | ) 10 | 11 | var TableOrganization Organization 12 | 13 | type Organization struct { 14 | db.MODEL 15 | db.SoftDelete 16 | TenantIdentify 17 | ParentId int64 `json:"parent_id"` 18 | Name string `json:"name"` 19 | Description string `json:"description"` 20 | } 21 | 22 | func (data Organization) TableName() string { 23 | return "organization" 24 | } 25 | 26 | func (data Organization) HasTableName(filed string) string { 27 | return six.Strings(data.TableName(), ".", filed).String() 28 | } 29 | 30 | func (data Organization) KeywordFields() []string { 31 | return six.Arrays( 32 | data.HasTableName("name"), 33 | data.HasTableName("description"), 34 | ) 35 | } 36 | 37 | func (data Organization) FilterSqlBuilder() func(db *gorm.DB) *gorm.DB { 38 | return func(db *gorm.DB) *gorm.DB { 39 | if data.Id > 0 { 40 | return db.Where(data.HasTableName("id")+" = ?", data.Id) 41 | } 42 | if data.ParentId != 0 { 43 | db = db.Where(data.HasTableName("parent_id")+" = ?", data.ParentId) 44 | } 45 | if data.Name != "" { 46 | db = db.Where(data.HasTableName("title")+" LIKE ?", "%"+data.Name+"%") 47 | } 48 | if data.Description != "" { 49 | db = db.Where(data.HasTableName("sign")+" LIKE ?", "%"+data.Description+"%") 50 | } 51 | 52 | return db.Scopes(data.TenantIdentify.SqlBuilder(data.TableName())) 53 | } 54 | } 55 | 56 | func (data Organization) GetId() int64 { 57 | return data.Id 58 | } 59 | 60 | func (data Organization) Valid(idRequired ...bool) error { 61 | if len(idRequired) > 0 && idRequired[0] { 62 | if data.Id <= 0 { 63 | return errors.New("id is required") 64 | } 65 | } 66 | 67 | return validation.ValidateStruct(&data, 68 | validation.Field(&data.ParentId, validation.Min(0).Error("上级组织不合法")), 69 | validation.Field(&data.Name, validation.Required.Error("角色名称必填")), 70 | ) 71 | } 72 | 73 | func (data Organization) HasChildren() (childNums int64, err error) { 74 | err = db.DB().Model(&Organization{}).Where("parent_id = ?", data.Id).Count(&childNums).Error 75 | return 76 | } 77 | -------------------------------------------------------------------------------- /six-arco/src/views/login/index.vue: -------------------------------------------------------------------------------- 1 | 21 | 22 | 27 | 28 | 71 | 72 | 82 | -------------------------------------------------------------------------------- /six-arco/src/views/login/components/banner.vue: -------------------------------------------------------------------------------- 1 | 16 | 17 | 41 | 42 | 85 | -------------------------------------------------------------------------------- /six-arco/src/store/modules/tab-bar/index.ts: -------------------------------------------------------------------------------- 1 | import type { RouteLocationNormalized } from 'vue-router'; 2 | import { defineStore } from 'pinia'; 3 | import { 4 | DEFAULT_ROUTE, 5 | DEFAULT_ROUTE_NAME, 6 | REDIRECT_ROUTE_NAME, 7 | } from '@/router/constants'; 8 | import { isString } from '@/utils/is'; 9 | import { TabBarState, TagProps } from './types'; 10 | 11 | const formatTag = (route: RouteLocationNormalized): TagProps => { 12 | const { name, meta, fullPath, query } = route; 13 | return { 14 | title: meta.locale || '', 15 | name: String(name), 16 | fullPath, 17 | query, 18 | ignoreCache: meta.ignoreCache, 19 | }; 20 | }; 21 | 22 | const BAN_LIST = [REDIRECT_ROUTE_NAME]; 23 | 24 | const useAppStore = defineStore('tabBar', { 25 | state: (): TabBarState => ({ 26 | cacheTabList: new Set([DEFAULT_ROUTE_NAME]), 27 | tagList: [DEFAULT_ROUTE], 28 | }), 29 | 30 | getters: { 31 | getTabList(): TagProps[] { 32 | return this.tagList; 33 | }, 34 | getCacheList(): string[] { 35 | return Array.from(this.cacheTabList); 36 | }, 37 | }, 38 | 39 | actions: { 40 | updateTabList(route: RouteLocationNormalized) { 41 | if (BAN_LIST.includes(route.name as string)) return; 42 | this.tagList.push(formatTag(route)); 43 | if (!route.meta.ignoreCache) { 44 | this.cacheTabList.add(route.name as string); 45 | } 46 | }, 47 | deleteTag(idx: number, tag: TagProps) { 48 | this.tagList.splice(idx, 1); 49 | this.cacheTabList.delete(tag.name); 50 | }, 51 | addCache(name: string) { 52 | if (isString(name) && name !== '') this.cacheTabList.add(name); 53 | }, 54 | deleteCache(tag: TagProps) { 55 | this.cacheTabList.delete(tag.name); 56 | }, 57 | freshTabList(tags: TagProps[]) { 58 | this.tagList = tags; 59 | this.cacheTabList.clear(); 60 | // 要先判断ignoreCache 61 | this.tagList 62 | .filter((el) => !el.ignoreCache) 63 | .map((el) => el.name) 64 | .forEach((x) => this.cacheTabList.add(x)); 65 | }, 66 | resetTabList() { 67 | this.tagList = [DEFAULT_ROUTE]; 68 | this.cacheTabList.clear(); 69 | this.cacheTabList.add(DEFAULT_ROUTE_NAME); 70 | }, 71 | }, 72 | }); 73 | 74 | export default useAppStore; 75 | -------------------------------------------------------------------------------- /six-go/utils/response/response.go: -------------------------------------------------------------------------------- 1 | package response 2 | 3 | import ( 4 | "log" 5 | "net/http" 6 | 7 | "github.com/gin-gonic/gin" 8 | ) 9 | 10 | type Result struct { 11 | Code int `json:"code"` 12 | Msg string `json:"msg"` 13 | Data any `json:"data"` 14 | } 15 | 16 | var EmptyList = make([]map[string]any, 0) 17 | var EmptyMap = make(map[string]any) 18 | 19 | const ( 20 | CodeOk = 0 21 | CodeWarn = 1 22 | CodeError = 2 23 | CodeNoAuth = 3 24 | CodeLogout = 9 25 | ) 26 | 27 | const ( 28 | ErrorParamsParser = "参数解析错误" 29 | ErrorDbNotFound = "数据不存在" 30 | ErrorDbSelect = "查询失败" 31 | ErrorDbCreate = "添加失败" 32 | ErrorDbUpdate = "修改失败" 33 | ErrorDbDelete = "删除失败" 34 | ErrorSetting = "设置失败" 35 | ErrorSystem = "系统错误" 36 | ErrorSystemMiddle = "系统错误:middleware" 37 | ErrorUsernameOrPassword = "用户名或密码错误" 38 | ErrorLogin = "登录失败" 39 | ) 40 | 41 | const ( 42 | OkDbSelect = "查询成功" 43 | OkDbCreate = "添加成功" 44 | OkDbUpdate = "修改成功" 45 | OkDbDelete = "删除成功" 46 | OkSetting = "设置成功" 47 | OkLogin = "登录成功" 48 | ) 49 | 50 | func Json(c *gin.Context, msg string, data any) { 51 | var result Result 52 | result.Code = CodeOk 53 | result.Msg = msg 54 | result.Data = data 55 | c.JSON(200, result) 56 | } 57 | 58 | func JsonPage(c *gin.Context, msg string, data any, total int64) { 59 | var result Result 60 | result.Code = CodeOk 61 | result.Msg = msg 62 | result.Data = map[string]any{ 63 | "total": total, 64 | "list": data, 65 | } 66 | c.JSON(200, result) 67 | } 68 | 69 | func JsonWarn(c *gin.Context, msg string) { 70 | var result Result 71 | result.Code = CodeWarn 72 | result.Msg = msg 73 | c.JSON(200, result) 74 | } 75 | 76 | func JsonError(c *gin.Context, msg string, errno error) { 77 | log.Println(errno) 78 | var result Result 79 | result.Code = CodeError 80 | result.Msg = msg 81 | c.JSON(200, result) 82 | } 83 | 84 | func JsonLogout(c *gin.Context) { 85 | var result Result 86 | result.Code = CodeLogout 87 | result.Msg = "登录状态失效" 88 | c.AbortWithStatusJSON(http.StatusOK, result) 89 | } 90 | 91 | func JsonNoAuth(c *gin.Context) { 92 | var result Result 93 | result.Code = CodeNoAuth 94 | result.Msg = "没有操作权限" 95 | c.AbortWithStatusJSON(http.StatusOK, result) 96 | } 97 | -------------------------------------------------------------------------------- /six-arco/src/views/system/AuthRole/components/form-save.vue: -------------------------------------------------------------------------------- 1 | 30 | 57 | 58 | -------------------------------------------------------------------------------- /six-arco/src/mock/message-box.ts: -------------------------------------------------------------------------------- 1 | import Mock from 'mockjs'; 2 | import setupMock, { successResponseWrap } from '@/utils/setup-mock'; 3 | 4 | const haveReadIds: number[] = []; 5 | const getMessageList = () => { 6 | return [ 7 | { 8 | id: 1, 9 | type: 'message', 10 | title: '郑曦月', 11 | subTitle: '的私信', 12 | avatar: 13 | '//p1-arco.byteimg.com/tos-cn-i-uwbnlip3yd/8361eeb82904210b4f55fab888fe8416.png~tplv-uwbnlip3yd-webp.webp', 14 | content: '审批请求已发送,请查收', 15 | time: '今天 12:30:01', 16 | }, 17 | { 18 | id: 2, 19 | type: 'message', 20 | title: '宁波', 21 | subTitle: '的回复', 22 | avatar: 23 | '//p1-arco.byteimg.com/tos-cn-i-uwbnlip3yd/3ee5f13fb09879ecb5185e440cef6eb9.png~tplv-uwbnlip3yd-webp.webp', 24 | content: '此处 bug 已经修复', 25 | time: '今天 12:30:01', 26 | }, 27 | { 28 | id: 3, 29 | type: 'message', 30 | title: '宁波', 31 | subTitle: '的回复', 32 | avatar: 33 | '//p1-arco.byteimg.com/tos-cn-i-uwbnlip3yd/3ee5f13fb09879ecb5185e440cef6eb9.png~tplv-uwbnlip3yd-webp.webp', 34 | content: '此处 bug 已经修复', 35 | time: '今天 12:20:01', 36 | }, 37 | { 38 | id: 4, 39 | type: 'notice', 40 | title: '续费通知', 41 | subTitle: '', 42 | avatar: '', 43 | content: '您的产品使用期限即将截止,如需继续使用产品请前往购…', 44 | time: '今天 12:20:01', 45 | messageType: 3, 46 | }, 47 | { 48 | id: 5, 49 | type: 'notice', 50 | title: '规则开通成功', 51 | subTitle: '', 52 | avatar: '', 53 | content: '内容屏蔽规则于 2021-12-01 开通成功并生效', 54 | time: '今天 12:20:01', 55 | messageType: 1, 56 | }, 57 | { 58 | id: 6, 59 | type: 'todo', 60 | title: '质检队列变更', 61 | subTitle: '', 62 | avatar: '', 63 | content: '内容质检队列于 2021-12-01 19:50:23 进行变更,请重新…', 64 | time: '今天 12:20:01', 65 | messageType: 0, 66 | }, 67 | ].map((item) => ({ 68 | ...item, 69 | status: haveReadIds.indexOf(item.id) === -1 ? 0 : 1, 70 | })); 71 | }; 72 | 73 | setupMock({ 74 | setup: () => { 75 | Mock.mock(new RegExp('/api/message/list'), () => { 76 | return successResponseWrap(getMessageList()); 77 | }); 78 | 79 | Mock.mock(new RegExp('/api/message/read'), (params: { body: string }) => { 80 | const { ids } = JSON.parse(params.body); 81 | haveReadIds.push(...(ids || [])); 82 | return successResponseWrap(true); 83 | }); 84 | }, 85 | }); 86 | -------------------------------------------------------------------------------- /six-arco/src/views/basic/Cron/components/form-save.vue: -------------------------------------------------------------------------------- 1 | 37 | 65 | 66 | -------------------------------------------------------------------------------- /six-go/database/models/operate_logs.go: -------------------------------------------------------------------------------- 1 | package models 2 | 3 | import ( 4 | "github.com/vainback/six-util/v3" 5 | 6 | "gorm.io/gorm" 7 | "six-go/database/db" 8 | ) 9 | 10 | var TableOperateLog OperateLog 11 | 12 | type OperateLog struct { 13 | db.MODEL 14 | db.SoftDelete 15 | TenantIdentify 16 | IP string `json:"ip"` // 客户端IP 17 | Uid int64 `json:"uid"` // 请求的用户 18 | Route string `json:"route"` // 请求的路由 19 | RouteName string `json:"route_name"` // 路由名 20 | RequestBody string `json:"request_body" gorm:"type:longtext"` // 请求body 21 | ResponseBody string `json:"response_body" gorm:"type:longtext"` // 响应body 22 | Latency string `json:"latency"` 23 | Agent string `json:"agent"` 24 | Method string `json:"method"` 25 | } 26 | 27 | func (OperateLog) TableName() string { 28 | return "operate_logs" 29 | } 30 | 31 | func (data OperateLog) HasTableName(filed string) string { 32 | return six.Strings(data.TableName(), ".", filed).String() 33 | } 34 | 35 | func (data OperateLog) KeywordFields() []string { 36 | return six.Arrays( 37 | data.HasTableName("ip"), 38 | data.HasTableName("route"), 39 | data.HasTableName("route_name"), 40 | data.HasTableName("request_body"), 41 | data.HasTableName("response_body"), 42 | ) 43 | } 44 | 45 | func (data OperateLog) FilterSqlBuilder() func(db *gorm.DB) *gorm.DB { 46 | return func(db *gorm.DB) *gorm.DB { 47 | if data.Id > 0 { 48 | return db.Where(data.HasTableName("id")+" = ?", data.Id) 49 | } 50 | if data.IP != "" { 51 | db = db.Where(data.HasTableName("ip")+" LIKE ?", "%"+data.IP+"%") 52 | } 53 | if data.Uid != 0 { 54 | db = db.Where(data.HasTableName("uid")+" = ?", data.Uid) 55 | } 56 | if data.Route != "" { 57 | db = db.Where(data.HasTableName("route")+" LIKE ?", "%"+data.Route+"%") 58 | } 59 | if data.RouteName != "" { 60 | db = db.Where(data.HasTableName("route_name")+" LIKE ?", "%"+data.RouteName+"%") 61 | } 62 | if data.RequestBody != "" { 63 | db = db.Where(data.HasTableName("request_body")+" LIKE ?", "%"+data.RequestBody+"%") 64 | } 65 | if data.ResponseBody != "" { 66 | db = db.Where(data.HasTableName("response_body")+" LIKE ?", "%"+data.ResponseBody+"%") 67 | } 68 | return db.Scopes(data.TenantIdentify.SqlBuilder(data.TableName())) 69 | } 70 | } 71 | 72 | func (data OperateLog) GetId() int64 { 73 | return data.Id 74 | } 75 | -------------------------------------------------------------------------------- /six-go/utils/rand.go: -------------------------------------------------------------------------------- 1 | package utils 2 | 3 | import ( 4 | "math/rand/v2" 5 | "strings" 6 | ) 7 | 8 | func RandMix(l int) string { 9 | if l <= 0 { 10 | return "" 11 | } 12 | chars := []string{ 13 | "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", 14 | "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", 15 | "u", "v", "w", "x", "y", "z", 16 | "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", 17 | "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", 18 | "U", "V", "W", "X", "Y", "Z", 19 | "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", 20 | } 21 | var str strings.Builder 22 | for i := 0; i < l; i++ { 23 | str.WriteString(chars[randInt(0, 61)]) 24 | } 25 | return str.String() 26 | } 27 | 28 | func RandLetter(l int) string { 29 | if l <= 0 { 30 | return "" 31 | } 32 | chars := []string{ 33 | "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", 34 | "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", 35 | "u", "v", "w", "x", "y", "z", 36 | "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", 37 | "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", 38 | "U", "V", "W", "X", "Y", "Z", 39 | } 40 | var str strings.Builder 41 | for i := 0; i < l; i++ { 42 | str.WriteString(chars[randInt(0, 51)]) 43 | } 44 | return str.String() 45 | } 46 | 47 | func RandUpper(l int) string { 48 | if l <= 0 { 49 | return "" 50 | } 51 | chars := []string{ 52 | "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", 53 | "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", 54 | "U", "V", "W", "X", "Y", "Z", 55 | } 56 | var str strings.Builder 57 | for i := 0; i < l; i++ { 58 | str.WriteString(chars[randInt(0, 25)]) 59 | } 60 | return str.String() 61 | } 62 | 63 | func RandLower(l int) string { 64 | if l <= 0 { 65 | return "" 66 | } 67 | chars := []string{ 68 | "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", 69 | "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", 70 | "u", "v", "w", "x", "y", "z", 71 | } 72 | var str strings.Builder 73 | for i := 0; i < l; i++ { 74 | str.WriteString(chars[randInt(0, 25)]) 75 | } 76 | return str.String() 77 | } 78 | 79 | func RandNumber(l int) string { 80 | if l <= 0 { 81 | return "" 82 | } 83 | chars := []string{ 84 | "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", 85 | } 86 | var str strings.Builder 87 | for i := 0; i < l; i++ { 88 | str.WriteString(chars[randInt(0, 9)]) 89 | } 90 | return str.String() 91 | } 92 | 93 | func randInt(minValue, maxValue int) int { 94 | return rand.IntN(maxValue-minValue) + minValue 95 | } 96 | -------------------------------------------------------------------------------- /six-arco/.eslintrc.js: -------------------------------------------------------------------------------- 1 | // eslint-disable-next-line @typescript-eslint/no-var-requires 2 | const path = require('path'); 3 | 4 | module.exports = { 5 | root: true, 6 | parser: 'vue-eslint-parser', 7 | parserOptions: { 8 | // Parser that checks the content of the