@@ -24,12 +24,12 @@ user:
|
|||||||
file:
|
file:
|
||||||
maxSize: 52428800
|
maxSize: 52428800
|
||||||
pahts:
|
pahts:
|
||||||
avatar: "./data/avatar/"
|
avatar: "data/static/avatar/"
|
||||||
image: "./data/upload/image/"
|
image: "data/upload/image/"
|
||||||
video: "./data/upload/video/"
|
video: "data/upload/video/"
|
||||||
music: "./data/upload/music/"
|
music: "data/upload/music/"
|
||||||
pdf: "./data/upload/pdf/"
|
pdf: "data/upload/pdf/"
|
||||||
other: "./data/upload/other/"
|
other: "data/upload/other/"
|
||||||
|
|
||||||
allowImageMime:
|
allowImageMime:
|
||||||
image/jpeg: ".jpeg"
|
image/jpeg: ".jpeg"
|
||||||
|
|||||||
@@ -9,6 +9,11 @@
|
|||||||
"userEmailFormatError":-43,
|
"userEmailFormatError":-43,
|
||||||
"userCookieError":-44,
|
"userCookieError":-44,
|
||||||
"userCookieNotFund":-44,
|
"userCookieNotFund":-44,
|
||||||
"userCookieExpired":-44
|
"userCookieExpired":-44,
|
||||||
|
"file_mime_err":-51,
|
||||||
|
"file_size_err":-52,
|
||||||
|
"file_name_err":-53,
|
||||||
|
"file_get_err":-54
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -68,6 +68,17 @@ func main() {
|
|||||||
models.ConfigAllInit()
|
models.ConfigAllInit()
|
||||||
routers.ApiInit()
|
routers.ApiInit()
|
||||||
|
|
||||||
|
//创建必要目录
|
||||||
|
for _, path := range models.ConfigsFile.Pahts {
|
||||||
|
fmt.Println(path)
|
||||||
|
err := os.MkdirAll(path, 0755)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("创建文件夹失败: %v\n", err)
|
||||||
|
panic("创建文件夹失败")
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
//启动gin服务
|
//启动gin服务
|
||||||
r := gin.Default()
|
r := gin.Default()
|
||||||
|
|
||||||
|
|||||||
@@ -4,8 +4,6 @@ import "github.com/mitchellh/mapstructure"
|
|||||||
|
|
||||||
var Configs map[string]interface{}
|
var Configs map[string]interface{}
|
||||||
|
|
||||||
//mime信息转换位拓展名
|
|
||||||
|
|
||||||
type ConfigsWeb_ struct {
|
type ConfigsWeb_ struct {
|
||||||
Host string `mapstructure:"host"`
|
Host string `mapstructure:"host"`
|
||||||
Port string `mapstructure:"port"`
|
Port string `mapstructure:"port"`
|
||||||
|
|||||||
+47
-1
@@ -1,6 +1,13 @@
|
|||||||
package models
|
package models
|
||||||
|
|
||||||
import "os"
|
import (
|
||||||
|
"crypto"
|
||||||
|
"encoding/hex"
|
||||||
|
"io"
|
||||||
|
"mime/multipart"
|
||||||
|
"net/http"
|
||||||
|
"os"
|
||||||
|
)
|
||||||
|
|
||||||
// 判断文件是否存在
|
// 判断文件是否存在
|
||||||
func FileExists(path string) bool {
|
func FileExists(path string) bool {
|
||||||
@@ -10,3 +17,42 @@ func FileExists(path string) bool {
|
|||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 计算文件的哈希
|
||||||
|
func SHA256HashFile(file_head *multipart.FileHeader) (string, error) {
|
||||||
|
// 打开文件
|
||||||
|
file, err := file_head.Open()
|
||||||
|
if err != nil {
|
||||||
|
return "foen error", err
|
||||||
|
}
|
||||||
|
defer file.Close()
|
||||||
|
|
||||||
|
hasher := crypto.SHA256.New()
|
||||||
|
|
||||||
|
// 从文件流中读取并计算哈希
|
||||||
|
_, err = io.Copy(hasher, file)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
hashBytes := hasher.Sum(nil)
|
||||||
|
return hex.EncodeToString(hashBytes), nil
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取文件mime
|
||||||
|
func GetFileMime(file_head *multipart.FileHeader) (string, error) {
|
||||||
|
file, err := file_head.Open()
|
||||||
|
if err != nil {
|
||||||
|
return "foen error", err
|
||||||
|
}
|
||||||
|
defer file.Close()
|
||||||
|
|
||||||
|
// 读取前512字节用于MIME检测
|
||||||
|
buffer := make([]byte, 512)
|
||||||
|
io.ReadFull(file, buffer)
|
||||||
|
mimeType := http.DetectContentType(buffer)
|
||||||
|
|
||||||
|
return mimeType, nil
|
||||||
|
|
||||||
|
}
|
||||||
|
|||||||
@@ -50,6 +50,7 @@ func SeparateData(ctx *gin.Context) (map[string]interface{}, string) {
|
|||||||
|
|
||||||
func ApiRoot(r *gin.RouterGroup) {
|
func ApiRoot(r *gin.RouterGroup) {
|
||||||
|
|
||||||
|
ApiStatic(r.Group("/static"))
|
||||||
ApiUser(r.Group("/users"))
|
ApiUser(r.Group("/users"))
|
||||||
|
|
||||||
r.GET("/", func(ctx *gin.Context) {
|
r.GET("/", func(ctx *gin.Context) {
|
||||||
|
|||||||
@@ -0,0 +1,25 @@
|
|||||||
|
package routers
|
||||||
|
|
||||||
|
import (
|
||||||
|
"ops/models"
|
||||||
|
"path"
|
||||||
|
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
)
|
||||||
|
|
||||||
|
//处理api的静态内容
|
||||||
|
|
||||||
|
func ApiStatic(r *gin.RouterGroup) {
|
||||||
|
r.GET("/avatar/:filename", func(ctx *gin.Context) {
|
||||||
|
filename := ctx.Param("filename")
|
||||||
|
dst := path.Join(models.ConfigsFile.Pahts["avatar"], filename)
|
||||||
|
if models.FileExists(dst) {
|
||||||
|
ctx.File(dst)
|
||||||
|
} else {
|
||||||
|
//找不到文件
|
||||||
|
ctx.String(404, "file not found")
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
})
|
||||||
|
}
|
||||||
+114
-1
@@ -1,8 +1,10 @@
|
|||||||
package routers
|
package routers
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"ops/models"
|
"ops/models"
|
||||||
|
"path"
|
||||||
"strconv"
|
"strconv"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@@ -80,6 +82,33 @@ type From_user_changepass struct {
|
|||||||
Newpass string `json:"newpass"`
|
Newpass string `json:"newpass"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func AuthenticationAuthorityFromCookie(c string) (*models.TabUser_, error) {
|
||||||
|
|
||||||
|
if c != "" {
|
||||||
|
cookie := models.TabCookie_{
|
||||||
|
Value: c,
|
||||||
|
}
|
||||||
|
if models.DB.Where(&cookie).First(&cookie).Error == nil {
|
||||||
|
//找到cookie,验证cookie有效性,以及更新cookie
|
||||||
|
if models.CheckCookiesAndUpdate(&cookie) {
|
||||||
|
//cookie有效
|
||||||
|
//载入user
|
||||||
|
user := models.TabUser_{
|
||||||
|
ID: cookie.UserID,
|
||||||
|
}
|
||||||
|
models.DB.Where(&user).First(&user)
|
||||||
|
return &user, nil
|
||||||
|
} else {
|
||||||
|
return nil, errors.New("cookie 过期")
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return nil, errors.New("cookie Not Fund")
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return nil, errors.New("cookie 参数错误")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func AuthenticationAuthority(ctx *gin.Context) (bool, models.TabUser_, map[string]interface{}) {
|
func AuthenticationAuthority(ctx *gin.Context) (bool, models.TabUser_, map[string]interface{}) {
|
||||||
var user models.TabUser_
|
var user models.TabUser_
|
||||||
|
|
||||||
@@ -187,8 +216,92 @@ func ApiUser(r *gin.RouterGroup) {
|
|||||||
|
|
||||||
//修改用户头像
|
//修改用户头像
|
||||||
r.POST("/updateAvatar", func(ctx *gin.Context) {
|
r.POST("/updateAvatar", func(ctx *gin.Context) {
|
||||||
|
cookie := ctx.PostForm("cookie")
|
||||||
|
user, err := AuthenticationAuthorityFromCookie(cookie)
|
||||||
|
if err == nil {
|
||||||
|
file, err := ctx.FormFile("file")
|
||||||
|
if err == nil {
|
||||||
|
if file.Filename != "" {
|
||||||
|
//限制文件大小
|
||||||
|
if file.Size > 512 {
|
||||||
|
//头像裁剪过限制1M应该差不多
|
||||||
|
if file.Size < 1048576 {
|
||||||
|
|
||||||
|
//判断mime
|
||||||
|
mimeType, err := models.GetFileMime(file)
|
||||||
|
if err == nil {
|
||||||
|
|
||||||
|
file_extname := models.ConfigsFile.AllowImageMime[mimeType]
|
||||||
|
if file_extname != "" {
|
||||||
|
|
||||||
|
//haxi文件
|
||||||
|
|
||||||
|
file_hashi_name, err := models.SHA256HashFile(file)
|
||||||
|
if err == nil {
|
||||||
|
|
||||||
|
dst := path.Join(models.ConfigsFile.Pahts["avatar"], file_hashi_name+file_extname)
|
||||||
|
|
||||||
|
var is_save_ok = false
|
||||||
|
//判断文件是否存在避免重复保存
|
||||||
|
if models.FileExists(dst) {
|
||||||
|
//fmt.Println("文件存在")
|
||||||
|
is_save_ok = true
|
||||||
|
ReturnJson(ctx, "apiOK", nil)
|
||||||
|
} else {
|
||||||
|
//fmt.Println("文件no存在")
|
||||||
|
ferr := ctx.SaveUploadedFile(file, dst)
|
||||||
|
if ferr == nil {
|
||||||
|
//文件保存成功
|
||||||
|
//fmt.Print("save_ok")
|
||||||
|
is_save_ok = true
|
||||||
|
ReturnJson(ctx, "apiOK", nil)
|
||||||
|
} else {
|
||||||
|
fmt.Print(ferr)
|
||||||
|
ReturnJson(ctx, "postErr", nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
if is_save_ok {
|
||||||
|
//修改数据库内容
|
||||||
|
var user_info_fund models.TabUserInfo_
|
||||||
|
user_info_fund.UserID = user.ID
|
||||||
|
|
||||||
|
var user_update_avatar models.TabUserInfo_
|
||||||
|
user_update_avatar.AvatarPath = file_hashi_name + file_extname
|
||||||
|
|
||||||
|
models.DB.Where(&user_info_fund).Updates(&user_update_avatar)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
ReturnJson(ctx, "postErr", nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
ReturnJson(ctx, "file_mime_err", nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
ReturnJson(ctx, "postErr", nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
ReturnJson(ctx, "file_size_err", nil)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
ReturnJson(ctx, "file_size_err", nil)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
ReturnJson(ctx, "file_name_err", nil)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
ReturnJson(ctx, "file_get_err", nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
ReturnJson(ctx, "userCookieError", nil)
|
||||||
|
}
|
||||||
|
|
||||||
ReturnJson(ctx, "jsonErr", nil)
|
|
||||||
})
|
})
|
||||||
|
|
||||||
//更新用户info
|
//更新用户info
|
||||||
|
|||||||
@@ -22,3 +22,13 @@ func ReturnJson(ctx *gin.Context, errMsg string, data map[string]interface{}) {
|
|||||||
//ctx.Abort()
|
//ctx.Abort()
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func Return_file(ctx *gin.Context, file_path string, preview bool) {
|
||||||
|
if preview {
|
||||||
|
ctx.File(file_path)
|
||||||
|
} else {
|
||||||
|
//需要从数据库拉取原始文件名
|
||||||
|
//ctx.FileAttachment(file_info.Path, file_info.Name)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,4 +1,10 @@
|
|||||||
{
|
{
|
||||||
|
"errorpage": {
|
||||||
|
"404_title": "404 Resource Not Found",
|
||||||
|
"404_msg_title": "Oops… You just found an error page",
|
||||||
|
"404_msg": "We are sorry but the page you are looking for was not found",
|
||||||
|
"404_back_home": "Take me home"
|
||||||
|
},
|
||||||
"appname": {
|
"appname": {
|
||||||
"home": "Home",
|
"home": "Home",
|
||||||
"login": "Login",
|
"login": "Login",
|
||||||
@@ -106,9 +112,9 @@
|
|||||||
},
|
},
|
||||||
"settings": {
|
"settings": {
|
||||||
"cancel": "Cancel",
|
"cancel": "Cancel",
|
||||||
"basic_information":"Basic Information",
|
"basic_information": "Basic Information",
|
||||||
"contact_information":"Contact Information",
|
"contact_information": "Contact Information",
|
||||||
"security_settings":"Security Settings",
|
"security_settings": "Security Settings",
|
||||||
"account_settings": "Account Settings",
|
"account_settings": "Account Settings",
|
||||||
"my_account": "My Account",
|
"my_account": "My Account",
|
||||||
"profile_information": "Profile Information",
|
"profile_information": "Profile Information",
|
||||||
|
|||||||
@@ -1,60 +1,66 @@
|
|||||||
{
|
{
|
||||||
|
"errorpage": {
|
||||||
|
"404_title": "404 资源未找到",
|
||||||
|
"404_msg_title": "抱歉…您刚刚发现了一个错误页面",
|
||||||
|
"404_msg": "您所查找的页面不存在",
|
||||||
|
"404_back_home": "返回首页"
|
||||||
|
},
|
||||||
"appname": {
|
"appname": {
|
||||||
"home": "主页",
|
"home": "主页",
|
||||||
"login": "登录",
|
"login": "登录",
|
||||||
"forgot_password": "忘记密码",
|
"forgot_password": "忘记密码",
|
||||||
"register": "注册",
|
"register": "注册",
|
||||||
"schedule":"日程",
|
"schedule": "日程",
|
||||||
"purchase":"采购",
|
"purchase": "采购",
|
||||||
"warehouse":"仓库"
|
"warehouse": "仓库"
|
||||||
},
|
},
|
||||||
"cropper": {
|
"cropper": {
|
||||||
"select_image": "选择图片",
|
"select_image": "选择图片",
|
||||||
"select_File": "选择文件",
|
"select_File": "选择文件",
|
||||||
"crop_image": "裁剪图片",
|
"crop_image": "裁剪图片",
|
||||||
"cancel": "取消",
|
"cancel": "取消",
|
||||||
"closs": "关闭"
|
"closs": "关闭"
|
||||||
},
|
},
|
||||||
"purchase":{
|
"purchase": {
|
||||||
"purchase_list":"采购列表",
|
"purchase_list": "采购列表",
|
||||||
"item_name":"物品名称",
|
"item_name": "物品名称",
|
||||||
"purpose":"用途",
|
"purpose": "用途",
|
||||||
"unit":"单位",
|
"unit": "单位",
|
||||||
"quantity":"数量",
|
"quantity": "数量",
|
||||||
"unit_price":"单价",
|
"unit_price": "单价",
|
||||||
"total_price":"总价",
|
"total_price": "总价",
|
||||||
"created_at":"创建日期",
|
"created_at": "创建日期",
|
||||||
"updated_at":"更新日期",
|
"updated_at": "更新日期",
|
||||||
"status":"状态",
|
"status": "状态",
|
||||||
"completed":"已完成",
|
"completed": "已完成",
|
||||||
"pending":"待处理",
|
"pending": "待处理",
|
||||||
"show":"显示",
|
"show": "显示",
|
||||||
"entries":"个物件",
|
"entries": "个物件",
|
||||||
"search":"搜索",
|
"search": "搜索",
|
||||||
"add_part":"添加订单",
|
"add_part": "添加订单",
|
||||||
"exp_report":"生成报告"
|
"exp_report": "生成报告"
|
||||||
},
|
},
|
||||||
"schedule": {
|
"schedule": {
|
||||||
"my_schedule":"我的日程",
|
"my_schedule": "我的日程",
|
||||||
"add_event":"添加事件",
|
"add_event": "添加事件",
|
||||||
"event_title":"事件标题",
|
"event_title": "事件标题",
|
||||||
"event_date":"事件日期",
|
"event_date": "事件日期",
|
||||||
"event_time":"事件时间",
|
"event_time": "事件时间",
|
||||||
"event_description":"事件描述",
|
"event_description": "事件描述",
|
||||||
"save_event":"保存事件",
|
"save_event": "保存事件",
|
||||||
"no_events":"没有找到事件",
|
"no_events": "没有找到事件",
|
||||||
"delete_event":"删除事件",
|
"delete_event": "删除事件",
|
||||||
"edit_event":"编辑事件",
|
"edit_event": "编辑事件",
|
||||||
"tody":"今天",
|
"tody": "今天",
|
||||||
"week":"本周",
|
"week": "本周",
|
||||||
"month":"本月",
|
"month": "本月",
|
||||||
"previous_month":"上月",
|
"previous_month": "上月",
|
||||||
"next_month":"下月",
|
"next_month": "下月",
|
||||||
"previous_year":"上年",
|
"previous_year": "上年",
|
||||||
"next_year":"下年"
|
"next_year": "下年"
|
||||||
},
|
},
|
||||||
"message": {
|
"message": {
|
||||||
"functionality_not_yet_developed":"功能未开发",
|
"functionality_not_yet_developed": "功能未开发",
|
||||||
"hello": "你好",
|
"hello": "你好",
|
||||||
"welcome": "欢迎",
|
"welcome": "欢迎",
|
||||||
"dark_mode": "深色模式",
|
"dark_mode": "深色模式",
|
||||||
@@ -95,20 +101,20 @@
|
|||||||
"user_settings": "个人资料",
|
"user_settings": "个人资料",
|
||||||
"preferences": "偏好设置",
|
"preferences": "偏好设置",
|
||||||
"administrator": "管理员",
|
"administrator": "管理员",
|
||||||
"select_date":"选择日期",
|
"select_date": "选择日期",
|
||||||
"save_ok":"保存成功",
|
"save_ok": "保存成功",
|
||||||
"change_ok":"更改成功",
|
"change_ok": "更改成功",
|
||||||
"type_old_pass":"输入旧密码",
|
"type_old_pass": "输入旧密码",
|
||||||
"type_new_pass":"输入新密码",
|
"type_new_pass": "输入新密码",
|
||||||
"type_cof_pass":"确认新密码",
|
"type_cof_pass": "确认新密码",
|
||||||
"old_pass_incorrect":"旧密码不正确",
|
"old_pass_incorrect": "旧密码不正确",
|
||||||
"confirm_password_incorrect":"确认密码不正确"
|
"confirm_password_incorrect": "确认密码不正确"
|
||||||
},
|
},
|
||||||
"settings": {
|
"settings": {
|
||||||
"cancel": "取消",
|
"cancel": "取消",
|
||||||
"basic_information":"基本信息",
|
"basic_information": "基本信息",
|
||||||
"contact_information":"联系信息",
|
"contact_information": "联系信息",
|
||||||
"security_settings":"安全设置",
|
"security_settings": "安全设置",
|
||||||
"account_settings": "个人设置",
|
"account_settings": "个人设置",
|
||||||
"my_account": "我的账户",
|
"my_account": "我的账户",
|
||||||
"profile_information": "个人信息",
|
"profile_information": "个人信息",
|
||||||
@@ -122,7 +128,7 @@
|
|||||||
"female": "女",
|
"female": "女",
|
||||||
"birthday": "生日",
|
"birthday": "生日",
|
||||||
"admin": "管理员",
|
"admin": "管理员",
|
||||||
"website_settings":"网站设置",
|
"website_settings": "网站设置",
|
||||||
"site_name": "网站名称",
|
"site_name": "网站名称",
|
||||||
"logo_settings": "Logo设置",
|
"logo_settings": "Logo设置",
|
||||||
"site_description": "网站描述",
|
"site_description": "网站描述",
|
||||||
|
|||||||
@@ -13,6 +13,11 @@ const router = createRouter({
|
|||||||
name: "home",
|
name: "home",
|
||||||
component: HomeView,
|
component: HomeView,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
path: "/404",
|
||||||
|
name: "404",
|
||||||
|
component: () => import("../views/404.vue"),
|
||||||
|
},
|
||||||
{
|
{
|
||||||
path: "/settings/account",
|
path: "/settings/account",
|
||||||
name: "settings account",
|
name: "settings account",
|
||||||
@@ -70,13 +75,18 @@ const router = createRouter({
|
|||||||
{
|
{
|
||||||
path: "/purchase",
|
path: "/purchase",
|
||||||
name: "purchase",
|
name: "purchase",
|
||||||
component: () => import("../views/purchaseView.vue"),
|
component: () => import("../views/purchase/purchase.vue"),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
path: "/purchase/addorder",
|
||||||
|
name: "purchase",
|
||||||
|
component: () => import("../views/purchase/addorder.vue"),
|
||||||
|
},
|
||||||
|
{
|
||||||
path: "/warehouse",
|
path: "/warehouse",
|
||||||
name: "warehouse",
|
name: "warehouse",
|
||||||
component: () => import("../views/warehouse.vue"),
|
component: () => import("../views/warehouse.vue"),
|
||||||
}
|
},
|
||||||
],
|
],
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -41,7 +41,7 @@ export const useUserStore = defineStore("user", () => {
|
|||||||
const getUserAvatarPath = () => {
|
const getUserAvatarPath = () => {
|
||||||
if (userInfo.value != null) {
|
if (userInfo.value != null) {
|
||||||
if (userInfo.value.AvatarPath != "") {
|
if (userInfo.value.AvatarPath != "") {
|
||||||
return userInfo.value.AvatarPath;
|
return "/api/static/avatar/"+userInfo.value.AvatarPath;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return "/ava.svg";
|
return "/ava.svg";
|
||||||
|
|||||||
@@ -0,0 +1,59 @@
|
|||||||
|
<script setup>
|
||||||
|
import { onMounted, watch, ref } from "vue";
|
||||||
|
import { useI18n } from "vue-i18n";
|
||||||
|
import { useRouter } from "vue-router";
|
||||||
|
const { t, locale } = useI18n();
|
||||||
|
|
||||||
|
function functionupdataTitle() {
|
||||||
|
document.title = "Operations." + t("errorpage.404_title");
|
||||||
|
}
|
||||||
|
|
||||||
|
// 监听语言变化,更新标题
|
||||||
|
watch(locale, () => {
|
||||||
|
functionupdataTitle();
|
||||||
|
});
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
//console.log("account mounted");
|
||||||
|
//username.value.value="Kevin";
|
||||||
|
functionupdataTitle();
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<div class="page page-center">
|
||||||
|
<div class="container-tight py-4">
|
||||||
|
<div class="empty">
|
||||||
|
<div class="empty-header">404</div>
|
||||||
|
<p class="empty-title">{{ t("errorpage.404_msg_title") }}</p>
|
||||||
|
<p class="empty-subtitle text-secondary">
|
||||||
|
{{ t("errorpage.404_msg") }}
|
||||||
|
</p>
|
||||||
|
<div class="empty-action">
|
||||||
|
<router-link to="/" class="btn btn-primary">
|
||||||
|
<!-- Download SVG icon from http://tabler-icons.io/i/arrow-left -->
|
||||||
|
<svg
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
class="icon"
|
||||||
|
width="24"
|
||||||
|
height="24"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
stroke-width="2"
|
||||||
|
stroke="currentColor"
|
||||||
|
fill="none"
|
||||||
|
stroke-linecap="round"
|
||||||
|
stroke-linejoin="round"
|
||||||
|
>
|
||||||
|
<path stroke="none" d="M0 0h24v24H0z" fill="none" />
|
||||||
|
<path d="M5 12l14 0" />
|
||||||
|
<path d="M5 12l6 6" />
|
||||||
|
<path d="M5 12l6 -6" />
|
||||||
|
</svg>
|
||||||
|
{{ t("errorpage.404_back_home") }}
|
||||||
|
</router-link>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
<script setup>
|
||||||
|
import { onMounted, watch, ref } from "vue";
|
||||||
|
import { useI18n } from "vue-i18n";
|
||||||
|
|
||||||
|
const { t, locale } = useI18n();
|
||||||
|
|
||||||
|
function functionupdataTitle() {
|
||||||
|
document.title = "Operations." + t("purchase.add_part");
|
||||||
|
}
|
||||||
|
onMounted(() => {
|
||||||
|
functionupdataTitle();
|
||||||
|
});
|
||||||
|
// 监听语言变化,更新标题
|
||||||
|
watch(locale, () => {
|
||||||
|
functionupdataTitle();
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
add_part
|
||||||
|
</template>
|
||||||
+36
-44
@@ -17,17 +17,15 @@ watch(locale, () => {
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
|
||||||
<div class="col-12">
|
<div class="col-12">
|
||||||
<div class="card">
|
<div class="card">
|
||||||
<div class="card-header">
|
<div class="card-header">
|
||||||
<h3 class="card-title">{{ t('purchase.purchase_list') }}</h3>
|
<h3 class="card-title">{{ t("purchase.purchase_list") }}</h3>
|
||||||
</div>
|
</div>
|
||||||
<div class="card-body border-bottom py-3">
|
<div class="card-body border-bottom py-3">
|
||||||
<div class="d-flex">
|
<div class="d-flex">
|
||||||
|
|
||||||
<div class="text-secondary">
|
<div class="text-secondary">
|
||||||
{{ t('purchase.show') }}
|
{{ t("purchase.show") }}
|
||||||
<div class="mx-2 d-inline-block">
|
<div class="mx-2 d-inline-block">
|
||||||
<input
|
<input
|
||||||
type="text"
|
type="text"
|
||||||
@@ -37,17 +35,19 @@ watch(locale, () => {
|
|||||||
aria-label="Invoices count"
|
aria-label="Invoices count"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
{{ t('purchase.entries') }}
|
{{ t("purchase.entries") }}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="ms-auto text-secondary">
|
<div class="ms-auto text-secondary">
|
||||||
<button class="btn btn-info m-1">{{ t('purchase.add_part') }}</button>
|
<router-link to="/purchase/addorder" class="btn btn-info m-1">
|
||||||
<button class="btn m-1">{{ t('purchase.exp_report') }}</button>
|
{{ t("purchase.add_part") }}
|
||||||
|
</router-link>
|
||||||
|
|
||||||
|
<button class="btn m-1">{{ t("purchase.exp_report") }}</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
<div class="ms-auto text-secondary">
|
<div class="ms-auto text-secondary">
|
||||||
{{ t('purchase.search') }}
|
{{ t("purchase.search") }}
|
||||||
<div class="ms-2 d-inline-block mr-2">
|
<div class="ms-2 d-inline-block mr-2">
|
||||||
<input
|
<input
|
||||||
type="text"
|
type="text"
|
||||||
@@ -55,7 +55,6 @@ watch(locale, () => {
|
|||||||
aria-label="Search invoice"
|
aria-label="Search invoice"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -89,46 +88,39 @@ watch(locale, () => {
|
|||||||
<path d="M6 15l6 -6l6 6" />
|
<path d="M6 15l6 -6l6 6" />
|
||||||
</svg>
|
</svg>
|
||||||
</th>
|
</th>
|
||||||
<th class="col-5">{{ t('purchase.item_name') }}</th>
|
<th class="col-5">{{ t("purchase.item_name") }}</th>
|
||||||
<th class="col-1">{{ t('purchase.purpose') }}</th>
|
<th class="col-1">{{ t("purchase.purpose") }}</th>
|
||||||
<th class="w-1">{{ t('purchase.unit') }}</th>
|
<th class="w-1">{{ t("purchase.unit") }}</th>
|
||||||
<th class="w-1">{{ t('purchase.quantity') }}</th>
|
<th class="w-1">{{ t("purchase.quantity") }}</th>
|
||||||
<th class="w-1">{{ t('purchase.unit_price') }}</th>
|
<th class="w-1">{{ t("purchase.unit_price") }}</th>
|
||||||
<th class="w-1">{{ t('purchase.total_price') }}</th>
|
<th class="w-1">{{ t("purchase.total_price") }}</th>
|
||||||
<th class="w-1">{{ t('purchase.created_at') }}</th>
|
<th class="w-1">{{ t("purchase.created_at") }}</th>
|
||||||
<th class="w-1">{{ t('purchase.updated_at') }}</th>
|
<th class="w-1">{{ t("purchase.updated_at") }}</th>
|
||||||
<th class="w-1">{{ t('purchase.status') }}</th>
|
<th class="w-1">{{ t("purchase.status") }}</th>
|
||||||
<th class="w-1"></th>
|
<th class="w-1"></th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
<tr>
|
<tr>
|
||||||
<td>
|
<td>
|
||||||
<input
|
<input
|
||||||
class="form-check-input m-0 align-middle"
|
class="form-check-input m-0 align-middle"
|
||||||
type="checkbox"
|
type="checkbox"
|
||||||
aria-label="Select invoice"
|
aria-label="Select invoice"
|
||||||
/>
|
/>
|
||||||
</td>
|
</td>
|
||||||
<td><span class="text-muted">001</span></td>
|
<td><span class="text-muted">001</span></td>
|
||||||
<td>
|
<td>办公室用纸</td>
|
||||||
办公室用纸
|
<td>办公用品</td>
|
||||||
</td>
|
<td>包</td>
|
||||||
<td>办公用品</td>
|
<td>10</td>
|
||||||
<td>包</td>
|
<td>15.00</td>
|
||||||
<td>10</td>
|
<td>150.00</td>
|
||||||
<td>15.00</td>
|
<td>2024-06-01</td>
|
||||||
<td>150.00</td>
|
<td>2024-06-05</td>
|
||||||
<td>2024-06-01</td>
|
<td><span class="badge bg-success me-1"></span> 已完成</td>
|
||||||
<td>2024-06-05</td>
|
<td class="text-end"></td>
|
||||||
<td>
|
|
||||||
<span class="badge bg-success me-1"></span> 已完成
|
|
||||||
</td>
|
|
||||||
<td class="text-end">
|
|
||||||
|
|
||||||
</td>
|
|
||||||
</tr>
|
</tr>
|
||||||
|
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
Reference in New Issue
Block a user