feat: PhotoWall 毕业照存储系统初始版本

后端: Go(Gin+GORM+MySQL+Redis)
- 17张业务表(yz_pw_前缀), 自动迁移
- JWT认证(3小时) + 盐+MD5密码 + 图形验证码
- 班级CRUD/加入(8人姓名验证/邀请码)/审核/30天自动清理
- 系统配置(16项)/菜单管理(动态路由)/数据统计
- 文件MD5去重/数据隔离/账号封禁/敏感词DFA检测

前端: Vue3+Vite+Element Plus+Less+ECharts+FontAwesome
- 动态路由(数据库菜单驱动)
- 蓝白配色, H5响应式
- 登录/注册/忘记密码/个人中心
- 班级创建向导/详情/加入/列表
- 管理后台: 审核/配置/菜单/统计/用户/敏感词

数据库: MySQL 10.31.100.3:3306/photowall
管理员: hero920103 / 920103
This commit is contained in:
hero920103
2026-09-03 05:55:23 +08:00
commit 57d9866dab
82 changed files with 12668 additions and 0 deletions
+111
View File
@@ -0,0 +1,111 @@
package config
import (
"os"
"strconv"
)
// Config 全局配置,优先从环境变量读取,提供默认值以便开箱即用。
type Config struct {
Port string
JWTSecret string
JWTExpireHrs int
UploadDir string
// MySQL
DBHost string
DBPort string
DBUser string
DBPassword string
DBName string
DBCharset string
// 平台管理员账号(首次启动自动创建)
AdminUsername string
AdminPassword string
// 班级审核补齐期限(天),逾期自动删除
AuditGraceDays int
// 极验行为验证(参数后期补,为空则跳过极验校验)
GeeTestID string
GeeTestKey string
// 短信验证码(参数后期补,为空则短信接口返回配置缺失)
SMSProvider string // aliyun / tencent
SMSAccessKey string
SMSSecretKey string
SMSSignName string
SMSTemplateCode string
// 微信扫码登录(参数后期补,为空则微信接口返回配置缺失)
WechatAppID string
WechatAppSecret string
WechatRedirectURI string
// Redis(缓存/验证码/限流,连接失败自动降级内存)
RedisHost string
RedisPort string
RedisPassword string
RedisDB int
}
var C *Config
func Load() *Config {
C = &Config{
Port: getEnv("PORT", "8010"),
JWTSecret: getEnv("JWT_SECRET", "photowall-dev-secret-change-in-prod"),
JWTExpireHrs: getEnvInt("JWT_EXPIRE_HOURS", 3),
UploadDir: getEnv("UPLOAD_DIR", "uploads"),
DBHost: getEnv("DB_HOST", "10.31.100.3"),
DBPort: getEnv("DB_PORT", "3306"),
DBUser: getEnv("DB_USER", "photowall"),
DBPassword: getEnv("DB_PASSWORD", "Dfn47yeKpyJfwz8n"),
DBName: getEnv("DB_NAME", "photowall"),
DBCharset: getEnv("DB_CHARSET", "utf8mb4"),
AdminUsername: getEnv("ADMIN_USERNAME", "hero920103"),
AdminPassword: getEnv("ADMIN_PASSWORD", "920103"),
AuditGraceDays: getEnvInt("AUDIT_GRACE_DAYS", 30),
// 极验(后期补参数)
GeeTestID: getEnv("GEETEST_ID", ""),
GeeTestKey: getEnv("GEETEST_KEY", ""),
// 短信(后期补参数)
SMSProvider: getEnv("SMS_PROVIDER", "aliyun"),
SMSAccessKey: getEnv("SMS_ACCESS_KEY", ""),
SMSSecretKey: getEnv("SMS_SECRET_KEY", ""),
SMSSignName: getEnv("SMS_SIGN_NAME", ""),
SMSTemplateCode: getEnv("SMS_TEMPLATE_CODE", ""),
// 微信扫码登录(后期补参数)
WechatAppID: getEnv("WECHAT_APP_ID", ""),
WechatAppSecret: getEnv("WECHAT_APP_SECRET", ""),
WechatRedirectURI: getEnv("WECHAT_REDIRECT_URI", ""),
// Redis
RedisHost: getEnv("REDIS_HOST", "localhost"),
RedisPort: getEnv("REDIS_PORT", "6379"),
RedisPassword: getEnv("REDIS_PASSWORD", ""),
RedisDB: getEnvInt("REDIS_DB", 0),
}
return C
}
// DSN 生成 MySQL 连接串
func (c *Config) DSN() string {
return c.DBUser + ":" + c.DBPassword + "@tcp(" + c.DBHost + ":" + c.DBPort + ")/" +
c.DBName + "?charset=" + c.DBCharset + "&parseTime=True&loc=Local"
}
func getEnv(key, def string) string {
if v := os.Getenv(key); v != "" {
return v
}
return def
}
func getEnvInt(key string, def int) int {
if v := os.Getenv(key); v != "" {
if n, err := strconv.Atoi(v); err == nil {
return n
}
}
return def
}