@@ -0,0 +1,15 @@ | |||
FROM golang:latest | |||
WORKDIR /app | |||
COPY . . | |||
RUN #go env -w GO111MODULE=off | |||
RUN apt-get update && apt-get install -y tzdata | |||
ENV TZ=Asia/Shanghai | |||
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone | |||
RUN go env -w GOPROXY=https://goproxy.cn,direct | |||
RUN go build -o staff-sync | |||
EXPOSE 18080 | |||
CMD ["./staff-sync"] |
@@ -0,0 +1,6 @@ | |||
runtime: go120 | |||
api_version: go1 | |||
handlers: | |||
- url: /.* | |||
script: _go_app |
@@ -0,0 +1,8 @@ | |||
#!/bin/bash | |||
# 重新构建docker镜像 | |||
sudo docker build -t staff-sync . | |||
sudo mkdir -p /home/digimeta/staff-sync | |||
# 运行生成的docker镜像 | |||
sudo docker run --add-host='oa.dfwytech.net:10.1.31.231' -v /home/digimeta/staff-sync/logs:/app/logs -v /home/digimeta/staff-sync/config.json:/app/config.json --restart=always -p 48480:18080 --name staff-sync -d staff-sync | |||
sudo tail -f -n 500 /home/digimeta/logs/web.log |
@@ -0,0 +1,896 @@ | |||
package business | |||
/** | |||
* @Author: yk | |||
* @Date: 2024/01/30 15:04 | |||
* @Desc: 外部接口实现,关于人员的接口 | |||
*/ | |||
import ( | |||
"bytes" | |||
"digimetastaffsync/common" | |||
"digimetastaffsync/mydatabase" | |||
"encoding/json" | |||
"errors" | |||
"fmt" | |||
"io" | |||
"mime/multipart" | |||
"net/http" | |||
"os" | |||
"sort" | |||
"strconv" | |||
"strings" | |||
"time" | |||
) | |||
var timeStep int | |||
func init() { | |||
common.LoadConfig() | |||
//初始化时间步长时间步长 | |||
timeStep = common.ConfigData.Timer | |||
} | |||
type FeatureResp struct { | |||
Status int `json:"status"` | |||
Message string `json:"message"` | |||
Result []interface{} `json:"result"` | |||
} | |||
type Staff struct { | |||
ID string `json:"id"` | |||
Name string `json:"name"` | |||
NickName string `json:"nickName"` | |||
Phone string `json:"phone"` | |||
Type int `json:"type"` | |||
Url string `json:"Url"` | |||
Image string `json:"image"` | |||
} | |||
type Req struct { | |||
Code string `json:"code"` | |||
StaffName string `json:"staffName"` | |||
StaffType int `json:"staffType"` | |||
Gender int `json:"gender"` | |||
DevId string `json:"devId"` | |||
FaceFeature string `json:"faceFeature"` | |||
HireDate string `json:"hireDate"` | |||
Birthday string `json:"birthDate"` | |||
Phone string `json:"phone"` | |||
StaffBase64Img string `json:"staffBase64Img"` | |||
DelFlag int `json:"status"` | |||
Modified string `json:"modified"` | |||
} | |||
func RegStaff(param Req) (*common.Response, error) { | |||
url := common.ConfigData.PushDataUrl | |||
common.Info(common.GenLogLine()+"reg staff url:%s\n", url) | |||
method := "POST" | |||
param.DevId = common.ConfigData.DevId | |||
if len(param.StaffBase64Img) < 20000 { | |||
param.StaffBase64Img = "" | |||
} | |||
fmt.Printf("code:%s, staffName:%s, staffType:%d, gender:%d, devId:%s, faceFeature:%s, hireDate:%s, birthday:%s, phone:%s, DelFlag:%d, modified:%s\n", | |||
param.Code, param.StaffName, param.StaffType, param.Gender, param.DevId, param.FaceFeature, param.HireDate, param.Birthday, param.Phone, param.DelFlag, param.Modified) | |||
common.Info(common.GenLogLine()+"exec reg code:%s, staffName:%s, staffType:%d, gender:%d, devId:%s, faceFeature:%s, hireDate:%s, birthday:%s, phone:%s, DelFlag:%d, modified:%s\n", | |||
param.Code, param.StaffName, param.StaffType, param.Gender, param.DevId, param.FaceFeature, param.HireDate, param.Birthday, param.Phone, param.DelFlag, param.Modified) | |||
fmt.Println() | |||
jsonData, err := json.Marshal(param) | |||
if err != nil { | |||
fmt.Println("Error marshaling JSON:", err) | |||
} | |||
req, err := http.NewRequest(method, url, bytes.NewBuffer(jsonData)) | |||
if err != nil { | |||
fmt.Errorf(common.GenLogLine()+"%s", err) | |||
common.Error(common.GenLogLine()+"%s", err) | |||
return nil, err | |||
} | |||
req.Header.Add("Content-Type", "application/json") | |||
client := &http.Client{} | |||
res, err := client.Do(req) | |||
if err != nil { | |||
fmt.Errorf(common.GenLogLine()+"%s", err) | |||
common.Error(common.GenLogLine()+"%s", err) | |||
return nil, err | |||
} | |||
defer res.Body.Close() | |||
body, err := io.ReadAll(res.Body) | |||
if err != nil { | |||
fmt.Errorf(common.GenLogLine()+"%s", err) | |||
common.Error(common.GenLogLine()+"%s", err) | |||
return nil, err | |||
} | |||
var response *common.Response | |||
err = json.Unmarshal([]byte(string(body)), &response) | |||
if err != nil { | |||
fmt.Println("Error:", err) | |||
return nil, err | |||
} | |||
common.Error(common.GenLogLine()+"reg result %s", string(body)) | |||
return response, nil | |||
} | |||
func RegOnlineStaff(param Req) error { | |||
url := common.ConfigData.PushDataUrl | |||
fmt.Printf("url:%s\n", url) | |||
method := "POST" | |||
param.DevId = common.ConfigData.DevId | |||
fmt.Printf("====param:%v\n", param) | |||
jsonData, err := json.Marshal(param) | |||
if err != nil { | |||
fmt.Println("Error marshaling JSON:", err) | |||
} | |||
req, err := http.NewRequest(method, url, bytes.NewBuffer(jsonData)) | |||
if err != nil { | |||
fmt.Errorf(common.GenLogLine()+"%s", err) | |||
common.Error(common.GenLogLine()+"%s", err) | |||
return err | |||
} | |||
req.Header.Add("Content-Type", "application/json") | |||
client := &http.Client{} | |||
res, err := client.Do(req) | |||
if err != nil { | |||
fmt.Errorf(common.GenLogLine()+"%s", err) | |||
common.Error(common.GenLogLine()+"%s", err) | |||
return err | |||
} | |||
defer res.Body.Close() | |||
body, err := io.ReadAll(res.Body) | |||
if err != nil { | |||
fmt.Errorf(common.GenLogLine()+"%s", err) | |||
common.Error(common.GenLogLine()+"%s", err) | |||
return err | |||
} | |||
fmt.Println(string(body)) | |||
return nil | |||
} | |||
func HandleStaff(emp Req) error { | |||
if emp.StaffBase64Img != "" { | |||
//feature = FetchStaffFaceFeature(emp.StaffBase64Img) | |||
//emp.FaceFeature = LocalFetchStaffFaceFeature(emp.StaffBase64Img) | |||
} | |||
var sType int | |||
if emp.StaffType > 70 { | |||
sType = 4 | |||
} else { | |||
sType = 5 | |||
} | |||
emp.StaffType = sType | |||
var sDels = []int{5, 6, 7, 8} | |||
if common.AryContainInt(sDels, emp.DelFlag) { | |||
emp.DelFlag = 1 | |||
} else { | |||
emp.DelFlag = 0 | |||
} | |||
RegStaff(emp) | |||
return nil | |||
} | |||
// Fetch2 获取员工信息,模拟获取saas的人员数据 | |||
func Fetch2() []Staff { | |||
_token, err := common.GetToken() | |||
if err != nil { | |||
fmt.Errorf(common.GenLogLine()+"%s", err) | |||
common.Error(common.GenLogLine()+"%s", err) | |||
return nil | |||
} | |||
url := common.ConfigData.FetchDataUrl | |||
method := "GET" | |||
payload := strings.NewReader(``) | |||
client := &http.Client{} | |||
req, err := http.NewRequest(method, url, payload) | |||
if err != nil { | |||
fmt.Errorf(common.GenLogLine()+"%s", err) | |||
common.Error(common.GenLogLine()+"%s", err) | |||
return nil | |||
} | |||
token := fmt.Sprintf(`Bearer %s`, _token) | |||
req.Header.Add("Authorization", token) | |||
res, err := client.Do(req) | |||
if err != nil { | |||
fmt.Errorf(common.GenLogLine()+"%s", err) | |||
common.Error(common.GenLogLine()+"%s", err) | |||
return nil | |||
} | |||
defer res.Body.Close() | |||
body, err := io.ReadAll(res.Body) | |||
if err != nil { | |||
fmt.Errorf(common.GenLogLine()+"%s", err) | |||
common.Error(common.GenLogLine()+"%s", err) | |||
return nil | |||
} | |||
var response *common.Response | |||
err = json.Unmarshal([]byte(string(body)), &response) | |||
if err != nil { | |||
fmt.Println("Error:", err) | |||
} | |||
var result []Staff | |||
switch v := response.Data["items"].(type) { | |||
case []interface{}: | |||
for _, item := range v { | |||
var s Staff | |||
//fmt.Println(item) | |||
if item.(map[string]interface{})["id"] != nil { | |||
s.ID = (item.(map[string]interface{})["id"]).(string) | |||
} | |||
if item.(map[string]interface{})["name"] != nil { | |||
s.Name = (item.(map[string]interface{})["name"]).(string) | |||
} | |||
if item.(map[string]interface{})["nickName"] != nil { | |||
s.NickName = (item.(map[string]interface{})["nickName"]).(string) | |||
} | |||
if item.(map[string]interface{})["phone"] != nil { | |||
s.Phone = (item.(map[string]interface{})["phone"]).(string) | |||
} | |||
if item.(map[string]interface{})["type"] != nil { | |||
s.Type = (item.(map[string]interface{})["type"]).(int) | |||
} | |||
if item.(map[string]interface{})["resource"] != nil { | |||
if item.(map[string]interface{})["resource"].(map[string]interface{})["url"] != nil { | |||
s.Url = (item.(map[string]interface{})["resource"].(map[string]interface{})["url"]).(string) | |||
} | |||
} | |||
result = append(result, s) | |||
} | |||
default: | |||
fmt.Println("无法解析的类型") | |||
} | |||
return result | |||
} | |||
// AbleSendCode 发送验证码 | |||
func AbleSendCode(phone string) string { | |||
url := common.ConfigData.CheckSendCodeUrl + "/" + phone | |||
method := "GET" | |||
payload := strings.NewReader("") | |||
client := &http.Client{} | |||
req, err := http.NewRequest(method, url, payload) | |||
if err != nil { | |||
fmt.Errorf(common.GenLogLine()+"%s", err) | |||
common.Error(common.GenLogLine()+"%s", err) | |||
return err.Error() | |||
} | |||
res, err := client.Do(req) | |||
if err != nil { | |||
fmt.Errorf(common.GenLogLine()+"%s", err) | |||
common.Error(common.GenLogLine()+"%s", err) | |||
return err.Error() | |||
} | |||
defer res.Body.Close() | |||
body, err := io.ReadAll(res.Body) | |||
if err != nil { | |||
fmt.Errorf(common.GenLogLine()+"%s", err) | |||
common.Error(common.GenLogLine()+"%s", err) | |||
return err.Error() | |||
} | |||
fmt.Println("response Body:", string(body)) | |||
return string(body) | |||
} | |||
func SendCode(phone string) string { | |||
ableSend := AbleSendCode(phone) | |||
fmt.Println("ableSend:", ableSend) | |||
url := common.ConfigData.SendCodeUrl | |||
method := "POST" | |||
payload := strings.NewReader(`{ | |||
"phone":"` + phone + `"}`) | |||
client := &http.Client{} | |||
req, err := http.NewRequest(method, url, payload) | |||
if err != nil { | |||
fmt.Errorf(common.GenLogLine()+"%s", err) | |||
common.Error(common.GenLogLine()+"%s", err) | |||
return err.Error() | |||
} | |||
req.Header.Add("Content-Type", "application/json") | |||
res, err := client.Do(req) | |||
if err != nil { | |||
fmt.Errorf(common.GenLogLine()+"%s", err) | |||
common.Error(common.GenLogLine()+"%s", err) | |||
return err.Error() | |||
} | |||
defer res.Body.Close() | |||
body, err := io.ReadAll(res.Body) | |||
if err != nil { | |||
fmt.Errorf(common.GenLogLine()+"%s", err) | |||
common.Error(common.GenLogLine()+"%s", err) | |||
return err.Error() | |||
} | |||
fmt.Println("response Body:", string(body)) | |||
var result map[string]interface{} | |||
err = json.Unmarshal([]byte(string(body)), &result) | |||
if err != nil { | |||
fmt.Println("解析JSON出错:", err) | |||
return err.Error() | |||
} | |||
return string(body) | |||
} | |||
func ValidCode(phone string, code string) (string, error) { | |||
ableSend := AbleSendCode(phone) | |||
fmt.Println("ableSend:", ableSend) | |||
url := common.ConfigData.ValidCodeUrl + phone + "/" + code | |||
method := "GET" | |||
payload := strings.NewReader(``) | |||
client := &http.Client{} | |||
req, err := http.NewRequest(method, url, payload) | |||
res, err := client.Do(req) | |||
if err != nil { | |||
fmt.Errorf(common.GenLogLine()+"%s", err) | |||
common.Error(common.GenLogLine()+"%s", err) | |||
return "", err | |||
} | |||
defer res.Body.Close() | |||
body, err := io.ReadAll(res.Body) | |||
if err != nil { | |||
fmt.Errorf(common.GenLogLine()+"%s", err) | |||
common.Error(common.GenLogLine()+"%s", err) | |||
return "", err | |||
} | |||
fmt.Println("response Body:", string(body)) | |||
common.Error(common.GenLogLine()+"reg result %s", string(body)) | |||
return string(body), nil | |||
} | |||
func StaffInfo(staffId string) (map[string]interface{}, error) { | |||
fmt.Println("staffId:", staffId) | |||
url := common.ConfigData.StaffInfoUrl | |||
method := "GET" | |||
token, err := common.GetToken() | |||
if err != nil { | |||
return nil, err | |||
} | |||
payload := &bytes.Buffer{} | |||
writer := multipart.NewWriter(payload) | |||
_ = writer.WriteField("id", staffId) | |||
err = writer.Close() | |||
if err != nil { | |||
fmt.Println(err) | |||
return nil, err | |||
} | |||
client := &http.Client{} | |||
req, err := http.NewRequest(method, url, payload) | |||
if err != nil { | |||
fmt.Println(err) | |||
return nil, err | |||
} | |||
req.Header.Add("Authorization", "Bearer "+token) | |||
req.Header.Set("Content-Type", writer.FormDataContentType()) | |||
res, err := client.Do(req) | |||
if err != nil { | |||
fmt.Println(err) | |||
return nil, err | |||
} | |||
defer res.Body.Close() | |||
body, err := io.ReadAll(res.Body) | |||
if err != nil { | |||
fmt.Println(err) | |||
return nil, err | |||
} | |||
fmt.Println(string(body)) | |||
var result map[string]interface{} | |||
err = json.Unmarshal([]byte(string(body)), &result) | |||
if err != nil { | |||
fmt.Println("解析JSON出错:", err) | |||
return nil, err | |||
} | |||
items, ok := result["data"].(map[string]interface{})["items"].([]interface{}) | |||
if !ok { | |||
fmt.Println("无法获取items字段") | |||
return nil, err | |||
} | |||
if len(items) == 0 { | |||
return nil, errors.New("未找到员工信息") | |||
} | |||
firstItem := items[0].(map[string]interface{}) | |||
common.Error(common.GenLogLine()+"info result %v", firstItem) | |||
return firstItem, nil | |||
} | |||
func MgrLogin(userName string, password string) string { | |||
url := common.ConfigData.MgrLoginUrl | |||
fmt.Println("url:", url) | |||
enterpriseName := common.ConfigData.EnterpriseName | |||
method := "POST" | |||
payload := strings.NewReader(`{ | |||
"enterpriseName":"` + enterpriseName + `", | |||
"userName":"` + userName + `", | |||
"password":"` + password + `"}`) | |||
client := &http.Client{} | |||
req, err := http.NewRequest(method, url, payload) | |||
if err != nil { | |||
fmt.Errorf(common.GenLogLine()+"%s", err) | |||
common.Error(common.GenLogLine()+"%s", err) | |||
return err.Error() | |||
} | |||
req.Header.Add("Content-Type", "application/json") | |||
res, err := client.Do(req) | |||
if err != nil { | |||
fmt.Errorf(common.GenLogLine()+"%s", err) | |||
common.Error(common.GenLogLine()+"%s", err) | |||
return err.Error() | |||
} | |||
defer res.Body.Close() | |||
body, err := io.ReadAll(res.Body) | |||
if err != nil { | |||
fmt.Errorf(common.GenLogLine()+"%s", err) | |||
common.Error(common.GenLogLine()+"%s", err) | |||
return err.Error() | |||
} | |||
fmt.Println("response Body:", string(body)) | |||
return string(body) | |||
} | |||
func PhoneLogin(phone string) (map[string]interface{}, error) { | |||
url := common.ConfigData.PhoneLoginUrl | |||
method := "POST" | |||
payload := strings.NewReader(`{ | |||
"phone":"` + phone + `"}`) | |||
client := &http.Client{} | |||
req, _ := http.NewRequest(method, url, payload) | |||
req.Header.Add("Content-Type", "application/json") | |||
res, err := client.Do(req) | |||
if err != nil { | |||
fmt.Errorf(common.GenLogLine()+"%s", err) | |||
common.Error(common.GenLogLine()+"%s", err) | |||
return nil, err | |||
} | |||
defer res.Body.Close() | |||
body, err := io.ReadAll(res.Body) | |||
if err != nil { | |||
fmt.Errorf(common.GenLogLine()+"%s", err) | |||
common.Error(common.GenLogLine()+"%s", err) | |||
return nil, err | |||
} | |||
fmt.Println("response Body:", string(body)) | |||
var result map[string]interface{} | |||
err = json.Unmarshal([]byte(string(body)), &result) | |||
if err != nil { | |||
fmt.Println("解析JSON出错:", err) | |||
return nil, err | |||
} | |||
return result, nil | |||
} | |||
func Fetch() []Req { | |||
url := common.ConfigData.FetchData2Url | |||
method := "POST" | |||
payload := strings.NewReader("appId=dfwycustomer2u8&ygbh") | |||
client := &http.Client{} | |||
req, err := http.NewRequest(method, url, payload) | |||
if err != nil { | |||
fmt.Errorf(common.GenLogLine()+"%s", err) | |||
common.Error(common.GenLogLine()+"%s", err) | |||
return nil | |||
} | |||
req.Header.Add("Content-Type", "application/x-www-form-urlencoded") | |||
res, err := client.Do(req) | |||
if err != nil { | |||
fmt.Errorf(common.GenLogLine()+"%s", err) | |||
common.Error(common.GenLogLine()+"%s", err) | |||
return nil | |||
} | |||
defer res.Body.Close() | |||
body, err := io.ReadAll(res.Body) | |||
if err != nil { | |||
fmt.Errorf(common.GenLogLine()+"%s", err) | |||
common.Error(common.GenLogLine()+"%s", err) | |||
return nil | |||
} | |||
var response *common.Resp | |||
err = json.Unmarshal([]byte(string(body)), &response) | |||
if err != nil { | |||
fmt.Println("Error:", err) | |||
} | |||
var result []Req | |||
fmt.Printf("====%#v====datassss\n", response) | |||
for _, item := range response.Data { | |||
var s Req | |||
//fmt.Println(item) | |||
if item.(map[string]interface{})["workcode"] != nil { | |||
s.Code = (item.(map[string]interface{})["workcode"]).(string) | |||
} | |||
if item.(map[string]interface{})["name"] != nil { | |||
s.StaffName = (item.(map[string]interface{})["name"]).(string) | |||
} | |||
if item.(map[string]interface{})["mobile"] != nil { | |||
s.Phone = (item.(map[string]interface{})["mobile"]).(string) | |||
} | |||
if item.(map[string]interface{})["level"] != nil { | |||
s.StaffType, _ = strconv.Atoi((item.(map[string]interface{})["level"]).(string)) | |||
} | |||
if item.(map[string]interface{})["birthday"] != nil { | |||
s.Birthday = (item.(map[string]interface{})["birthday"]).(string) | |||
} | |||
if item.(map[string]interface{})["companystartdate"] != nil { | |||
s.HireDate = (item.(map[string]interface{})["companystartdate"]).(string) | |||
} | |||
if item.(map[string]interface{})["status"] != nil { | |||
s.DelFlag, _ = strconv.Atoi((item.(map[string]interface{})["status"]).(string)) | |||
} | |||
if item.(map[string]interface{})["image"] != nil { | |||
s.StaffBase64Img = (item.(map[string]interface{})["image"]).(string) | |||
} | |||
if item.(map[string]interface{})["modified"] != nil { | |||
s.Modified = (item.(map[string]interface{})["modified"]).(string) | |||
} | |||
result = append(result, s) | |||
} | |||
if len(result) > 0 { | |||
sort.Slice(result, func(i, j int) bool { | |||
a, err := time.Parse("2006-01-02 15:04:05", result[i].Modified) | |||
if err != nil { | |||
common.Error(common.GenLogLine() + err.Error()) | |||
} | |||
b, err2 := time.Parse("2006-01-02 15:04:05", result[j].Modified) | |||
if err2 != nil { | |||
common.Error(common.GenLogLine() + err2.Error()) | |||
} | |||
return b.Before(a) | |||
}) | |||
} | |||
return result | |||
} | |||
func FetchStaffImage(ygbh string) string { | |||
url := common.ConfigData.FetchData2Url | |||
method := "POST" | |||
payload := strings.NewReader("appId=dfwycustomer2u8&ygbh=" + fmt.Sprintf("%s", ygbh)) | |||
client := &http.Client{} | |||
req, err := http.NewRequest(method, url, payload) | |||
if err != nil { | |||
fmt.Errorf(common.GenLogLine()+"%s", err) | |||
common.Error(common.GenLogLine()+"%s", err) | |||
return "" | |||
} | |||
req.Header.Add("Content-Type", "application/x-www-form-urlencoded") | |||
res, _ := client.Do(req) | |||
defer res.Body.Close() | |||
body, err := io.ReadAll(res.Body) | |||
if err != nil { | |||
fmt.Errorf(common.GenLogLine()+"%s", err) | |||
common.Error(common.GenLogLine()+"%s", err) | |||
return "" | |||
} | |||
var response *common.Resp | |||
err = json.Unmarshal([]byte(string(body)), &response) | |||
if err != nil { | |||
fmt.Println("Error:", err) | |||
} | |||
var result string = "" | |||
for _, item := range response.Data { | |||
var s string | |||
//fmt.Println(item) | |||
if item.(map[string]interface{})["image"] != nil { | |||
s = (item.(map[string]interface{})["image"]).(string) | |||
} | |||
result = s | |||
} | |||
return strings.Replace(result, "\n", "", -1) | |||
} | |||
func FetchStaffFaceFeature(base64 string) string { | |||
url := "http://39.105.51.226:5000/cv/feature-extraction-service/1.7" | |||
method := "POST" | |||
err := common.SaveBase64ImageToFile(base64, "images/"+fmt.Sprintf("%d", time.Now().Unix())+"test.jpg") | |||
fmt.Printf("%v\n", err) | |||
payload := strings.NewReader(`{ | |||
"detect":true, | |||
"base64Data":"` + base64 + `"}`) | |||
client := &http.Client{} | |||
req, err := http.NewRequest(method, url, payload) | |||
if err != nil { | |||
fmt.Errorf(common.GenLogLine()+"%s", err) | |||
common.Error(common.GenLogLine()+"%s", err) | |||
return "" | |||
} | |||
req.Header.Add("Authorization", "Bearer ") | |||
req.Header.Add("Content-Type", "application/json") | |||
res, err := client.Do(req) | |||
if err != nil { | |||
fmt.Errorf(common.GenLogLine()+"%s", err) | |||
common.Error(common.GenLogLine()+"%s", err) | |||
return "" | |||
} | |||
defer res.Body.Close() | |||
body, err := io.ReadAll(res.Body) | |||
if err != nil { | |||
fmt.Errorf(common.GenLogLine()+"%s", err) | |||
common.Error(common.GenLogLine()+"%s", err) | |||
return "" | |||
} | |||
fmt.Println(string(body)) | |||
var response *FeatureResp | |||
err = json.Unmarshal([]byte(string(body)), &response) | |||
if err != nil { | |||
fmt.Println("Error:", err) | |||
} | |||
var result string | |||
result, err = extractFeature(response.Result[0]) | |||
fmt.Printf(" success data : %+v\n", result) | |||
return result | |||
} | |||
func extractFeature(data interface{}) (string, error) { | |||
// 将 interface{} 类型转换为 map[string]interface{} | |||
resultMap, ok := data.(map[string]interface{}) | |||
if !ok { | |||
return "", fmt.Errorf("Invalid data format") | |||
} | |||
// 取出 "faces" 字段 | |||
faces, ok := resultMap["faces"].([]interface{}) | |||
if !ok || len(faces) == 0 { | |||
return "", fmt.Errorf("No faces found") | |||
} | |||
// 取出 "feature" 字段 | |||
feature, ok := faces[0].(map[string]interface{})["feature"].([]interface{}) | |||
if !ok || len(feature) == 0 { | |||
return "", fmt.Errorf("No feature found") | |||
} | |||
// 转换 feature 字段为 []float64 类型 | |||
var featureValues []float64 | |||
for _, value := range feature { | |||
if floatValue, ok := value.(float64); ok { | |||
featureValues = append(featureValues, floatValue) | |||
} else { | |||
return "", fmt.Errorf("Invalid feature value type") | |||
} | |||
} | |||
str := common.FloatSliceToString(featureValues) | |||
return str, nil | |||
} | |||
func LocalFetchStaffFaceFeature(base64 string) (string, string, error) { | |||
url := common.ConfigData.LocalDetectUrl | |||
method := "POST" | |||
imgName := "static/faces/" + fmt.Sprintf("%d", time.Now().Unix()) + "test.jpg" | |||
err := common.SaveBase64ImageToFile(base64, imgName) | |||
payload := strings.NewReader(`{ | |||
"imgbase64":"` + base64 + `"}`) | |||
client := &http.Client{} | |||
req, _ := http.NewRequest(method, url, payload) | |||
//req.Header.Add("Authorization", "Bearer ") | |||
req.Header.Add("Content-Type", "application/json") | |||
res, err := client.Do(req) | |||
if err != nil { | |||
fmt.Errorf(common.GenLogLine()+"%s", err) | |||
common.Error(common.GenLogLine()+"%s", err) | |||
return "", imgName, err | |||
} | |||
defer res.Body.Close() | |||
body, err := io.ReadAll(res.Body) | |||
if err != nil { | |||
fmt.Errorf(common.GenLogLine()+"%s", err) | |||
common.Error(common.GenLogLine()+"%s", err) | |||
return "", imgName, err | |||
} | |||
fmt.Println(string(body)) | |||
var response map[string]interface{} | |||
err = json.Unmarshal([]byte(string(body)), &response) | |||
if err != nil { | |||
fmt.Println("Error:", err) | |||
return "", imgName, err | |||
} | |||
faces, ok := response["data"].(map[string]interface{}) | |||
if !ok { | |||
fmt.Errorf("No faces found") | |||
} | |||
feature, ok1 := faces["faceData"].(map[string]interface{})["theFeature"].([]interface{}) | |||
if !ok1 || len(feature) == 0 { | |||
return "", imgName, err | |||
} | |||
// 转换 feature 字段为 []float64 类型 | |||
var featureValues []float64 | |||
for _, value := range feature { | |||
if floatValue, ok := value.(float64); ok { | |||
featureValues = append(featureValues, floatValue) | |||
} else { | |||
return "", imgName, err | |||
} | |||
} | |||
str := common.FloatSliceToString(featureValues) | |||
return str, imgName, nil | |||
} | |||
func GetMaxId(dataList []Staff) string { | |||
maxID := dataList[0].ID | |||
common.Info(common.GenLogLine()+"maxID:", maxID) | |||
for _, data := range dataList { | |||
if data.ID > maxID { | |||
maxID = data.ID | |||
common.Info(common.GenLogLine()+"maxID:%s", maxID) | |||
} | |||
} | |||
return maxID | |||
} | |||
func GetNewestModified(dataList []Req) string { | |||
if len(dataList) == 0 { | |||
return "" | |||
} | |||
maxID := dataList[0].Modified | |||
return maxID | |||
} | |||
func TimerHandle() { | |||
fmt.Printf("TimerHandle start %d\n", timeStep) | |||
ticker := time.NewTicker(time.Second * time.Duration(timeStep)) | |||
defer ticker.Stop() | |||
for range ticker.C { //十秒执行一次 | |||
common.Info(common.GenLogLine() + "=====执行timerHandle开始=====") | |||
now := time.Now() | |||
// 将时间设置为23点59分59秒 | |||
t := time.Date(now.Year(), now.Month(), now.Day(), 23, 59, 55, 0, now.Location()) | |||
common.Info(common.GenLogLine() + "--1,执行日志分割 START--") | |||
duration := t.Sub(now) | |||
isWithin10Seconds := duration > 0*time.Second && duration <= time.Duration(timeStep)*time.Second | |||
fmt.Fprintln(os.Stdout, isWithin10Seconds) | |||
if isWithin10Seconds { | |||
common.Info(common.GenLogLine() + "--1.1执行RenameLogFile--") | |||
common.RenameLogFile() | |||
} | |||
common.Info(common.GenLogLine() + "--1,执行日志分割 END--") | |||
common.Info(common.GenLogLine() + "--2,数据同步 START--") | |||
//获取接口数据 | |||
staffs := Fetch() | |||
cachedTime := common.GetCache("maxTime") | |||
if len(staffs) == 0 { | |||
common.Info(common.GenLogLine() + "数据为空") | |||
} else { | |||
//获取最新更新时间 | |||
maxTime := GetNewestModified(staffs) | |||
var t1 time.Time | |||
var t2 time.Time | |||
var t3 time.Time | |||
if cachedTime == "" { | |||
cachedTime = common.ReadFile("di.txt") | |||
common.SetCacheWithExpire("maxTime", cachedTime, 0) | |||
} | |||
t1, _ = time.Parse("2006-01-02 15:04:05", cachedTime) | |||
t2, _ = time.Parse("2006-01-02 15:04:05", maxTime) | |||
if !t2.After(t1) { | |||
common.Info(common.GenLogLine() + "--2.1, 数据已被同步") | |||
} else { | |||
common.SetCacheWithExpire("maxTime", maxTime, 0) | |||
for _, staff := range staffs { | |||
time.Sleep(1 * time.Second) // 暂停1秒 | |||
t3, _ = time.Parse("2006-01-02 15:04:05", staff.Modified) | |||
if t3.After(t1) { | |||
staff.StaffBase64Img = FetchStaffImage(staff.Code) | |||
common.Info(common.GenLogLine()+"----%v", "" == staff.StaffBase64Img) | |||
str := HandleStaff(staff) | |||
common.Info(common.GenLogLine()+"--2.2注册人员 姓名:%s 编号:%s 更新时间:%s--\n", staff.StaffName, staff.Code, staff.Modified) | |||
//str := RegOnlineStaff(staff) | |||
ss := "" | |||
if str == nil { | |||
ss = "保存成功" | |||
} else { | |||
ss = str.Error() | |||
} | |||
fmt.Printf("注册人员:%v\n", ss) | |||
common.Info(common.GenLogLine()+"--2.3注册人员:%v--\n", ss) | |||
} else { | |||
break | |||
} | |||
} | |||
common.WriteFile("di.txt", maxTime) | |||
common.Info(common.GenLogLine()+"--2.4,数据同步,缓存数据maxID-- :%s", common.GetCache("maxTime")) | |||
} | |||
} | |||
common.Info(common.GenLogLine() + "--2,数据同步 END--") | |||
common.Info(common.GenLogLine() + "=====执行timerHandle结束=====") | |||
} | |||
} | |||
func EmpToReq(emp mydatabase.Emp) Req { | |||
var req Req | |||
req.StaffName = emp.Name | |||
req.StaffType = 5 //普通员工 | |||
req.Phone = emp.Phone | |||
req.StaffBase64Img = emp.Avatar | |||
req.FaceFeature = emp.Features | |||
return req | |||
} |
@@ -0,0 +1,125 @@ | |||
package common | |||
/** | |||
* @Author:yk | |||
* @Date: 2024/01/19 | |||
* @Desc: 缓存方法,文件读取写入方法 | |||
*/ | |||
import ( | |||
"encoding/base64" | |||
"fmt" | |||
"github.com/coocood/freecache" | |||
"os" | |||
"path/filepath" | |||
"runtime/debug" | |||
"strings" | |||
"sync" | |||
) | |||
var ( | |||
instance *freecache.Cache | |||
mu sync.Mutex | |||
) | |||
// GetInstance 返回单例缓存对象 | |||
func GetInstance() *freecache.Cache { | |||
if instance == nil { | |||
mu.Lock() | |||
defer mu.Unlock() | |||
if instance == nil { | |||
cacheSize := 100 * 1024 * 1024 | |||
cache := freecache.NewCache(cacheSize) | |||
instance = cache | |||
} | |||
} | |||
return instance | |||
} | |||
// SetCache 设置缓存,默认过期时间为60秒 | |||
func SetCache(k string, v string) { | |||
SetCacheWithExpire(k, v, 60) | |||
} | |||
// SetCacheWithExpire 设置缓存 | |||
func SetCacheWithExpire(k string, v string, t int) { | |||
debug.SetGCPercent(20) | |||
key := []byte(k) | |||
val := []byte(v) | |||
GetInstance().Set(key, val, t) | |||
} | |||
// GetCache 获取缓存 | |||
func GetCache(k string) string { | |||
key := []byte(k) | |||
got, err := GetInstance().Get(key) | |||
if err != nil { | |||
fmt.Printf(GenLogLine()+"%s", err) | |||
Error(GenLogLine()+"%s", err) | |||
return "" | |||
} else { | |||
return string(got) | |||
} | |||
} | |||
// ReadFile 读取文件内容 | |||
func ReadFile(filePath string) string { | |||
content, err := os.ReadFile(filePath) // 读取文件内容 | |||
if err != nil { | |||
fmt.Printf("读取文件失败:%v\n", err) | |||
Error("读取文件失败:%v\n", err) | |||
return "" | |||
} | |||
fmt.Println(string(content)) | |||
return string(content) | |||
} | |||
// WriteFile 写入文件内容 | |||
func WriteFile(filePath string, content string) error { | |||
file, err := os.Create(filePath) | |||
if err != nil { | |||
return err | |||
} | |||
defer file.Close() | |||
_, err = file.WriteString(content) | |||
if err != nil { | |||
return err | |||
} | |||
return nil | |||
} | |||
func SaveBase64ImageToFile(base64Image string, outputFileName string) error { | |||
// 解码 base64 编码的图片数据 | |||
imageData, err := base64.StdEncoding.DecodeString(extractBase64Data(base64Image)) | |||
if err != nil { | |||
return fmt.Errorf("Error decoding base64 image data: %v", err) | |||
} | |||
if len(imageData) == 0 { | |||
return fmt.Errorf("Decoded image data is empty") | |||
} | |||
// 确保目录存在 | |||
outputDir := filepath.Dir(outputFileName) | |||
if err := os.MkdirAll(outputDir, 0755); err != nil { | |||
return fmt.Errorf("Error creating directories: %v", err) | |||
} | |||
// 保存图片数据为文件 | |||
err = os.WriteFile(outputFileName, imageData, 0644) | |||
if err != nil { | |||
return fmt.Errorf("Error saving image data to file: %v", err) | |||
} | |||
fmt.Printf("Image saved to %s\n", outputFileName) | |||
return nil | |||
} | |||
// extractBase64Data 从 base64 编码的图片数据中提取实际的 base64 数据部分 | |||
func extractBase64Data(base64Image string) string { | |||
// 图片数据格式为 "data:image/png;base64,...",我们需要提取逗号后的部分 | |||
parts := strings.SplitN(base64Image, ",", 2) | |||
if len(parts) != 2 { | |||
return base64Image | |||
} | |||
return parts[1] | |||
} |
@@ -0,0 +1,203 @@ | |||
package common | |||
import ( | |||
"bytes" | |||
"encoding/json" | |||
"fmt" | |||
"io" | |||
"net/http" | |||
"runtime" | |||
"strconv" | |||
"strings" | |||
"time" | |||
) | |||
type Response struct { | |||
Msg string `json:"msg"` | |||
Code int `json:"code"` | |||
Data map[string]interface{} `json:"data"` | |||
Type string `json:"type"` | |||
} | |||
type Resp struct { | |||
Code int `json:"code"` | |||
Message string `json:"message"` | |||
Data []interface{} `json:"data"` | |||
} | |||
type InterfaceResp struct { | |||
Status int `json:"code"` | |||
Err string `json:"message"` | |||
Data interface{} `json:"data"` | |||
} | |||
func GenLogLine() string { | |||
pc, _, _, ok := runtime.Caller(1) | |||
if !ok { | |||
return "unknown" | |||
} | |||
// 获取函数信息 | |||
f := runtime.FuncForPC(pc) | |||
if f == nil { | |||
return "unknown" | |||
} | |||
// 获取文件名和行号 | |||
file, line := f.FileLine(pc) | |||
// 获取函数名 | |||
funcName := f.Name() | |||
return fmt.Sprintf("file:%s; func:%s %d行:", TruncateLastSlash(file), TruncateLastSlash(funcName), line) | |||
} | |||
func FloatSliceToString(floats []float64) string { | |||
var strSlice []string | |||
for _, f := range floats { | |||
strSlice = append(strSlice, strconv.FormatFloat(f, 'f', -1, 64)) | |||
} | |||
return "[" + strings.Join(strSlice, ", ") + "]" | |||
} | |||
func TruncateLastSlash(inputString string) string { | |||
lastIndex := strings.LastIndex(inputString, "/") | |||
if lastIndex == -1 { | |||
// 没有反斜线,返回原始字符串 | |||
return inputString | |||
} | |||
// 截断字符串并返回 | |||
return inputString[lastIndex+1:] | |||
} | |||
func GetToken() (string, error) { | |||
url := ConfigData.FetchTokenUrl | |||
method := "POST" | |||
Info(GenLogLine() + "获取token") | |||
token := GetCache("token") | |||
if "" != token { | |||
Info(GenLogLine() + "====get token from cache====") | |||
return token, nil | |||
} | |||
payload := fmt.Sprintf(`{"deviceId":"%s"}`, ConfigData.DevId) | |||
input := strings.NewReader(payload) | |||
client := &http.Client{} | |||
req, err := http.NewRequest(method, url, input) | |||
if err != nil { | |||
return "", fmt.Errorf("create request fail: %w", err) | |||
} | |||
req.Header.Add("Content-Type", "application/json") | |||
res, err := client.Do(req) | |||
if err != nil { | |||
fmt.Errorf(GenLogLine()+"%s", err) | |||
Error(GenLogLine()+"%s", err) | |||
return "", fmt.Errorf("request fail: %w", err) | |||
} | |||
defer res.Body.Close() | |||
body, err := io.ReadAll(res.Body) | |||
if err != nil { | |||
fmt.Errorf(GenLogLine()+"%s", err) | |||
Error(GenLogLine()+"%s", err) | |||
return "", fmt.Errorf("handle resp fail: %w", err) | |||
} | |||
var response Response | |||
err = json.Unmarshal([]byte(string(body)), &response) | |||
if err != nil { | |||
Error("Error:", err) | |||
} | |||
Info(GenLogLine()+"token:====", response.Data["access_token"]) | |||
result := response.Data["access_token"].(string) | |||
SetCacheWithExpire("token", result, 3600) | |||
return result, nil | |||
} | |||
func CovertTime(timeStr string) string { | |||
location, err := time.LoadLocation("Asia/Shanghai") | |||
if err != nil { | |||
fmt.Println("Error loading location:", err) | |||
return "" | |||
} | |||
// 解析日期字符串 | |||
parsedDate, err := time.ParseInLocation("2006-01-02", timeStr, location) | |||
if err != nil { | |||
fmt.Println("Error parsing date:", err) | |||
return "" | |||
} | |||
// 输出日期 | |||
fmt.Println("Parsed Date:", parsedDate) | |||
// 将日期格式化为字符串 | |||
formattedDate := parsedDate.Format("2006-01-02") | |||
fmt.Println("Formatted Date:", formattedDate) | |||
// 传递给 Java 的字符串日期(带时区信息) | |||
javaDateString := parsedDate.Format("2006-01-02T15:04:05Z07:00") | |||
return javaDateString | |||
} | |||
func exec() { | |||
ticker := time.NewTicker(5 * time.Minute) | |||
defer ticker.Stop() | |||
for range ticker.C { | |||
// 请求接口A | |||
respA, err := http.Get("http://localhost:8080/api/interfaceA") | |||
if err != nil { | |||
fmt.Println("请求接口A失败:", err) | |||
continue | |||
} | |||
defer respA.Body.Close() | |||
// 读取接口A返回的数据 | |||
dataA, err := io.ReadAll(respA.Body) | |||
if err != nil { | |||
fmt.Println("读取接口A返回数据失败:", err) | |||
continue | |||
} | |||
// 将接口A返回的数据通过接口B发送到某个系统 | |||
respB, err := http.Post("http://localhost:8080/api/interfaceB", "application/json", bytes.NewBuffer(dataA)) | |||
if err != nil { | |||
Error("发送数据到接口B失败:", err) | |||
continue | |||
} | |||
defer respB.Body.Close() | |||
// 检查接口B的响应状态 | |||
if respB.StatusCode == http.StatusOK { | |||
Info(GenLogLine() + "数据发送成功") | |||
} else { | |||
Error("数据发送失败,状态码:", respB.StatusCode) | |||
} | |||
} | |||
} | |||
func AryContainInt(s []int, str int) bool { | |||
found := false | |||
for _, value := range s { | |||
if value == str { | |||
found = true | |||
break | |||
} | |||
} | |||
return found | |||
} | |||
func AryContainStr(s []string, str string) bool { | |||
found := false | |||
for _, value := range s { | |||
if value == str { | |||
found = true | |||
break | |||
} | |||
} | |||
return found | |||
} |
@@ -0,0 +1,121 @@ | |||
package common | |||
import ( | |||
"encoding/json" | |||
"os" | |||
) | |||
type Config struct { | |||
FetchTokenUrl string `json:"fetchTokenUrl"` | |||
Phone string `json:"phone"` | |||
FetchDataUrl string `json:"fetchDataUrl"` | |||
FetchData2Url string `json:"fetchData2Url"` | |||
SendCodeUrl string `json:"sendCodeUrl"` | |||
CheckSendCodeUrl string `json:"checkSendCodeUrl"` | |||
PhoneLoginUrl string `json:"phoneLoginUrl"` | |||
MgrLoginUrl string `json:"mgrLoginUrl"` | |||
ValidCodeUrl string `json:"validCodeUrl"` | |||
StaffInfoUrl string `json:"staffInfoUrl"` | |||
EnterpriseName string `json:"enterpriseName"` | |||
Port string `json:"port"` | |||
PushDataUrl string `json:"pushDataUrl"` | |||
LocalDetectUrl string `json:"localDetectUrl"` | |||
DevId string `json:"devId"` | |||
Timer int `json:"timer"` | |||
Mode string `json:"mode"` | |||
} | |||
var ConfigData Config | |||
func LoadConfig() interface{} { | |||
// 读取配置文件 | |||
data, err := os.ReadFile("config.json") | |||
if err != nil { | |||
return nil | |||
} | |||
// 解析配置文件内容到全局变量中 | |||
err = json.Unmarshal(data, &ConfigData) | |||
if err != nil { | |||
return nil | |||
} | |||
return ConfigData | |||
} | |||
func UpdateConfig(updateValues map[string]interface{}) string { | |||
config := ConfigData | |||
for key, value := range updateValues { | |||
switch key { | |||
case "port": | |||
config.Port = value.(string) | |||
case "phone": | |||
config.Phone = value.(string) | |||
case "devId": | |||
config.DevId = value.(string) | |||
case "mode": | |||
config.Mode = value.(string) | |||
case "enterpriseName": | |||
config.EnterpriseName = value.(string) | |||
case "fetchTokenUrl": | |||
config.FetchTokenUrl = value.(string) | |||
case "fetchDataUrl": | |||
config.FetchDataUrl = value.(string) | |||
case "fetchData2Url": | |||
config.FetchData2Url = value.(string) | |||
case "pushDataUrl": | |||
config.PushDataUrl = value.(string) | |||
case "sendCodeUrl": | |||
config.SendCodeUrl = value.(string) | |||
case "checkSendCodeUrl": | |||
config.CheckSendCodeUrl = value.(string) | |||
case "mgrLoginUrl": | |||
config.MgrLoginUrl = value.(string) | |||
case "phoneLoginUrl": | |||
config.PhoneLoginUrl = value.(string) | |||
case "localDetectUrl": | |||
config.LocalDetectUrl = value.(string) | |||
case "validCodeUrl": | |||
config.ValidCodeUrl = value.(string) | |||
case "staffInfoUrl": | |||
config.StaffInfoUrl = value.(string) | |||
case "timer": | |||
config.Timer = int(value.(float64)) | |||
default: | |||
return "Unknown config key: " + key | |||
} | |||
} | |||
if err := writeConfigToFile(&config, "config.json"); err != nil { | |||
return "Failed to write config to file: " + err.Error() | |||
} | |||
return "" | |||
} | |||
// 从文件中读取配置 | |||
func readConfigFromFile(filename string) (*Config, error) { | |||
fileContent, err := os.ReadFile(filename) | |||
if err != nil { | |||
return nil, err | |||
} | |||
var config Config | |||
if err := json.Unmarshal(fileContent, &config); err != nil { | |||
return nil, err | |||
} | |||
return &config, nil | |||
} | |||
// 将配置写入文件 | |||
func writeConfigToFile(config *Config, filename string) error { | |||
configJSON, err := json.MarshalIndent(config, "", " ") | |||
if err != nil { | |||
return err | |||
} | |||
return os.WriteFile(filename, configJSON, 0644) | |||
} |
@@ -0,0 +1,101 @@ | |||
package common | |||
import ( | |||
"io" | |||
"log" | |||
"os" | |||
"time" | |||
) | |||
// flags and prefix | |||
const ( | |||
flag = log.Ldate | log.Ltime | log.Lshortfile | |||
preDebug = "[DEBUG] " | |||
preInfo = "[INFO] " | |||
preWarning = "[WARNING] " | |||
preError = "[ERROR] " | |||
) | |||
// diff logger and output log file | |||
var ( | |||
logFile io.Writer | |||
debugLogger *log.Logger | |||
infoLogger *log.Logger | |||
warningLogger *log.Logger | |||
errorLogger *log.Logger | |||
defaultLogFile = "./logs/web.log" | |||
) | |||
func createFile() { | |||
var err error | |||
logFile, err = os.OpenFile(defaultLogFile, os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0644) | |||
if err != nil { | |||
logFile, err = os.OpenFile(defaultLogFile, os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0644) | |||
if err != nil { | |||
log.Fatalf("create log file err %+v", err) | |||
} | |||
} | |||
debugLogger = log.New(io.MultiWriter(os.Stdout, logFile), preDebug, flag) | |||
infoLogger = log.New(logFile, preInfo, flag) | |||
warningLogger = log.New(logFile, preWarning, flag) | |||
errorLogger = log.New(logFile, preError, flag) | |||
} | |||
// init for logger | |||
func init() { | |||
createFile() | |||
} | |||
// Debug logger | |||
func Debug(format string, v ...interface{}) { | |||
debugLogger.Printf(format, v...) | |||
} | |||
func Info(format string, v ...interface{}) { | |||
infoLogger.Printf(format, v...) | |||
} | |||
func Warning(format string, v ...interface{}) { | |||
warningLogger.Printf(format, v...) | |||
} | |||
func Error(format string, v ...interface{}) { | |||
errorLogger.Printf(format, v...) | |||
} | |||
// set output file | |||
func setOutputPath(path string) { | |||
var err error | |||
logFile, err = os.OpenFile(path, os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0644) | |||
if err != nil { | |||
log.Fatalf("create log file err %+v", err) | |||
} | |||
debugLogger = log.New(logFile, preDebug, flag) | |||
infoLogger = log.New(logFile, preInfo, flag) | |||
warningLogger = log.New(logFile, preWarning, flag) | |||
errorLogger = log.New(logFile, preError, flag) | |||
} | |||
func SetFlags(flag int) { | |||
debugLogger.SetFlags(flag) | |||
infoLogger.SetFlags(flag) | |||
warningLogger.SetFlags(flag) | |||
errorLogger.SetFlags(flag) | |||
} | |||
func RenameLogFile() { | |||
if _, err := os.Stat(defaultLogFile); os.IsNotExist(err) { | |||
Info("文件不存在") | |||
return | |||
} | |||
// 重命名文件 | |||
err := os.Rename(defaultLogFile, "./logs/"+time.Now().Format("2006-01-02")+"-info.log") | |||
if err != nil { | |||
Info("重命名失败:", err) | |||
} else { | |||
Info("重命名成功") | |||
createFile() | |||
} | |||
} |
@@ -0,0 +1,19 @@ | |||
{ | |||
"fetchTokenUrl": "http://127.0.0.1:8080/auth/deviceLogin", | |||
"phone": "18910801519", | |||
"fetchDataUrl": "http://127.0.0.1:8080/system/staff/list", | |||
"fetchData2Url": "http://10.1.26.139/api/dizhiyuan/member/DZYAction", | |||
"sendCodeUrl": "http://127.0.0.1:8080/system/sms/api/send-code", | |||
"checkSendCodeUrl": "http://127.0.0.1:8080/system/staff/api/ableLogin", | |||
"phoneLoginUrl": "http://127.0.0.1:8080/auth/phoneLogin", | |||
"mgrLoginUrl": "http://127.0.0.1:8080/auth/mgr-login", | |||
"validCodeUrl": "http://127.0.0.1:8080/system/staff/api/validCode", | |||
"staffInfoUrl": "http://127.0.0.1:8080/system/staff/list", | |||
"enterpriseName": "演示机", | |||
"port": "18080", | |||
"pushDataUrl": "http://127.0.0.1:8080/system/staff/api/new-staff", | |||
"localDetectUrl": "http://192.168.10.32:8080/face/feature", | |||
"devId": "442926c7610ed10b", | |||
"timer": 90, | |||
"mode": "online" | |||
} |
@@ -0,0 +1,20 @@ | |||
<?xml version="1.0" encoding="UTF-8"?> | |||
<module type="WEB_MODULE" version="4"> | |||
<component name="Go" enabled="true"> | |||
<buildTags> | |||
<option name="customFlags"> | |||
<array> | |||
<option value="appengine" /> | |||
</array> | |||
</option> | |||
</buildTags> | |||
</component> | |||
<component name="NewModuleRootManager" inherit-compiler-output="true"> | |||
<exclude-output /> | |||
<content url="file://$MODULE_DIR$" /> | |||
<orderEntry type="sourceFolder" forTests="false" /> | |||
</component> | |||
<component name="SonarLintModuleSettings"> | |||
<option name="uniqueId" value="03c654ca-3133-4399-af16-d5d0ba94b53f" /> | |||
</component> | |||
</module> |
@@ -0,0 +1,38 @@ | |||
module digimetastaffsync | |||
go 1.20 | |||
require ( | |||
github.com/coocood/freecache v1.2.4 | |||
github.com/gin-gonic/gin v1.9.1 | |||
) | |||
require ( | |||
github.com/bytedance/sonic v1.10.2 // indirect | |||
github.com/cespare/xxhash/v2 v2.1.2 // indirect | |||
github.com/chenzhuoyu/base64x v0.0.0-20230717121745-296ad89f973d // indirect | |||
github.com/chenzhuoyu/iasm v0.9.1 // indirect | |||
github.com/gabriel-vasile/mimetype v1.4.3 // indirect | |||
github.com/gin-contrib/sse v0.1.0 // indirect | |||
github.com/go-playground/locales v0.14.1 // indirect | |||
github.com/go-playground/universal-translator v0.18.1 // indirect | |||
github.com/go-playground/validator/v10 v10.17.0 // indirect | |||
github.com/goccy/go-json v0.10.2 // indirect | |||
github.com/json-iterator/go v1.1.12 // indirect | |||
github.com/klauspost/cpuid/v2 v2.2.6 // indirect | |||
github.com/leodido/go-urn v1.3.0 // indirect | |||
github.com/mattn/go-isatty v0.0.20 // indirect | |||
github.com/mattn/go-sqlite3 v1.14.20 // indirect | |||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect | |||
github.com/modern-go/reflect2 v1.0.2 // indirect | |||
github.com/pelletier/go-toml/v2 v2.1.1 // indirect | |||
github.com/twitchyliquid64/golang-asm v0.15.1 // indirect | |||
github.com/ugorji/go/codec v1.2.12 // indirect | |||
golang.org/x/arch v0.7.0 // indirect | |||
golang.org/x/crypto v0.18.0 // indirect | |||
golang.org/x/net v0.20.0 // indirect | |||
golang.org/x/sys v0.16.0 // indirect | |||
golang.org/x/text v0.14.0 // indirect | |||
google.golang.org/protobuf v1.32.0 // indirect | |||
gopkg.in/yaml.v3 v3.0.1 // indirect | |||
) |
@@ -0,0 +1,96 @@ | |||
github.com/bytedance/sonic v1.5.0/go.mod h1:ED5hyg4y6t3/9Ku1R6dU/4KyJ48DZ4jPhfY1O2AihPM= | |||
github.com/bytedance/sonic v1.10.0-rc/go.mod h1:ElCzW+ufi8qKqNW0FY314xriJhyJhuoJ3gFZdAHF7NM= | |||
github.com/bytedance/sonic v1.10.2 h1:GQebETVBxYB7JGWJtLBi07OVzWwt+8dWA00gEVW2ZFE= | |||
github.com/bytedance/sonic v1.10.2/go.mod h1:iZcSUejdk5aukTND/Eu/ivjQuEL0Cu9/rf50Hi0u/g4= | |||
github.com/cespare/xxhash/v2 v2.1.2 h1:YRXhKfTDauu4ajMg1TPgFO5jnlC2HCbmLXMcTG5cbYE= | |||
github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= | |||
github.com/chenzhuoyu/base64x v0.0.0-20211019084208-fb5309c8db06/go.mod h1:DH46F32mSOjUmXrMHnKwZdA8wcEefY7UVqBKYGjpdQY= | |||
github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311/go.mod h1:b583jCggY9gE99b6G5LEC39OIiVsWj+R97kbl5odCEk= | |||
github.com/chenzhuoyu/base64x v0.0.0-20230717121745-296ad89f973d h1:77cEq6EriyTZ0g/qfRdp61a3Uu/AWrgIq2s0ClJV1g0= | |||
github.com/chenzhuoyu/base64x v0.0.0-20230717121745-296ad89f973d/go.mod h1:8EPpVsBuRksnlj1mLy4AWzRNQYxauNi62uWcE3to6eA= | |||
github.com/chenzhuoyu/iasm v0.9.0/go.mod h1:Xjy2NpN3h7aUqeqM+woSuuvxmIe6+DDsiNLIrkAmYog= | |||
github.com/chenzhuoyu/iasm v0.9.1 h1:tUHQJXo3NhBqw6s33wkGn9SP3bvrWLdlVIJ3hQBL7P0= | |||
github.com/chenzhuoyu/iasm v0.9.1/go.mod h1:Xjy2NpN3h7aUqeqM+woSuuvxmIe6+DDsiNLIrkAmYog= | |||
github.com/coocood/freecache v1.2.4 h1:UdR6Yz/X1HW4fZOuH0Z94KwG851GWOSknua5VUbb/5M= | |||
github.com/coocood/freecache v1.2.4/go.mod h1:RBUWa/Cy+OHdfTGFEhEuE1pMCMX51Ncizj7rthiQ3vk= | |||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= | |||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= | |||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= | |||
github.com/gabriel-vasile/mimetype v1.4.3 h1:in2uUcidCuFcDKtdcBxlR0rJ1+fsokWf+uqxgUFjbI0= | |||
github.com/gabriel-vasile/mimetype v1.4.3/go.mod h1:d8uq/6HKRL6CGdk+aubisF/M5GcPfT7nKyLpA0lbSSk= | |||
github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE= | |||
github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI= | |||
github.com/gin-gonic/gin v1.9.1 h1:4idEAncQnU5cB7BeOkPtxjfCSye0AAm1R0RVIqJ+Jmg= | |||
github.com/gin-gonic/gin v1.9.1/go.mod h1:hPrL7YrpYKXt5YId3A/Tnip5kqbEAP+KLuI3SUcPTeU= | |||
github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s= | |||
github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA= | |||
github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY= | |||
github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY= | |||
github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY= | |||
github.com/go-playground/validator/v10 v10.17.0 h1:SmVVlfAOtlZncTxRuinDPomC2DkXJ4E5T9gDA0AIH74= | |||
github.com/go-playground/validator/v10 v10.17.0/go.mod h1:9iXMNT7sEkjXb0I+enO7QXmzG6QCsPWY4zveKFVRSyU= | |||
github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU= | |||
github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= | |||
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= | |||
github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU= | |||
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= | |||
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= | |||
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= | |||
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= | |||
github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= | |||
github.com/klauspost/cpuid/v2 v2.2.6 h1:ndNyv040zDGIDh8thGkXYjnFtiN02M1PVVF+JE/48xc= | |||
github.com/klauspost/cpuid/v2 v2.2.6/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws= | |||
github.com/knz/go-libedit v1.10.1/go.mod h1:MZTVkCWyz0oBc7JOWP3wNAzd002ZbM/5hgShxwh4x8M= | |||
github.com/leodido/go-urn v1.3.0 h1:jX8FDLfW4ThVXctBNZ+3cIWnCSnrACDV73r76dy0aQQ= | |||
github.com/leodido/go-urn v1.3.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI= | |||
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= | |||
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= | |||
github.com/mattn/go-sqlite3 v1.14.20 h1:BAZ50Ns0OFBNxdAqFhbZqdPcht1Xlb16pDCqkq1spr0= | |||
github.com/mattn/go-sqlite3 v1.14.20/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y= | |||
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= | |||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= | |||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= | |||
github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= | |||
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= | |||
github.com/pelletier/go-toml/v2 v2.1.1 h1:LWAJwfNvjQZCFIDKWYQaM62NcYeYViCmWIwmOStowAI= | |||
github.com/pelletier/go-toml/v2 v2.1.1/go.mod h1:tJU2Z3ZkXwnxa4DPO899bsyIoywizdUvyaeZurnPPDc= | |||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= | |||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= | |||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= | |||
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= | |||
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= | |||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= | |||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= | |||
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= | |||
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= | |||
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= | |||
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= | |||
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= | |||
github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI= | |||
github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08= | |||
github.com/ugorji/go/codec v1.2.12 h1:9LC83zGrHhuUA9l16C9AHXAqEV/2wBQ4nkvumAE65EE= | |||
github.com/ugorji/go/codec v1.2.12/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg= | |||
golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= | |||
golang.org/x/arch v0.7.0 h1:pskyeJh/3AmoQ8CPE95vxHLqp1G1GfGNXTmcl9NEKTc= | |||
golang.org/x/arch v0.7.0/go.mod h1:FEVrYAQjsQXMVJ1nsMoVVXPZg6p2JE2mx8psSWTDQys= | |||
golang.org/x/crypto v0.18.0 h1:PGVlW0xEltQnzFZ55hkuX5+KLyrMYhHld1YHO4AKcdc= | |||
golang.org/x/crypto v0.18.0/go.mod h1:R0j02AL6hcrfOiy9T4ZYp/rcWeMxM3L6QYxlOuEG1mg= | |||
golang.org/x/net v0.20.0 h1:aCL9BSgETF1k+blQaYUBx9hJ9LOGP3gAVemcZlf1Kpo= | |||
golang.org/x/net v0.20.0/go.mod h1:z8BVo6PvndSri0LbOE3hAn0apkU+1YvI6E70E9jsnvY= | |||
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= | |||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= | |||
golang.org/x/sys v0.16.0 h1:xWw16ngr6ZMtmxDyKyIgsE93KNKz5HKmMa3b8ALHidU= | |||
golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= | |||
golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= | |||
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= | |||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= | |||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= | |||
google.golang.org/protobuf v1.32.0 h1:pPC6BG5ex8PDFnkbrGU3EixyhKcQ2aDuBS36lqK/C7I= | |||
google.golang.org/protobuf v1.32.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= | |||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= | |||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= | |||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= | |||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= | |||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= | |||
nullprogram.com/x/optparse v1.0.0/go.mod h1:KdyPE+Igbe0jQUrVfMqDMeJQIJZEuyV7pjYmp6pbG50= | |||
rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4= |
@@ -0,0 +1,291 @@ | |||
package main | |||
import ( | |||
"digimetastaffsync/business" | |||
"digimetastaffsync/common" | |||
"digimetastaffsync/mydatabase" | |||
"fmt" | |||
"github.com/gin-gonic/gin" | |||
"io" | |||
"log" | |||
"net/http" | |||
"os" | |||
"path/filepath" | |||
"strconv" | |||
"strings" | |||
) | |||
func init() { | |||
setupLogger() | |||
common.SetFlags(log.Ldate | log.Ltime) | |||
common.LoadConfig() | |||
} | |||
func setupLogger() { | |||
logsDir := "logs" | |||
logFileName := "web.log" | |||
logFilePath := filepath.Join(logsDir, logFileName) | |||
// 检查日志文件是否存在 | |||
if _, err := os.Stat(logFilePath); os.IsNotExist(err) { | |||
// 不存在则创建新文件 | |||
err := os.MkdirAll(logsDir, 0755) | |||
if err != nil { | |||
log.Fatalf("Error creating logs directory: %v", err) | |||
} | |||
// 创建日志文件 | |||
file, err := os.Create(logFilePath) | |||
if err != nil { | |||
log.Fatalf("Error creating log file: %v", err) | |||
} | |||
defer file.Close() | |||
// 设置 Gin 默认的写入器 | |||
gin.DefaultWriter = io.MultiWriter(file) | |||
} else { | |||
// 存在则打开已有文件 | |||
file, err := os.OpenFile(logFilePath, os.O_APPEND|os.O_WRONLY, os.ModeAppend) | |||
if err != nil { | |||
log.Fatalf("Error opening log file: %v", err) | |||
} | |||
defer file.Close() | |||
// 设置 Gin 默认的写入器 | |||
gin.DefaultWriter = io.MultiWriter(file) | |||
} | |||
// 设置 Gin 的日志输出 | |||
gin.SetMode(gin.ReleaseMode) | |||
} | |||
type Config struct { | |||
Port string `json:"port"` | |||
Phone string `json:"phone"` | |||
Mode string `json:"mode"` | |||
DevId string `json:"devId"` | |||
} | |||
func main() { | |||
router := gin.Default() | |||
router.LoadHTMLGlob("templates/*") | |||
router.GET("/", HomeHandler) | |||
router.GET("/reg", RegPageHandler) | |||
router.GET("/info", InfoPageHandler) | |||
router.POST("/send_validation_code", SendCodeHandler) | |||
router.POST("/valid_code", ValidCodeHandler) | |||
router.POST("/phone_login", PhoneLoginHandler) | |||
router.POST("/mgr_login", MgrLoginHandler) | |||
router.GET("/mgr", MgrPageHandler) | |||
router.GET("/test", TestHandler) | |||
router.GET("/register", RegisterPageHandler) | |||
router.POST("/register", RegisterHandler) | |||
router.POST("/pass", PassHandler) | |||
router.POST("/update", UpdateConfigHandler) | |||
common.Info(common.GenLogLine()+"file content:%s", common.ReadFile("di.txt")) | |||
defer mydatabase.GetDb().Close() | |||
port := common.ConfigData.Port | |||
if port == "" { | |||
port = "18080" | |||
log.Printf("Defaulting to port %s", port) | |||
} | |||
// 启动定时任务,用于同步人脸操作 | |||
go business.TimerHandle() | |||
log.Printf("Listening on port %s", port) | |||
log.Printf("Open http://localhost:%s in the browser", port) | |||
router.Static("/static", "./static") | |||
router.Run(fmt.Sprintf(":%s", port)) | |||
} | |||
// UpdateConfigHandler 更新配置 | |||
func UpdateConfigHandler(c *gin.Context) { | |||
var updateValues map[string]interface{} | |||
if err := c.BindJSON(&updateValues); err != nil { | |||
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) | |||
return | |||
} | |||
str := common.UpdateConfig(updateValues) | |||
if str != "" { | |||
c.JSON(http.StatusInternalServerError, gin.H{"message": str}) | |||
return | |||
} | |||
//更新配置文件变量configData | |||
common.LoadConfig() | |||
c.JSON(http.StatusOK, gin.H{"message": "Config updated successfully"}) | |||
} | |||
func HomeHandler(c *gin.Context) { | |||
t := c.Query("type") | |||
c.HTML(http.StatusOK, "login.html", gin.H{ | |||
"type": t, | |||
}) | |||
} | |||
func RegPageHandler(c *gin.Context) { | |||
c.HTML(http.StatusOK, "reg.html", nil) | |||
} | |||
func InfoPageHandler(c *gin.Context) { | |||
staffId := c.Query("staffId") | |||
res, err := business.StaffInfo(staffId) | |||
if err != nil { | |||
c.HTML(http.StatusOK, "info.html", gin.H{ | |||
"err": err.Error(), | |||
}) | |||
} | |||
fmt.Printf("res:%v", res) | |||
c.HTML(http.StatusOK, "info.html", gin.H{ | |||
"info": res, | |||
}) | |||
} | |||
func PhoneLoginHandler(c *gin.Context) { | |||
phone := c.PostForm("phone") | |||
res, err := business.PhoneLogin(phone) | |||
if err != nil { | |||
c.JSON(http.StatusInternalServerError, err.Error()) | |||
} | |||
c.JSON(http.StatusOK, res) | |||
} | |||
func MgrLoginHandler(c *gin.Context) { | |||
phone := c.PostForm("userName") | |||
pwd := c.PostForm("password") | |||
str := business.MgrLogin(phone, pwd) | |||
c.JSON(http.StatusOK, str) | |||
} | |||
func SendCodeHandler(c *gin.Context) { | |||
phone := c.PostForm("phone") | |||
str := business.SendCode(phone) | |||
c.JSON(http.StatusOK, str) | |||
} | |||
func ValidCodeHandler(c *gin.Context) { | |||
phone := c.PostForm("phone") | |||
code := c.PostForm("code") | |||
str, err := business.ValidCode(phone, code) | |||
if err != nil { | |||
c.JSON(http.StatusInternalServerError, err.Error()) | |||
} | |||
c.JSON(http.StatusOK, str) | |||
} | |||
// RegisterPageHandler 处理注册页面请求 | |||
func RegisterPageHandler(c *gin.Context) { | |||
c.HTML(http.StatusOK, "register.html", map[string]interface{}{"Message": ""}) | |||
} | |||
// MgrPageHandler 处理管理页面请求 | |||
func MgrPageHandler(c *gin.Context) { | |||
key := c.Query("key") | |||
users, err := mydatabase.Select(key) | |||
if err != nil { | |||
log.Fatal(err) | |||
} | |||
if err != nil { | |||
common.Error("Error marshaling JSON:%s", err) | |||
return | |||
} | |||
c.HTML(http.StatusOK, "mgr.html", gin.H{ | |||
"users": users, | |||
"key": key, | |||
}) | |||
} | |||
func TestHandler(c *gin.Context) { | |||
fmt.Printf("timer: ====%d\n", common.ConfigData.Timer) | |||
c.JSON(http.StatusOK, "request successfully") | |||
} | |||
// RegisterHandler 处理注册页面请求 | |||
func RegisterHandler(c *gin.Context) { | |||
// 从表单中获取用户输入 | |||
username := c.PostForm("staffName") | |||
phone := c.PostForm("staffPhone") | |||
avatar := c.PostForm("avatar") | |||
emp, _ := mydatabase.SelectOneByPhone(phone) | |||
fmt.Println("====phone:" + phone) | |||
fmt.Println(emp) | |||
if emp.ID > 0 { | |||
c.JSON(http.StatusInternalServerError, map[string]interface{}{"Message": "已存在该手机号对应的员工,请查验后重试!"}) | |||
return | |||
} | |||
// 在实际应用中,你可能会将用户信息保存到数据库中 | |||
avatar = strings.ReplaceAll(avatar, "data:image/jpeg;base64,", "") | |||
features, imgName, err := business.LocalFetchStaffFaceFeature(avatar) | |||
if err != nil { | |||
c.JSON(http.StatusInternalServerError, map[string]interface{}{"Message": err.Error()}) | |||
return | |||
} | |||
mydatabase.Insert(username, 0, phone, imgName, features, 1) | |||
// 将注册成功的消息渲染到页面 | |||
message := fmt.Sprintf("Registration successful! %s %s %s %s!", username, phone, imgName, features) | |||
fmt.Println(message) | |||
c.JSON(http.StatusOK, map[string]interface{}{"Message": "注册成功,请等待审核!"}) | |||
} | |||
// PassHandler 审核通过或拒绝的处理函数 | |||
func PassHandler(c *gin.Context) { | |||
// 从表单中获取用户输入 | |||
id := c.PostForm("id") | |||
handleType := c.PostForm("handle") | |||
handleTypeInt, _ := strconv.Atoi(handleType) | |||
if handleTypeInt != 1 && handleTypeInt != 2 && handleTypeInt != 4 { | |||
c.JSON(http.StatusInternalServerError, map[string]interface{}{"Message": "handleType参数错误!"}) | |||
return | |||
} | |||
idInt, _ := strconv.Atoi(id) | |||
emp, err := mydatabase.SelectOne(idInt) | |||
if err != nil || !(emp.ID > 0) { | |||
c.JSON(http.StatusInternalServerError, map[string]interface{}{"Message": "指定id未查询到记录"}) | |||
return | |||
} | |||
if handleTypeInt == 1 { | |||
emp.Avatar = strings.ReplaceAll(emp.Avatar, "data:image/jpeg;base64,", "") | |||
//将员工信息提交到后台 | |||
resp, err := business.RegStaff(business.EmpToReq(emp)) | |||
if err != nil { | |||
c.JSON(http.StatusOK, map[string]interface{}{"Message": err.Error()}) | |||
return | |||
} | |||
if resp != nil && resp.Code != 0 { | |||
c.JSON(http.StatusOK, map[string]interface{}{"Message": resp.Msg}) | |||
return | |||
} | |||
//更新sqllite里面数据状态 | |||
mydatabase.Update(emp.ID, emp.Name, emp.Phone, emp.Avatar, 1, 1) | |||
c.JSON(http.StatusOK, map[string]interface{}{"Message": "操作成功,注册流程结束!"}) | |||
} else if handleTypeInt == 2 { | |||
//更新sqllite里面数据状态 | |||
mydatabase.SoftDelete(emp.ID) | |||
c.JSON(http.StatusOK, map[string]interface{}{"Message": "操作成功"}) | |||
} else if handleTypeInt == 4 { | |||
//删除数据 | |||
mydatabase.Delete(emp.ID) | |||
//删除指定路径图片 | |||
if emp.Avatar != "" { | |||
os.Remove(emp.Avatar) | |||
} | |||
c.JSON(http.StatusOK, map[string]interface{}{"Message": "操作成功"}) | |||
} | |||
} |
@@ -0,0 +1,48 @@ | |||
package mydatabase | |||
import ( | |||
"database/sql" | |||
"fmt" | |||
_ "github.com/mattn/go-sqlite3" | |||
"sync" | |||
) | |||
var ( | |||
db2 *Database | |||
mu2 sync.Mutex | |||
) | |||
// Database 结构体封装了数据库连接和相关的操作方法 | |||
type Database struct { | |||
db *sql.DB | |||
} | |||
// NewDatabase 创建一个新的 Database 实例 | |||
func NewDatabase(dbPath string) *Database { | |||
db, err := sql.Open("sqlite3", dbPath) | |||
if err != nil { | |||
fmt.Printf("Failed to connect to database: %v", err) | |||
return nil | |||
} | |||
return &Database{db} | |||
} | |||
// Close 关闭数据库连接 | |||
func (d *Database) Close() error { | |||
return d.db.Close() | |||
} | |||
// GetDb 返回单例缓存对象 | |||
func GetDb() *Database { | |||
if db2 == nil { | |||
mu2.Lock() | |||
defer mu2.Unlock() | |||
if db2 == nil { | |||
cache := NewDatabase("./staffs.db") | |||
cache.Create() | |||
db2 = cache | |||
} | |||
} | |||
return db2 | |||
} |
@@ -0,0 +1,147 @@ | |||
package mydatabase | |||
import ( | |||
"fmt" | |||
"log" | |||
"time" | |||
) | |||
type Emp struct { | |||
ID int | |||
Eno int // 员工的ID | |||
Name string | |||
Phone string | |||
Avatar string | |||
Features string | |||
Level int | |||
Status int | |||
UpdateTime string | |||
CreateTime string | |||
} | |||
func (d *Database) Create() error { | |||
createTableStmt := ` | |||
CREATE TABLE IF NOT EXISTS staff ( | |||
id INTEGER PRIMARY KEY AUTOINCREMENT, | |||
eno INTEGER, | |||
name TEXT NOT NULL, | |||
phone TEXT, | |||
avatar TEXT, | |||
level INTEGER, | |||
status INTEGER DEFAULT 0, | |||
features TEXT, | |||
create_time DATETIME, | |||
update_time DATETIME DEFAULT CURRENT_TIMESTAMP | |||
); | |||
` | |||
_, err := d.db.Exec(createTableStmt) | |||
if err != nil { | |||
log.Fatal(err) | |||
} | |||
return err | |||
} | |||
func Insert(name string, eno int, phone string, avatar string, features string, level int) error { | |||
insertStmt := "INSERT INTO staff (name,eno, phone, avatar,features, level, create_time) VALUES (?, ?, ?, ?,?, ?, ?)" | |||
eventTime := time.Now() | |||
// 将时间格式化为 SQLite 支持的 DATETIME 格式("2006-01-02 15:04:05") | |||
formattedTime := eventTime.Format("2006-01-02 15:04:05") | |||
_, err := GetDb().db.Exec(insertStmt, name, eno, phone, avatar, features, level, formattedTime) | |||
if err != nil { | |||
log.Fatal(err) | |||
} | |||
return err | |||
} | |||
func Update(id int, name string, phone string, avatar string, level int, status int) error { | |||
updateStmt := "UPDATE staff SET phone = ?, name = ?, avatar = ?, level=?, status=? WHERE id = ?" | |||
_, err := GetDb().db.Exec(updateStmt, phone, name, avatar, level, status, id) | |||
if err != nil { | |||
log.Fatal(err) | |||
} | |||
return err | |||
} | |||
func Delete(id int) { | |||
deleteStmt := "DELETE FROM staff WHERE id = ?" | |||
_, err := GetDb().db.Exec(deleteStmt, id) | |||
if err != nil { | |||
log.Fatal(err) | |||
} | |||
} | |||
func SoftDelete(id int) error { | |||
updateStmt := "UPDATE staff SET status=2 WHERE id = ?" | |||
_, err := GetDb().db.Exec(updateStmt, id) | |||
if err != nil { | |||
log.Fatal(err) | |||
} | |||
return err | |||
} | |||
func Select(key string) ([]Emp, error) { | |||
str := "SELECT id, eno, name, phone, avatar,features, level, status, create_time, update_time FROM staff" | |||
if key != "" { | |||
str += " WHERE name LIKE '%" + key + "%' or phone LIKE '%" + key + "%'" | |||
} | |||
rows, err := GetDb().db.Query(str + " order by status, update_time desc") | |||
if err != nil { | |||
log.Fatal(err) | |||
} | |||
defer rows.Close() | |||
var users []Emp | |||
for rows.Next() { | |||
var user Emp | |||
err := rows.Scan(&user.ID, &user.Eno, &user.Name, &user.Phone, &user.Avatar, &user.Features, &user.Level, &user.Status, &user.CreateTime, &user.UpdateTime) | |||
if err != nil { | |||
return nil, err | |||
} | |||
users = append(users, user) | |||
} | |||
return users, nil | |||
} | |||
func SelectOne(id int) (Emp, error) { | |||
rows, err := GetDb().db.Query("SELECT id, eno, name, phone, avatar,features, level, status, create_time, update_time FROM staff where id = ? LIMIT 1", id) | |||
if err != nil { | |||
log.Fatal(err) | |||
} | |||
defer rows.Close() | |||
var user Emp | |||
if rows.Next() { | |||
err := rows.Scan(&user.ID, &user.Eno, &user.Name, &user.Phone, &user.Avatar, &user.Features, &user.Level, &user.Status, &user.CreateTime, &user.UpdateTime) | |||
if err != nil { | |||
return user, err | |||
} | |||
} | |||
if err := rows.Err(); err != nil { | |||
return user, err | |||
} | |||
return user, nil | |||
} | |||
func SelectOneByPhone(phone string) (Emp, error) { | |||
fmt.Printf("SelectOneByPhone phone:%s\n", phone) | |||
rows, err := GetDb().db.Query("SELECT id, eno, name, phone, avatar,features, level, status, create_time, update_time FROM staff where phone = ? and status<>2 LIMIT 1", phone) | |||
if err != nil { | |||
log.Fatal(err) | |||
} | |||
defer rows.Close() | |||
var user Emp | |||
if rows.Next() { | |||
err := rows.Scan(&user.ID, &user.Eno, &user.Name, &user.Phone, &user.Avatar, &user.Features, &user.Level, &user.Status, &user.CreateTime, &user.UpdateTime) | |||
if err != nil { | |||
return user, err | |||
} | |||
} | |||
if err := rows.Err(); err != nil { | |||
return user, err | |||
} | |||
return user, nil | |||
} |
@@ -0,0 +1,159 @@ | |||
//生成Html | |||
var GenerateHtml = function(type, title, msg) { | |||
var _html = ""; | |||
_html += '<div id="mb_box"></div><div id="mb_con"><span id="mb_tit">' + title + '</span>'; | |||
_html += '<a id="mb_ico">x</a><div id="mb_msg" style="text-align:center;">' + msg + '</div><div id="mb_btnbox">'; | |||
if (type == "alert") { | |||
_html += '<input id="mb_btn_ok" type="button" value="确定" />'; | |||
} | |||
if (type == "confirm") { | |||
_html += '<input id="mb_btn_ok" type="button" value="确定" />'; | |||
_html += '<input id="mb_btn_no" type="button" value="取消" />'; | |||
} | |||
_html += '</div></div>'; | |||
//必须先将_html添加到body,再设置Css样式 | |||
$("body").append(_html); | |||
//生成Css | |||
GenerateCss(); | |||
} | |||
//生成Css | |||
var GenerateCss = function() { | |||
var _widht = document.documentElement.clientWidth; //屏幕宽 | |||
var _height = document.documentElement.clientHeight; //屏幕高 | |||
var isPhonePage = 0; | |||
if (_widht<_height) { | |||
isPhonePage = 1; | |||
} | |||
$("#mb_box").css({ | |||
width: '100%', | |||
height: '100%', | |||
zIndex: '99999', | |||
position: 'fixed', | |||
filter: 'Alpha(opacity=60)', | |||
backgroundColor: 'black', | |||
top: '0', | |||
left: '0', | |||
opacity: '0.6' | |||
}); | |||
$("#mb_con").css({ | |||
zIndex: '999999', | |||
width: isPhonePage?'80%':'400px', | |||
position: 'fixed', | |||
backgroundColor: 'White', | |||
borderRadius: '15px' | |||
}); | |||
$("#mb_tit").css({ | |||
display: 'block', | |||
fontSize: '14px', | |||
color: '#444', | |||
padding: '10px 15px', | |||
backgroundColor: '#DDD', | |||
borderRadius: '15px 15px 0 0', | |||
borderBottom: '3px solid #009BFE', | |||
fontWeight: 'bold' | |||
}); | |||
$("#mb_msg").css({ | |||
padding: '20px', | |||
lineHeight: '20px', | |||
borderBottom: '1px dashed #DDD', | |||
fontSize: '13px' | |||
}); | |||
$("#mb_ico").css({ | |||
display: 'block', | |||
position: 'absolute', | |||
right: '10px', | |||
top: '9px', | |||
border: '1px solid Gray', | |||
width: '18px', | |||
height: '18px', | |||
textAlign: 'center', | |||
lineHeight: '16px', | |||
cursor: 'pointer', | |||
borderRadius: '12px', | |||
fontFamily: '微软雅黑' | |||
}); | |||
$("#mb_btnbox").css({ | |||
margin: '15px 0 10px 0', | |||
textAlign: 'center' | |||
}); | |||
$("#mb_btn_ok,#mb_btn_no").css({ | |||
width: '85px', | |||
height: '30px', | |||
color: 'white', | |||
border: 'none' | |||
}); | |||
$("#mb_btn_ok").css({ | |||
backgroundColor: '#168bbb' | |||
}); | |||
$("#mb_btn_no").css({ | |||
backgroundColor: 'gray', | |||
marginLeft: '20px' | |||
}); | |||
//右上角关闭按钮hover样式 | |||
$("#mb_ico").hover(function() { | |||
$(this).css({ | |||
backgroundColor: 'Red', | |||
color: 'White' | |||
}); | |||
}, function() { | |||
$(this).css({ | |||
backgroundColor: '#DDD', | |||
color: 'black' | |||
}); | |||
}); | |||
console.log($(document.body).width()) | |||
console.log(_widht) | |||
var boxWidth = $("#mb_con").width(); | |||
var boxHeight = $("#mb_con").height(); | |||
//让提示框居中 | |||
$("#mb_con").css({ | |||
top: (_height - boxHeight) / 2 + "px", | |||
left: (_widht - boxWidth) / 2 + "px" | |||
}); | |||
} | |||
//确定按钮事件 | |||
var btnOk = function(callback) { | |||
$("#mb_btn_ok").click(function() { | |||
$("#mb_box,#mb_con").remove(); | |||
if (typeof(callback) == 'function') { | |||
callback(); | |||
} | |||
}); | |||
} | |||
//取消按钮事件 | |||
var btnNo = function() { | |||
$("#mb_btn_no,#mb_ico").click(function() { | |||
$("#mb_box,#mb_con").remove(); | |||
}); | |||
} | |||
var btnDel = function(callback) { | |||
$("#mb_ico").click(function() { | |||
$("#mb_box,#mb_con").remove(); | |||
if (typeof(callback) == 'function') { | |||
callback(); | |||
} | |||
}); | |||
} | |||
$.MsgBox = { | |||
Alert: function(title, msg) { | |||
GenerateHtml("alert", title, msg); | |||
btnOk(); //alert只是弹出消息,因此没必要用到回调函数callback | |||
btnNo(); | |||
}, | |||
AlertWithCallback: function(title, msg, callback) { | |||
GenerateHtml("alert", title, msg); | |||
btnOk(callback); //alert只是弹出消息,因此没必要用到回调函数callback | |||
btnNo(); | |||
btnDel(callback) | |||
}, | |||
Confirm: function(title, msg, callback) { | |||
GenerateHtml("confirm", title, msg); | |||
btnOk(callback); | |||
btnNo(); | |||
} | |||
} |
@@ -0,0 +1,8 @@ | |||
body { | |||
background-color: #f0f0f0; | |||
font-family: Arial, sans-serif; | |||
} | |||
h1 { | |||
color: #333; | |||
} |
@@ -0,0 +1,380 @@ | |||
<!DOCTYPE html> | |||
<html lang="en"> | |||
<head> | |||
<meta charset="UTF-8"> | |||
<meta name="viewport" content="width=device-width, initial-scale=1.0"> | |||
<title>信息页面</title> | |||
<style> | |||
body{ | |||
margin: 0; | |||
} | |||
li { | |||
list-style-type: none; | |||
} | |||
@media screen and (orientation: portrait) { | |||
.login { | |||
width: 100vw; | |||
height: 100vh; | |||
background-image: url("/static/img/phoneBgc.jpg"); | |||
background-size: 100% 100%; | |||
background-repeat: no-repeat; | |||
} | |||
.register { | |||
background-image: url("/static/img/registerBgc.jpg") !important; | |||
padding-top: 15vh; | |||
} | |||
.register_loginTitle { | |||
width: 100vw; | |||
font-size: 8vw; | |||
text-align: center; | |||
} | |||
.register_inputBox { | |||
display: flex; | |||
flex-direction: column; | |||
justify-content: center; | |||
align-items: center; | |||
margin-top: 5vh; | |||
position: relative; | |||
} | |||
.register_phoneInput { | |||
width: 50vw; | |||
height: 5vh; | |||
border-radius: 2vw; | |||
background-color: transparent; | |||
font-size: 3vw; | |||
padding-left: 2vw; | |||
border: 1px solid #000; | |||
margin-bottom: 2vh; | |||
} | |||
.register_nameInput { | |||
width: 50vw; | |||
height: 5vh; | |||
border-radius: 2vw; | |||
background-color: transparent; | |||
font-size: 3vw; | |||
padding-left: 2vw; | |||
border: 1px solid #000; | |||
margin-bottom: 2vh; | |||
} | |||
.reg_button { | |||
width: 40vw; | |||
height: 5vh; | |||
background-color: rgb(101, 161, 255); | |||
border-radius: 10vw; | |||
display: flex; | |||
justify-content: center; | |||
align-items: center; | |||
color:#fff; | |||
font-size: 4vw; | |||
margin: 2vh 0 0 30vw; | |||
} | |||
.register_loginButton { | |||
width: 40vw; | |||
height: 5vh; | |||
background-color: rgb(101, 161, 255); | |||
border-radius: 10vw; | |||
display: flex; | |||
justify-content: center; | |||
align-items: center; | |||
color:#fff; | |||
font-size: 4vw; | |||
margin: 2vh 0 0 30vw; | |||
} | |||
.uploadImg{ | |||
width: 46vw !important; | |||
transform: translate(0%, 0%) !important; | |||
left: 27vw !important; | |||
position: relative; | |||
} | |||
} | |||
@media screen and (orientation: landscape) { | |||
input:focus { | |||
border: 0.1vw solid #000; | |||
outline: none; /* 可选,用于去除默认的外边框样式 */ | |||
} | |||
.login { | |||
width: 100vw; | |||
height: 100vh; | |||
background-image: url("/static/img/phoneBgc_pc.jpg"); | |||
background-size: 100% 100%; | |||
background-repeat: no-repeat; | |||
position: relative; | |||
} | |||
.register { | |||
background-image: url("/static/img/registerBgc_pc.jpg") !important; | |||
} | |||
.register_loginTitle { | |||
width: 100vw; | |||
display: flex; | |||
justify-content: center; | |||
font-size: 4vh; | |||
text-align: center; | |||
position: absolute; | |||
z-index: 10; | |||
top: 10vh; | |||
} | |||
.uploadImg { | |||
width: 15vw; | |||
} | |||
.register_inputBox { | |||
width: 100vw; | |||
display: flex; | |||
flex-direction: column; | |||
justify-content: center; | |||
align-items: center; | |||
position: relative; | |||
padding-top: 42vh; | |||
} | |||
.register_phoneInput { | |||
width: 37vh; | |||
height: 6vh; | |||
border-radius: 2vh; | |||
background-color: transparent; | |||
font-size: 3vh; | |||
border: 0.1vw solid #000; | |||
margin-bottom: 5vh; | |||
padding-left:1vw ; | |||
} | |||
.register_nameInput { | |||
width: 37vh; | |||
height: 6vh; | |||
border-radius: 2vh; | |||
background-color: transparent; | |||
font-size: 3vh; | |||
border: 0.1vw solid #000; | |||
padding-left: 1vw ; | |||
margin-bottom: 2vh; | |||
} | |||
.reg_button { | |||
width: 16vw; | |||
height: 3vw; | |||
background-color: rgb(101, 161, 255); | |||
border-radius: 10vh; | |||
display: flex; | |||
justify-content: center; | |||
align-items: center; | |||
color: #fff; | |||
font-size: 2vw; | |||
/* margin: 2vh 0 0 30vh; */ | |||
position: absolute; | |||
left: 55vw; | |||
top: 65vh; | |||
} | |||
.register_loginButton { | |||
width: 8vw; | |||
height: 2vw; | |||
background-color: rgb(101, 161, 255); | |||
border-radius: 1vw; | |||
display: flex; | |||
justify-content: center; | |||
align-items: center; | |||
color: #fff; | |||
font-size: 3vh; | |||
position: absolute; | |||
left: 46vw; | |||
top: 65vh; | |||
} | |||
.hand:hover{ | |||
cursor: pointer; | |||
} | |||
.uploadImg{ | |||
width: 200px !important; | |||
transform: translate(0%, 0%) !important; | |||
left: 2vw !important; | |||
position: relative; | |||
} | |||
} | |||
.upload-img-box { | |||
position: relative; | |||
} | |||
.upload-img-box .input-box { | |||
display: inline-block; | |||
width: 144px; | |||
height: 144px; | |||
/*border: solid black 1px;*/ | |||
} | |||
.upload-img-box .befor-img { | |||
display: flex; | |||
/*width: 300px;*/ | |||
/*height: 90px;*/ | |||
/*border: solid black 1px;*/ | |||
position: absolute; | |||
top: 0px; | |||
left: 0px; | |||
/*background: #ffffff;*/ | |||
z-index: 30; | |||
align-items: center; | |||
justify-content: center; | |||
} | |||
.upload-img-box .befor-img.hasImg { | |||
display: none; | |||
} | |||
.upload-img-box .after-img { | |||
display: inline-block; | |||
width: 144px; | |||
height: 144px; | |||
border: none; | |||
/*position: absolute;*/ | |||
top: 0px; | |||
left: 0px; | |||
/*background: #ffffff;*/ | |||
z-index: 20; | |||
} | |||
.after-img img, .uploadImg { | |||
/*position: absolute;*/ | |||
width: 100%; | |||
height: 100%; | |||
object-fit: cover; /*根据父容器的尺寸裁剪和缩放图片,以填充整个容器,并保持长宽比例不变。*/ | |||
object-position: center; /*指定对象的位置,如果不设置,则默认是center*/ | |||
background-size: cover; /*背景图片的大小,如果不设置,则默认是auto*/ | |||
background-position: center; | |||
top: 50%; | |||
left: 50%; | |||
transform: translate(-50%, 0%);/*将元素移动到中心*/ | |||
border-radius: 50%; | |||
} | |||
</style> | |||
</head> | |||
<body> | |||
<!-- 注册页面 --> | |||
<div class="register login"> | |||
<div class="register_loginTitle "> | |||
<div class="upload-img-box"> | |||
<div class="input-box"> | |||
<input type="file" id="img-file" hidden="hidden" name="选择图片"> | |||
</div> | |||
<div class="befor-img"> | |||
<img class="uploadImg hand" src="/static/img/upload.png" alt=""> | |||
</div> | |||
<div class="after-img"> | |||
<img id="img-box" src="" width="30%" height="auto"> | |||
</div> | |||
</div> | |||
</div> | |||
<div class="register_inputBox"> | |||
{{ if .info }} | |||
<input class="register_nameInput" name="staffName" type="text" placeholder="员工姓名" value="{{.info.userName}}"> | |||
<input class="register_phoneInput" name="staffPhone" type="text" placeholder="员工手机号" value="{{.info.phone}}"> | |||
{{else}} | |||
<input class="register_nameInput" name="staffName" type="text" placeholder="员工姓名"> | |||
<input class="register_phoneInput" name="staffPhone" type="text" placeholder="员工手机号"> | |||
{{ end }} | |||
</div> | |||
<div class="register_loginButton hand">修改信息</div> | |||
</div> | |||
<script src="/static/js/jquery.min.js"></script> | |||
<script src="/static/js/msg-box.js"></script> | |||
<script> | |||
$(function(){ | |||
if ("{{.err}}"){ | |||
$.MsgBox.Alert("错误", "{{.err}}"); | |||
return; | |||
} | |||
$.MsgBox = { | |||
Alert: function(title, msg) { | |||
GenerateHtml("alert", title, msg); | |||
btnOk(); //alert只是弹出消息,因此没必要用到回调函数callback | |||
btnNo(); | |||
}, | |||
Confirm: function(title, msg, callback) { | |||
GenerateHtml("confirm", title, msg); | |||
btnOk(callback); | |||
btnNo(); | |||
} | |||
} | |||
$(".register_loginButton").on("click",function() { | |||
var staffPhone = $(".register_phoneInput").val(); | |||
var staffName = $(".register_nameInput").val(); | |||
const regex = /^1[3-9]\d{9}$/; | |||
if (staffPhone == "" || !regex.test(staffPhone)){ | |||
$.MsgBox.Alert("提示", "手机号为空或不合法,请检查"); | |||
return; | |||
} | |||
if (staffName == ""){ | |||
$.MsgBox.Alert("提示", "员工姓名为空,请检查"); | |||
return; | |||
} | |||
var img = $("#img-box").attr("src"); | |||
console.log(img); | |||
$.ajax({ | |||
url: "/register", | |||
type: "post", | |||
data: { | |||
staffPhone: staffPhone, | |||
staffName: staffName, | |||
avatar: img | |||
}, | |||
success: function(data) { | |||
$.MsgBox.Alert("提示", data.Message); | |||
}, | |||
error: function(error) { | |||
console.log(error); | |||
$.MsgBox.Alert("提示", error.responseJSON.Message); | |||
} | |||
}) | |||
}) | |||
$(document).on("click", ".upload-img-box .befor-img,.upload-img-box .after-img", function (e) { | |||
$(".input-box input").trigger("click"); | |||
}) | |||
// 使用input 的change事件,监听当文件上传的值进行改变的时候,才触发事件。 | |||
$(document).on("change", ".upload-img-box #img-file", function () { | |||
var file = $("#img-file")[0].files[0]; | |||
console.log(file); | |||
// file 内容包括: lastModified , lastModifiedDate , name , size , type | |||
var formdata = new FormData(); | |||
formdata.append('file', file); | |||
if (window.FileReader) { | |||
var fr = new FileReader(); | |||
fr.onloadend = function (e) { | |||
// console.log(this.result); | |||
// document.getElementById("portrait").src = e.target.result; | |||
$("#img-box").attr("src",e.target.result) | |||
$(".upload-img-box .befor-img").addClass("hasImg") | |||
}; | |||
//给FileReader对象一个读取完成的方法, | |||
//使用readAsDataURL会返回一个url | |||
//这个值就保存在事件对象的result里 | |||
//img通过加载这个地址,完成图片的加载 | |||
fr.readAsDataURL(file); | |||
} | |||
//判断图片大小 | |||
if (file.size > 3 * 1024 * 1024) { | |||
alert("上传图片不能大于3M"); | |||
} | |||
//判断图片数据类型 | |||
if (!/.(gif|jpg|jpeg|png|GIF|JPG|bmp)$/.test(file.name)) { | |||
alert("图片类型必须是.gif,jpeg,jpg,png,bmp中的一种"); | |||
} | |||
}) | |||
}) | |||
</script> | |||
</body> | |||
</html> |
@@ -0,0 +1,871 @@ | |||
<!DOCTYPE html> | |||
<html lang="en"> | |||
<head> | |||
<meta charset="UTF-8"> | |||
<meta name="viewport" content="width=device-width, initial-scale=1.0"> | |||
<title>Document</title> | |||
<style> | |||
body{ | |||
margin: 0; | |||
} | |||
li { | |||
list-style-type: none; | |||
} | |||
@media screen and (orientation: portrait) { | |||
.login { | |||
width: 100vw; | |||
height: 100vh; | |||
background-image: url("/static/img/phoneBgc.jpg"); | |||
background-size: 100% 100%; | |||
background-repeat: no-repeat; | |||
} | |||
.register { | |||
background-image: url("/static/img/registerBgc.jpg") !important; | |||
padding-top: 15vh; | |||
} | |||
.logo { | |||
width: 15vw; | |||
margin: 4vw 0 0 4vw; | |||
} | |||
.login_title { | |||
width: 100vw; | |||
font-size: 8vw; | |||
text-align: center; | |||
margin-top: 15vh; | |||
} | |||
.register_loginTitle { | |||
width: 100vw; | |||
font-size: 8vw; | |||
text-align: center; | |||
} | |||
.input_box { | |||
width: 100vw; | |||
height: 25vw; | |||
display: flex; | |||
flex-direction: column; | |||
justify-content: center; | |||
align-items: center; | |||
margin-top: 5vh; | |||
position: relative; | |||
} | |||
.register_inputBox { | |||
display: flex; | |||
flex-direction: column; | |||
justify-content: center; | |||
align-items: center; | |||
margin-top: 5vh; | |||
position: relative; | |||
} | |||
.phone_input{ | |||
width: 50vw; | |||
height: 11vw; | |||
border-radius: 2vw; | |||
background-color: transparent; | |||
font-size: 3vw; | |||
padding-left: 2vw; | |||
border: 1px solid #000; | |||
position: absolute; | |||
top: 0vw; | |||
} | |||
.register_phoneInput { | |||
width: 50vw; | |||
height: 5vh; | |||
border-radius: 2vw; | |||
background-color: transparent; | |||
font-size: 3vw; | |||
padding-left: 2vw; | |||
border: 1px solid #000; | |||
margin-bottom: 2vh; | |||
} | |||
.code_input { | |||
width: 50vw; | |||
height: 11vw; | |||
margin-top: 2vh; | |||
border-radius: 2vw; | |||
padding-left: 2vw; | |||
font-size: 3vw; | |||
background-color: transparent; | |||
border: 1px solid #000; | |||
position: absolute; | |||
top: 10vw; | |||
} | |||
.register_codeInput { | |||
width: 50vw; | |||
height: 5vh; | |||
border-radius: 2vw; | |||
background-color: transparent; | |||
font-size: 3vw; | |||
padding-left: 2vw; | |||
border: 1px solid #000; | |||
} | |||
.login_button { | |||
width: 40vw; | |||
height: 5vh; | |||
background-color: rgb(101, 161, 255); | |||
border-radius: 10vw; | |||
display: flex; | |||
justify-content: center; | |||
align-items: center; | |||
color:#fff; | |||
font-size: 4vw; | |||
margin: 2vh 0 0 30vw; | |||
} | |||
.register_loginButton { | |||
width: 40vw; | |||
height: 5vh; | |||
background-color: rgb(101, 161, 255); | |||
border-radius: 10vw; | |||
display: flex; | |||
justify-content: center; | |||
align-items: center; | |||
color:#fff; | |||
font-size: 4vw; | |||
margin: 2vh 0 0 30vw; | |||
} | |||
.send_code { | |||
position: absolute; | |||
font-size: 2.5vw; | |||
top: 18.5vw; | |||
right: 30vw; | |||
border-left: 2px solid; | |||
padding-left: 2vw; | |||
} | |||
.employee { | |||
display: flex; | |||
align-items: center; | |||
} | |||
.administrator { | |||
display: flex; | |||
align-items: center; | |||
margin-left: 5vw; | |||
} | |||
.choose_employee { | |||
width: 2vw; | |||
height: 2vw; | |||
border-radius: 50%; | |||
border: 2px solid #000; | |||
margin-right: 1vw; | |||
} | |||
.choose_administrator { | |||
width: 2vw; | |||
height: 2vw; | |||
border-radius: 50%; | |||
border: 2px solid #000; | |||
margin-right: 1vw; | |||
} | |||
.login_style { | |||
display: flex; | |||
justify-content: center; | |||
align-items: center; | |||
font-size: 2.5vw; | |||
margin-top: 2vh; | |||
} | |||
.hidden { | |||
display: none; | |||
} | |||
.active { | |||
display: flex; | |||
} | |||
.background { | |||
background-color: #000; | |||
} | |||
.password-container { | |||
position: relative; | |||
} | |||
.password_toggle { | |||
position: absolute; | |||
width: 5vw; | |||
top: 18vw; | |||
right: 26vw; | |||
} | |||
.approval_page { | |||
width: 100vw; | |||
height: 100vh; | |||
background-image: url("/static/img/registerBgc.jpg"); | |||
background-size: 100% 100%; | |||
overflow: auto; | |||
} | |||
.approval_box { | |||
max-width: 100vw; | |||
min-height: 100vh; | |||
background-color:rgba(237,237,237,0.8); | |||
} | |||
.search_people { | |||
width: 80vw; | |||
height: 5vh; | |||
border-radius: 1vw; | |||
margin: 5vh 0 0 10vw; | |||
border: 0 solid #fff; | |||
font-size: 3vw; | |||
text-align: center; | |||
} | |||
.every_info { | |||
height: 7vh; | |||
margin-top: 3vh; | |||
display: flex; | |||
align-items: center; | |||
justify-content: space-around; | |||
font-size: 3vw; | |||
} | |||
#scroll-to-top-btn { | |||
display: none; | |||
position: fixed; | |||
right: 20px; | |||
bottom: 20px; | |||
width: 7vw; | |||
height: 10vh; | |||
color: #fff; | |||
border: none; | |||
border-radius: 5px; | |||
font-size: 3vw; | |||
cursor: pointer; | |||
} | |||
.people_img { | |||
width: 6vh; | |||
height: 6vh; | |||
} | |||
.pass_nopass { | |||
display: flex; | |||
} | |||
.pass { | |||
background-color: rgb(92, 186, 45); | |||
width: 10vw; | |||
height: 5vw; | |||
border-radius: 1vw; | |||
display: flex; | |||
justify-content: center; | |||
align-items: center; | |||
} | |||
.no_pass { | |||
background-color: rgb(187, 44, 45); | |||
width: 10vw; | |||
height: 5vw; | |||
border-radius: 1vw; | |||
display: flex; | |||
justify-content: center; | |||
align-items: center; | |||
margin-left: 2vw; | |||
} | |||
.goTop_img { | |||
width: 6vw; | |||
height: 6vw; | |||
} | |||
} | |||
@media screen and (orientation: landscape) { | |||
input:focus { | |||
border: 0.1vw solid #000; | |||
outline: none; /* 可选,用于去除默认的外边框样式 */ | |||
} | |||
.login { | |||
width: 100vw; | |||
height: 100vh; | |||
background-image: url("/static/img/phoneBgc_pc.jpg"); | |||
background-size: 100% 100%; | |||
background-repeat: no-repeat; | |||
position: relative; | |||
} | |||
.PC_img { | |||
width: 52.6vw; | |||
height: 64.44vh; | |||
background-image: url("/static/img/loginBox.png"); | |||
background-size: 100% 100%; | |||
background-repeat: no-repeat; | |||
position: absolute; | |||
top: 18.88vh; | |||
left: 23.7vw; | |||
} | |||
.register { | |||
background-image: url("/static/img/registerBgc_pc.jpg") !important; | |||
} | |||
.logo { | |||
width: 15vh; | |||
margin: 4vh 0 0 4vh; | |||
} | |||
.login_title { | |||
/* width: 100vw; */ | |||
font-size: 4vh; | |||
text-align: center; | |||
position: absolute; | |||
z-index: 10; | |||
top: 28vh; | |||
margin-left: 58vw; | |||
/* margin-top: 15vh;*/ | |||
} | |||
.register_loginTitle { | |||
width: 100vw; | |||
display: flex; | |||
justify-content: center; | |||
font-size: 4vh; | |||
text-align: center; | |||
position: absolute; | |||
z-index: 10; | |||
top: 10vh; | |||
} | |||
.uploadImg { | |||
width: 15vw; | |||
} | |||
.input_box { | |||
flex-direction: column; | |||
justify-content: center; | |||
align-items: center; | |||
margin-top: 15vh; | |||
position: relative; | |||
} | |||
.register_inputBox { | |||
width: 100vw; | |||
display: flex; | |||
flex-direction: column; | |||
justify-content: center; | |||
align-items: center; | |||
position: relative; | |||
padding-top: 42vh; | |||
} | |||
.phone_input{ | |||
width: 15vw; | |||
height: 6.66vh; | |||
border-radius: 2vh; | |||
background-color: transparent; | |||
font-size: 2vw; | |||
padding-left: 2vh; | |||
padding-right: 5vw; | |||
border: 0.1vw solid #000; | |||
margin-left: 25vw; | |||
} | |||
.register_phoneInput { | |||
width: 37vh; | |||
height: 6vh; | |||
border-radius: 2vh; | |||
background-color: transparent; | |||
font-size: 3vh; | |||
border: 0.1vw solid #000; | |||
margin-bottom: 5vh; | |||
padding-left:1vw ; | |||
} | |||
.register_codeInput { | |||
width: 37vh; | |||
height: 6vh; | |||
border-radius: 2vh; | |||
background-color: transparent; | |||
font-size: 3vh; | |||
border: 0.1vw solid #000; | |||
padding-left: 1vw ; | |||
} | |||
.code_input { | |||
width: 15vw; | |||
height: 6.66vh; | |||
margin-top: 2vw; | |||
border-radius: 2vh; | |||
padding-left: 2vh; | |||
font-size: 1.5vw; | |||
padding-right: 5vw; | |||
background-color: transparent; | |||
border: 0.1vw solid #000; | |||
margin-left: 25vw; | |||
} | |||
.login_button { | |||
width: 16vw; | |||
height: 3vw; | |||
background-color: rgb(101, 161, 255); | |||
border-radius: 10vh; | |||
display: flex; | |||
justify-content: center; | |||
align-items: center; | |||
color: #fff; | |||
font-size: 2vw; | |||
/* margin: 2vh 0 0 30vh; */ | |||
position: absolute; | |||
left: 55vw; | |||
top: 65vh; | |||
} | |||
.register_loginButton { | |||
width: 30vh; | |||
height: 3vw; | |||
background-color: rgb(101, 161, 255); | |||
border-radius: 1vw; | |||
display: flex; | |||
justify-content: center; | |||
align-items: center; | |||
color: #fff; | |||
font-size: 3vh; | |||
position: absolute; | |||
left: 42.5vw; | |||
top: 65vh; | |||
} | |||
.send_code { | |||
position: absolute; | |||
font-size: 1.5vh; | |||
top: 11.5vh; | |||
right: 27.3vw; | |||
border-left: 0.1vw solid; | |||
padding-left: 1vh; | |||
display: flex; | |||
align-items: center; | |||
height: 3vw; | |||
} | |||
.employee { | |||
display: flex; | |||
align-items: center; | |||
} | |||
.administrator { | |||
display: flex; | |||
align-items: center; | |||
margin-left: 3vw; | |||
} | |||
.hand:hover{ | |||
cursor: pointer; | |||
} | |||
.choose_employee { | |||
width: 2vh; | |||
height: 2vh; | |||
border-radius: 50%; | |||
border: 0.1vw solid #000; | |||
margin-right: 1vh; | |||
} | |||
.choose_administrator { | |||
width: 2vh; | |||
height: 2vh; | |||
border-radius: 50%; | |||
border: 0.1vw solid #000; | |||
margin-right: 1vh; | |||
} | |||
.login_style { | |||
display: flex; | |||
justify-content: center; | |||
align-items: center; | |||
font-size: 1vw; | |||
margin-top: 2vw; | |||
position: absolute; | |||
left: 54.8vw; | |||
} | |||
.hidden { | |||
display: none; | |||
} | |||
.active { | |||
display: flex; | |||
} | |||
.background { | |||
background-color: #000; | |||
} | |||
.password-container { | |||
position: relative; | |||
} | |||
.password_toggle { | |||
width: 3vw; | |||
position: absolute; | |||
font-size: 1.5vh; | |||
top: 11.5vh; | |||
right: 28.5vw; | |||
padding-left: 0.5vh; | |||
} | |||
.approval_page { | |||
width: 100vw; | |||
height: 100vh; | |||
background-image: url("/static/img/registerBgc.jpg"); | |||
background-size: 100% 100%; | |||
overflow: auto; | |||
} | |||
.approval_box { | |||
max-width: 100vw; | |||
min-height: 100vh; | |||
background-color:rgba(237,237,237,0.8); | |||
} | |||
.search_people { | |||
width: 60vw; | |||
height: 6vh; | |||
border-radius: 1vh; | |||
margin: 5vh 0 0 20vw; | |||
border: 0 solid #fff; | |||
font-size: 3vh; | |||
text-align: center; | |||
} | |||
.every_info { | |||
height: 7vw; | |||
margin-top: 3vw; | |||
display: flex; | |||
align-items: center; | |||
justify-content: space-around; | |||
font-size: 3vh; | |||
} | |||
#scroll-to-top-btn { | |||
display: none; | |||
position: fixed; | |||
right: 20px; | |||
bottom: 20px; | |||
width: 7vh; | |||
height: 10vw; | |||
color: #fff; | |||
border: none; | |||
border-radius: 5px; | |||
font-size: 3vh; | |||
cursor: pointer; | |||
} | |||
.people_img { | |||
width: 6vw; | |||
height: 6vw; | |||
} | |||
.pass_nopass { | |||
display: flex; | |||
} | |||
.pass { | |||
background-color: rgb(92, 186, 45); | |||
width: 10vh; | |||
height: 5vh; | |||
border-radius: 1vh; | |||
display: flex; | |||
justify-content: center; | |||
align-items: center; | |||
} | |||
.no_pass { | |||
background-color: rgb(187, 44, 45); | |||
width: 10vh; | |||
height: 5vh; | |||
border-radius: 1vh; | |||
display: flex; | |||
justify-content: center; | |||
align-items: center; | |||
margin-left: 2vh; | |||
} | |||
.goTop_img { | |||
width: 6vh; | |||
height: 6vh; | |||
} | |||
} | |||
.list_box{ | |||
padding-inline-start: 0px; | |||
} | |||
.uploadImg{ | |||
width: 48% !important; | |||
transform: translate(0%, 0%) !important; | |||
} | |||
.upload-img-box { | |||
position: relative; | |||
} | |||
.upload-img-box .input-box { | |||
display: inline-block; | |||
width: 144px; | |||
height: 144px; | |||
/*border: solid black 1px;*/ | |||
} | |||
.upload-img-box .befor-img { | |||
display: flex; | |||
/*width: 300px;*/ | |||
/*height: 90px;*/ | |||
/*border: solid black 1px;*/ | |||
position: absolute; | |||
top: 0px; | |||
left: 0px; | |||
/*background: #ffffff;*/ | |||
z-index: 30; | |||
align-items: center; | |||
justify-content: center; | |||
} | |||
.upload-img-box .befor-img.hasImg { | |||
display: none; | |||
} | |||
.upload-img-box .after-img { | |||
display: inline-block; | |||
width: 144px; | |||
height: 144px; | |||
border: none; | |||
/*position: absolute;*/ | |||
top: 0px; | |||
left: 0px; | |||
/*background: #ffffff;*/ | |||
z-index: 20; | |||
} | |||
.after-img img, .uploadImg { | |||
/*position: absolute;*/ | |||
width: 100%; | |||
height: 100%; | |||
object-fit: cover; /*根据父容器的尺寸裁剪和缩放图片,以填充整个容器,并保持长宽比例不变。*/ | |||
object-position: center; /*指定对象的位置,如果不设置,则默认是center*/ | |||
background-size: cover; /*背景图片的大小,如果不设置,则默认是auto*/ | |||
background-position: center; | |||
top: 50%; | |||
left: 50%; | |||
transform: translate(-50%, 0%);/*将元素移动到中心*/ | |||
border-radius: 50%; | |||
} | |||
</style> | |||
</head> | |||
<body> | |||
<!-- 登录页面 --> | |||
<div class="login"> | |||
<img class="logo" src="/static/img/logo.png" alt=""> | |||
<div class="PC_img"></div> | |||
<div class="login_title">请 登 录</div> | |||
<div id="employeeForm" class="input_box hidden active"> | |||
<input class="phone_input" type="text" placeholder="请输入手机号"> | |||
<input class="code_input" type="text" placeholder="请输入验证码"> | |||
<div class="send_code hand">发送验证码</div> | |||
</div> | |||
<div id="adminForm" class="input_box hidden password-container"> | |||
<input class="phone_input" type="text" placeholder="请输入账号"> | |||
<input id="password-input" class="code_input" type="password" placeholder="请输入密码"> | |||
<img id="password_toggle" class="password_toggle hand" src="/static/img/close.png" alt=""> | |||
</div> | |||
<div class="login_style"> | |||
<div id="employeeBtn" class="employee hand"> | |||
<div id="choose_employee" class="choose_employee background"></div> | |||
<div>员工登录</div> | |||
</div> | |||
<div id="adminBtn" class="administrator hand"> | |||
<div id="choose_administrator" class="choose_administrator"></div> | |||
<div>管理员登录</div> | |||
</div> | |||
</div> | |||
<div class="login_button hand">登 录</div> | |||
</div> | |||
<!-- 注册页面 --> | |||
<div style="display: none;" class="register login"> | |||
<div class="register_loginTitle "> | |||
<div class="upload-img-box"> | |||
<div class="input-box"> | |||
<input type="file" id="img-file" hidden="hidden" name="选择图片"> | |||
</div> | |||
<div class="befor-img"> | |||
<img class="uploadImg hand" src="/static/img/upload.png" alt=""> | |||
</div> | |||
<div class="after-img"> | |||
<img id="img-box" src="" width="30%" height="auto"> | |||
</div> | |||
</div> | |||
</div> | |||
<div class="register_inputBox"> | |||
<input class="register_phoneInput" type="text" placeholder="员工编号"> | |||
<input class="register_codeInput" type="text" placeholder="员工姓名"> | |||
</div> | |||
<div class="register_loginButton hand">注册人脸</div> | |||
</div> | |||
<!-- 管理员页面 --> | |||
<div style="display: none;" class="approval_page"> | |||
<div id="scroll_box" class="approval_box"> | |||
<input id="search" class="search_people" type="text" placeholder="🔍 搜索"> | |||
<ul class="list_box"> | |||
<li class="every_info"> | |||
<img class="people_img" src="/static/img/logo.png" alt=""> | |||
<div class="name">张三</div> | |||
<div class="people_code">001</div> | |||
<div class="pass_nopass"> | |||
<div class="pass">通过</div> | |||
<div class="no_pass">不通过</div> | |||
</div> | |||
</li> | |||
<li class="every_info"> <img class="people_img" src="/static/img/logo.png" alt=""> | |||
<div class="name">张三</div> | |||
<div class="people_code">001</div> | |||
<div class="pass_nopass"> | |||
<div class="pass">通过</div> | |||
<div class="no_pass">不通过</div> | |||
</div></li> | |||
<li class="every_info"> <img class="people_img" src="/static/img/logo.png" alt=""> | |||
<div class="name">张三</div> | |||
<div class="people_code">001</div> | |||
<div class="pass_nopass"> | |||
<div class="pass">通过</div> | |||
<div class="no_pass">不通过</div> | |||
</div></li> | |||
<li class="every_info"> <img class="people_img" src="/static/img/logo.png" alt=""> | |||
<div class="name">张三</div> | |||
<div class="people_code">001</div> | |||
<div class="pass_nopass"> | |||
<div class="pass">通过</div> | |||
<div class="no_pass">不通过</div> | |||
</div></li> | |||
<li class="every_info"> <img class="people_img" src="/static/img/logo.png" alt=""> | |||
<div class="name">张三</div> | |||
<div class="people_code">001</div> | |||
<div class="pass_nopass"> | |||
<div class="pass">通过</div> | |||
<div class="no_pass">不通过</div> | |||
</div></li> | |||
<li class="every_info"> <img class="people_img" src="/static/img/logo.png" alt=""> | |||
<div class="name">张三</div> | |||
<div class="people_code">001</div> | |||
<div class="pass_nopass"> | |||
<div class="pass">通过</div> | |||
<div class="no_pass">不通过</div> | |||
</div></li> | |||
<li class="every_info"> <img class="people_img" src="/static/img/logo.png" alt=""> | |||
<div class="name">张三</div> | |||
<div class="people_code">001</div> | |||
<div class="pass_nopass"> | |||
<div class="pass">通过</div> | |||
<div class="no_pass">不通过</div> | |||
</div></li> | |||
<li class="every_info"> <img class="people_img" src="/static/img/logo.png" alt=""> | |||
<div class="name">张三</div> | |||
<div class="people_code">001</div> | |||
<div class="pass_nopass"> | |||
<div class="pass">通过</div> | |||
<div class="no_pass">不通过</div> | |||
</div></li> | |||
<li class="every_info"> <img class="people_img" src="/static/img/logo.png" alt=""> | |||
<div class="name">张三</div> | |||
<div class="people_code">001</div> | |||
<div class="pass_nopass"> | |||
<div class="pass">通过</div> | |||
<div class="no_pass">不通过</div> | |||
</div></li> | |||
<li class="every_info"> <img class="people_img" src="/static/img/logo.png" alt=""> | |||
<div class="name">张三</div> | |||
<div class="people_code">001</div> | |||
<div class="pass_nopass"> | |||
<div class="pass">通过</div> | |||
<div class="no_pass">不通过</div> | |||
</div></li> | |||
<li class="every_info"> <img class="people_img" src="/static/img/logo.png" alt=""> | |||
<div class="name">张三</div> | |||
<div class="people_code">001</div> | |||
<div class="pass_nopass"> | |||
<div class="pass">通过</div> | |||
<div class="no_pass">不通过</div> | |||
</div></li> | |||
<li class="every_info"> <img class="people_img" src="/static/img/logo.png" alt=""> | |||
<div class="name">张三</div> | |||
<div class="people_code">001</div> | |||
<div class="pass_nopass"> | |||
<div class="pass">通过</div> | |||
<div class="no_pass">不通过</div> | |||
</div></li> | |||
<li class="every_info"> <img class="people_img" src="/static/img/logo.png" alt=""> | |||
<div class="name">张三</div> | |||
<div class="people_code">001</div> | |||
<div class="pass_nopass"> | |||
<div class="pass">通过</div> | |||
<div class="no_pass">不通过</div> | |||
</div></li> | |||
<li class="every_info"> <img class="people_img" src="/static/img/logo.png" alt=""> | |||
<div class="name">张三</div> | |||
<div class="people_code">001</div> | |||
<div class="pass_nopass"> | |||
<div class="pass">通过</div> | |||
<div class="no_pass">不通过</div> | |||
</div></li> | |||
<li class="every_info"> <img class="people_img" src="/static/img/logo.png" alt=""> | |||
<div class="name">张三</div> | |||
<div class="people_code">001</div> | |||
<div class="pass_nopass"> | |||
<div class="pass">通过</div> | |||
<div class="no_pass">不通过</div> | |||
</div></li> | |||
<li class="every_info"> <img class="people_img" src="/static/img/logo.png" alt=""> | |||
<div class="name">张三</div> | |||
<div class="people_code">001</div> | |||
<div class="pass_nopass"> | |||
<div class="pass">通过</div> | |||
<div class="no_pass">不通过</div> | |||
</div></li> | |||
</ul> | |||
</div> | |||
<a id="scroll-to-top-btn" href=""> | |||
<img class="goTop_img" src="/static/img/goTop.png" alt=""> | |||
</a> | |||
</div> | |||
<script src="/static/js/jquery.min.js"></script> | |||
<script> | |||
$(function(){ | |||
$(".login_button").on("click",function(){ | |||
console.log("click"); | |||
$(".login").css("display","none"); | |||
// $(".approval_page").css("display","block"); | |||
$(".register").css("display","block"); | |||
}) | |||
$(document).on("click", ".upload-img-box .befor-img,.upload-img-box .after-img", function (e) { | |||
$(".input-box input").trigger("click"); | |||
}) | |||
// 使用input 的change事件,监听当文件上传的值进行改变的时候,才触发事件。 | |||
$(document).on("change", ".upload-img-box #img-file", function () { | |||
var file = $("#img-file")[0].files[0]; | |||
console.log(file); | |||
// file 内容包括: lastModified , lastModifiedDate , name , size , type | |||
var formdata = new FormData(); | |||
formdata.append('file', file); | |||
if (window.FileReader) { | |||
var fr = new FileReader(); | |||
fr.onloadend = function (e) { | |||
// console.log(this.result); | |||
// document.getElementById("portrait").src = e.target.result; | |||
$("#img-box").attr("src",e.target.result) | |||
$(".upload-img-box .befor-img").addClass("hasImg") | |||
}; | |||
//给FileReader对象一个读取完成的方法, | |||
//使用readAsDataURL会返回一个url | |||
//这个值就保存在事件对象的result里 | |||
//img通过加载这个地址,完成图片的加载 | |||
fr.readAsDataURL(file); | |||
} | |||
//判断图片大小 | |||
if (file.size > 3 * 1024 * 1024) { | |||
alert("上传图片不能大于3M"); | |||
} | |||
//判断图片数据类型 | |||
if (!/.(gif|jpg|jpeg|png|GIF|JPG|bmp)$/.test(file.name)) { | |||
alert("图片类型必须是.gif,jpeg,jpg,png,bmp中的一种"); | |||
} | |||
}) | |||
}) | |||
// 切换登陆页面 | |||
document.getElementById("employeeBtn").addEventListener("click", function() { | |||
document.getElementById("employeeForm").classList.add("active"); | |||
document.getElementById("adminForm").classList.remove("active"); | |||
document.getElementById("choose_administrator").classList.remove("background"); | |||
document.getElementById("choose_employee").classList.add("background"); | |||
}); | |||
document.getElementById("adminBtn").addEventListener("click", function() { | |||
document.getElementById("employeeForm").classList.remove("active"); | |||
document.getElementById("adminForm").classList.add("active"); | |||
document.getElementById("choose_employee").classList.remove("background"); | |||
document.getElementById("choose_administrator").classList.add("background"); | |||
}); | |||
document.getElementById("password_toggle").addEventListener("click", function() { | |||
let passwordInput = document.getElementById("password-input") | |||
if (passwordInput.type === 'password') { | |||
passwordInput.type ='text'; | |||
document.getElementById("password_toggle").src = "/static/img/open.png" | |||
} else { | |||
passwordInput.type = "password"; | |||
document.getElementById("password_toggle").src = "/static/img/close.png" | |||
} | |||
}); | |||
// 点击回到顶部 | |||
var element = document.getElementById('search'); | |||
var observer = new IntersectionObserver(function(entries) { | |||
entries.forEach(function(entry) { | |||
var scrollToTopBtn = document.getElementById('scroll-to-top-btn'); | |||
if (entry.isIntersecting) { | |||
// 元素进入视口,执行代码 | |||
scrollToTopBtn.style.display = 'none'; | |||
} else { | |||
scrollToTopBtn.style.display = 'block'; | |||
} | |||
}); | |||
}); | |||
observer.observe(element); | |||
document.getElementById('scroll-to-top-btn').addEventListener('click', function() { | |||
document.getElementById("scroll_box").scrollTop = 0 | |||
}); | |||
</script> | |||
</body> | |||
</html> |
@@ -0,0 +1,578 @@ | |||
<!DOCTYPE html> | |||
<html lang="en"> | |||
<head> | |||
<meta charset="UTF-8"> | |||
<meta name="viewport" content="width=device-width, initial-scale=1.0"> | |||
<title>页面登录</title> | |||
<style> | |||
body{ | |||
margin: 0; | |||
} | |||
li { | |||
list-style-type: none; | |||
} | |||
@media screen and (orientation: portrait) { | |||
.login { | |||
width: 100vw; | |||
height: 100vh; | |||
background-image: url("/static/img/phoneBgc.jpg"); | |||
background-size: 100% 100%; | |||
background-repeat: no-repeat; | |||
} | |||
.register { | |||
background-image: url("/static/img/registerBgc.jpg") !important; | |||
padding-top: 15vh; | |||
} | |||
.logo { | |||
width: 15vw; | |||
margin: 4vw 0 0 4vw; | |||
} | |||
.login_title { | |||
width: 100vw; | |||
font-size: 8vw; | |||
text-align: center; | |||
margin-top: 15vh; | |||
} | |||
.input_box { | |||
width: 100vw; | |||
height: 25vw; | |||
display: flex; | |||
flex-direction: column; | |||
justify-content: center; | |||
align-items: center; | |||
margin-top: 5vh; | |||
position: relative; | |||
} | |||
.phone_input, .account_input{ | |||
width: 50vw; | |||
height: 11vw; | |||
border-radius: 2vw; | |||
background-color: transparent; | |||
font-size: 3vw; | |||
padding-left: 2vw; | |||
border: 1px solid #000; | |||
position: absolute; | |||
top: 0vw; | |||
} | |||
.code_input, .password_input{ | |||
width: 50vw; | |||
height: 11vw; | |||
margin-top: 2vh; | |||
border-radius: 2vw; | |||
padding-left: 2vw; | |||
font-size: 3vw; | |||
background-color: transparent; | |||
border: 1px solid #000; | |||
position: absolute; | |||
top: 10vw; | |||
} | |||
.login_button { | |||
width: 40vw; | |||
height: 5vh; | |||
background-color: rgb(101, 161, 255); | |||
border-radius: 10vw; | |||
display: flex; | |||
justify-content: center; | |||
align-items: center; | |||
color:#fff; | |||
font-size: 4vw; | |||
margin: 2vh 0 0 30vw; | |||
} | |||
#sendCodeBtn { | |||
position: absolute; | |||
font-size: 2.5vw; | |||
top: 18.5vw; | |||
right: 30vw; | |||
border-left: 2px solid; | |||
padding-left: 2vw; | |||
border: none; | |||
background: transparent; | |||
} | |||
.employee { | |||
display: flex; | |||
align-items: center; | |||
} | |||
.administrator { | |||
display: flex; | |||
align-items: center; | |||
margin-left: 5vw; | |||
} | |||
.choose_employee { | |||
width: 2vw; | |||
height: 2vw; | |||
border-radius: 50%; | |||
border: 2px solid #000; | |||
margin-right: 1vw; | |||
} | |||
.choose_administrator { | |||
width: 2vw; | |||
height: 2vw; | |||
border-radius: 50%; | |||
border: 2px solid #000; | |||
margin-right: 1vw; | |||
} | |||
.login_style { | |||
display: flex; | |||
justify-content: center; | |||
align-items: center; | |||
font-size: 2.5vw; | |||
margin-top: 2vh; | |||
} | |||
.hidden { | |||
display: none; | |||
} | |||
.active { | |||
display: flex; | |||
} | |||
.background { | |||
background-color: #000; | |||
} | |||
.password-container { | |||
position: relative; | |||
} | |||
.password_toggle { | |||
position: absolute; | |||
width: 5vw; | |||
top: 18vw; | |||
right: 26vw; | |||
} | |||
} | |||
@media screen and (orientation: landscape) { | |||
input:focus { | |||
border: 0.1vw solid #000; | |||
outline: none; /* 可选,用于去除默认的外边框样式 */ | |||
} | |||
.login { | |||
width: 100vw; | |||
height: 100vh; | |||
background-image: url("/static/img/phoneBgc_pc.jpg"); | |||
background-size: 100% 100%; | |||
background-repeat: no-repeat; | |||
position: relative; | |||
} | |||
.PC_img { | |||
width: 52.6vw; | |||
height: 64.44vh; | |||
background-image: url("/static/img/loginBox.png"); | |||
background-size: 100% 100%; | |||
background-repeat: no-repeat; | |||
position: absolute; | |||
top: 18.88vh; | |||
left: 23.7vw; | |||
} | |||
.register { | |||
background-image: url("/static/img/registerBgc_pc.jpg") !important; | |||
} | |||
.logo { | |||
width: 15vh; | |||
margin: 4vh 0 0 4vh; | |||
} | |||
.login_title { | |||
/* width: 100vw; */ | |||
font-size: 4vh; | |||
text-align: center; | |||
position: absolute; | |||
z-index: 10; | |||
top: 28vh; | |||
margin-left: 58vw; | |||
/* margin-top: 15vh;*/ | |||
} | |||
.input_box { | |||
flex-direction: column; | |||
justify-content: center; | |||
align-items: center; | |||
margin-top: 15vh; | |||
position: relative; | |||
} | |||
.phone_input, .account_input { | |||
width: 15vw; | |||
height: 6.66vh; | |||
border-radius: 2vh; | |||
background-color: transparent; | |||
font-size: 1.5vw; | |||
padding-left: 2vh; | |||
padding-right: 5vw; | |||
border: 0.1vw solid #000; | |||
margin-left: 25vw; | |||
} | |||
.code_input, .password_input { | |||
width: 15vw; | |||
height: 6.66vh; | |||
margin-top: 2vw; | |||
border-radius: 2vh; | |||
padding-left: 2vh; | |||
font-size: 1.5vw; | |||
padding-right: 5vw; | |||
background-color: transparent; | |||
border: 0.1vw solid #000; | |||
margin-left: 25vw; | |||
} | |||
.login_button { | |||
width: 16vw; | |||
height: 3vw; | |||
background-color: rgb(101, 161, 255); | |||
border-radius: 10vh; | |||
display: flex; | |||
justify-content: center; | |||
align-items: center; | |||
color: #fff; | |||
font-size: 2vw; | |||
/* margin: 2vh 0 0 30vh; */ | |||
position: absolute; | |||
left: 55vw; | |||
top: 65vh; | |||
} | |||
#sendCodeBtn { | |||
position: absolute; | |||
font-size: 1.5vh; | |||
top: 11.5vh; | |||
right: 27.3vw; | |||
border-left: 0.1vw solid; | |||
padding-left: 1vh; | |||
display: flex; | |||
align-items: center; | |||
height: 3vw; | |||
border: none; | |||
background: transparent; | |||
} | |||
.employee { | |||
display: flex; | |||
align-items: center; | |||
} | |||
.administrator { | |||
display: flex; | |||
align-items: center; | |||
margin-left: 3vw; | |||
} | |||
.hand:hover { | |||
cursor: pointer; | |||
} | |||
.choose_employee { | |||
width: 2vh; | |||
height: 2vh; | |||
border-radius: 50%; | |||
border: 0.1vw solid #000; | |||
margin-right: 1vh; | |||
} | |||
.choose_administrator { | |||
width: 2vh; | |||
height: 2vh; | |||
border-radius: 50%; | |||
border: 0.1vw solid #000; | |||
margin-right: 1vh; | |||
} | |||
.login_style { | |||
display: flex; | |||
justify-content: center; | |||
align-items: center; | |||
font-size: 1vw; | |||
margin-top: 2vw; | |||
position: absolute; | |||
left: 54.8vw; | |||
} | |||
.hidden { | |||
display: none; | |||
} | |||
.active { | |||
display: flex; | |||
} | |||
.background { | |||
background-color: #000; | |||
} | |||
.password-container { | |||
position: relative; | |||
} | |||
.password_toggle { | |||
width: 3vw; | |||
position: absolute; | |||
font-size: 1.5vh; | |||
top: 11.5vh; | |||
right: 28.5vw; | |||
padding-left: 0.5vh; | |||
} | |||
#scroll-to-top-btn { | |||
display: none; | |||
position: fixed; | |||
right: 20px; | |||
bottom: 20px; | |||
width: 7vh; | |||
height: 10vw; | |||
color: #fff; | |||
border: none; | |||
border-radius: 5px; | |||
font-size: 3vh; | |||
cursor: pointer; | |||
} | |||
} | |||
button:disabled { | |||
color: black !important; | |||
} | |||
</style> | |||
</head> | |||
<body> | |||
<!-- 登录页面 --> | |||
<div class="login"> | |||
<img class="logo" src="/static/img/logo.png" alt=""> | |||
<div class="PC_img"></div> | |||
<div class="login_title">请 登 录</div> | |||
<div id="employeeForm" class="input_box hidden active"> | |||
<input class="phone_input" type="text" placeholder="请输入手机号"> | |||
<input class="code_input" type="text" placeholder="请输入验证码"> | |||
<button id="sendCodeBtn" class="btn">发送验证码</button> | |||
</div> | |||
<div id="adminForm" class="input_box hidden password-container"> | |||
<input class="account_input" type="text" placeholder="请输入账号"> | |||
<input id="password_input" class="password_input" type="password" placeholder="请输入密码"> | |||
<img id="password_toggle" class="password_toggle hand" src="/static/img/close.png" alt=""> | |||
</div> | |||
<div class="login_style"> | |||
<div id="employeeBtn" class="employee hand"> | |||
<div id="choose_employee" class="choose_employee background"></div> | |||
<div>员工登录</div> | |||
</div> | |||
<div id="adminBtn" class="administrator hand"> | |||
<div id="choose_administrator" class="choose_administrator"></div> | |||
<div>管理员登录</div> | |||
</div> | |||
</div> | |||
<div class="login_button hand">登 录</div> | |||
</div> | |||
<script src="/static/js/jquery.min.js"></script> | |||
<script src="/static/js/msg-box.js"></script> | |||
<script> | |||
$(function(){ | |||
console.log("{{.type}}"); | |||
if ("{{.type}}" == "mgr") { | |||
$("#adminBtn").click(); | |||
} | |||
$.MsgBox = { | |||
Alert: function(title, msg) { | |||
GenerateHtml("alert", title, msg); | |||
btnOk(); //alert只是弹出消息,因此没必要用到回调函数callback | |||
btnNo(); | |||
}, | |||
Confirm: function(title, msg, callback) { | |||
GenerateHtml("confirm", title, msg); | |||
btnOk(callback); | |||
btnNo(); | |||
} | |||
} | |||
const sendCodeBtn = $('#sendCodeBtn'); | |||
let countdown = 30; | |||
let timer; | |||
function startCountdown() { | |||
sendCodeBtn.attr("disabled", "disabled"); | |||
sendCodeBtn.html(`${countdown}秒`); | |||
timer = setInterval(() => { | |||
console.log(countdown); | |||
countdown--; | |||
sessionStorage.setItem('countdown',countdown); | |||
sendCodeBtn.html(`${countdown}秒`); | |||
if (countdown <= 0) { | |||
clearInterval(timer); | |||
sendCodeBtn.html('发送验证码'); | |||
sendCodeBtn.removeAttr("disabled"); | |||
countdown = 30; | |||
} | |||
}, 1000); | |||
} | |||
$("#sendCodeBtn").on("click",function(){ | |||
if (!phoneValid()){ | |||
$.MsgBox.Alert("提示", "手机号为空或不合法,请检查"); | |||
return; | |||
} | |||
countdown = 30; | |||
startCountdown(); | |||
sessionStorage.setItem('countdown',countdown); | |||
// ajax发送验证码 | |||
$.ajax({ | |||
url: '/send_validation_code', | |||
type: 'POST', | |||
dataType: 'json', | |||
data: { | |||
phone: $(".phone_input").val(), | |||
}, | |||
success: function (response) { | |||
console.log(response); | |||
response = JSON.parse(response) | |||
if (response.code == 200) { | |||
$.MsgBox.Alert("提示", "验证码发送成功"); | |||
} else { | |||
$.MsgBox.Alert("提示", response.msg ? response.msg : "验证码发送失败"); | |||
} | |||
}, | |||
error: function () { | |||
} | |||
}); | |||
}) | |||
function initCountdown() { | |||
const storedCountdown = sessionStorage.getItem('countdown'); | |||
if (storedCountdown) { | |||
countdown = parseInt(storedCountdown, 10); | |||
if (countdown > 0) { | |||
startCountdown(); | |||
} | |||
} | |||
} | |||
initCountdown(); | |||
function phoneValid() { | |||
const regex = /^1[3-9]\d{9}$/; | |||
var phone = $(".phone_input").val(); | |||
if (phone == "" || !regex.test(phone)){ | |||
return false; | |||
} | |||
return true; | |||
} | |||
$(".login_button").on("click",function(){ | |||
if ($("#employeeForm").hasClass("active")) { | |||
if (!phoneValid()){ | |||
$.MsgBox.Alert("提示", "手机号为空或不合法,请检查"); | |||
return; | |||
} | |||
const codeRegex = /^\d{4}$/; | |||
var code = $(".code_input").val(); | |||
if (code == "" || !codeRegex.test(code)){ | |||
$.MsgBox.Alert("提示", "验证码为4位数字,请检查"); | |||
return; | |||
} | |||
$.ajax({ | |||
url: '/valid_code', | |||
type: 'POST', | |||
dataType: 'json', | |||
data: { | |||
phone: $(".phone_input").val(), | |||
code: code, | |||
}, | |||
success: function (response) { | |||
console.log(response); | |||
response = JSON.parse(response) | |||
if (response.status == 0) { | |||
$.ajax({ | |||
url: '/phone_login', | |||
type: 'POST', | |||
dataType: 'json', | |||
data: { | |||
phone: $(".phone_input").val(), | |||
}, | |||
success: function (response) { | |||
console.log(response); | |||
console.log(response.data); | |||
console.log(response.data.staffId); | |||
// response = JSON.parse(response) | |||
if (response.code == 200) { | |||
window.location.href = '/info?staffId='+response.data.staffId; | |||
} else { | |||
$.MsgBox.Alert("提示", response.msg); | |||
} | |||
}, | |||
error: function () { | |||
} | |||
}); | |||
} else { | |||
$.MsgBox.Alert("提示", response.err); | |||
} | |||
}, | |||
error: function () { | |||
} | |||
}); | |||
} else { | |||
if ($(".account_input").val() == "") { | |||
$.MsgBox.Alert("提示", "请输入账号!"); | |||
return; | |||
} | |||
if ($(".password_input").val() == "") { | |||
$.MsgBox.Alert("提示", "请输入密码!"); | |||
return; | |||
} | |||
$.ajax({ | |||
url: '/mgr_login', | |||
type: 'POST', | |||
dataType: 'json', | |||
data: { | |||
userName: $(".account_input").val(), | |||
password: $(".password_input").val(), | |||
}, | |||
success: function (response) { | |||
console.log(response); | |||
response = JSON.parse(response) | |||
if (response.code == 200) { | |||
console.log(response.data.access_token); | |||
console.log(response.type); | |||
sessionStorage.setItem('token',response.type); | |||
window.location.href = '/mgr'; | |||
} else { | |||
$.MsgBox.Alert("提示", response.msg); | |||
} | |||
}, | |||
error: function () { | |||
} | |||
}); | |||
} | |||
}) | |||
}) | |||
// 切换登陆页面 | |||
document.getElementById("employeeBtn").addEventListener("click", function() { | |||
document.getElementById("employeeForm").classList.add("active"); | |||
document.getElementById("adminForm").classList.remove("active"); | |||
document.getElementById("choose_administrator").classList.remove("background"); | |||
document.getElementById("choose_employee").classList.add("background"); | |||
}); | |||
document.getElementById("adminBtn").addEventListener("click", function() { | |||
document.getElementById("employeeForm").classList.remove("active"); | |||
document.getElementById("adminForm").classList.add("active"); | |||
document.getElementById("choose_employee").classList.remove("background"); | |||
document.getElementById("choose_administrator").classList.add("background"); | |||
}); | |||
document.getElementById("password_toggle").addEventListener("click", function() { | |||
let passwordInput = document.getElementById("password_input") | |||
if (passwordInput.type === 'password') { | |||
passwordInput.type ='text'; | |||
document.getElementById("password_toggle").src = "/static/img/open.png" | |||
} else { | |||
passwordInput.type = "password"; | |||
document.getElementById("password_toggle").src = "/static/img/close.png" | |||
} | |||
}); | |||
</script> | |||
</body> | |||
</html> |
@@ -0,0 +1,402 @@ | |||
<!DOCTYPE html> | |||
<html lang="en"> | |||
<head> | |||
<meta charset="UTF-8"> | |||
<meta name="viewport" content="width=device-width, initial-scale=1.0"> | |||
<title>管理页面</title> | |||
<style> | |||
body{ | |||
margin: 0; | |||
} | |||
li { | |||
list-style-type: none; | |||
} | |||
@media screen and (orientation: portrait) { | |||
.approval_page { | |||
width: 100vw; | |||
height: 100vh; | |||
background-image: url("/static/img/registerBgc.jpg"); | |||
background-size: 100% 100%; | |||
overflow: auto; | |||
} | |||
.approval_box { | |||
max-width: 100vw; | |||
min-height: 100vh; | |||
background-color:rgba(237,237,237,0.8); | |||
} | |||
.search_people { | |||
width: 80vw; | |||
height: 5vh; | |||
border-radius: 1vw; | |||
margin: 5vh 0 0 10vw; | |||
border: 0 solid #fff; | |||
font-size: 3vw; | |||
text-align: center; | |||
} | |||
.every_info { | |||
height: 7vh; | |||
margin-top: 3vh; | |||
display: flex; | |||
align-items: center; | |||
justify-content: space-around; | |||
font-size: 3vw; | |||
} | |||
#scroll-to-top-btn { | |||
display: none; | |||
position: fixed; | |||
right: 20px; | |||
bottom: 20px; | |||
width: 7vw; | |||
height: 10vh; | |||
color: #fff; | |||
border: none; | |||
border-radius: 5px; | |||
font-size: 3vw; | |||
cursor: pointer; | |||
} | |||
.people_img { | |||
width: 6vh; | |||
height: 6vh; | |||
border-radius: 50%; | |||
} | |||
.pass_nopass { | |||
display: flex; | |||
} | |||
.pass { | |||
background-color: rgb(92, 186, 45); | |||
width: 12vw; | |||
height: 6vw; | |||
border-radius: 1vw; | |||
display: flex; | |||
justify-content: center; | |||
align-items: center; | |||
color: white; | |||
} | |||
.no_pass, .del_pass { | |||
background-color: rgb(187, 44, 45); | |||
width: 12vw; | |||
height: 6vw; | |||
border-radius: 1vw; | |||
display: flex; | |||
justify-content: center; | |||
align-items: center; | |||
margin-left: 3vw; | |||
color: white; | |||
} | |||
.goTop_img { | |||
width: 6vw; | |||
height: 6vw; | |||
} | |||
.pass_info{ | |||
width: 25vw; | |||
} | |||
.no_pass_info{ | |||
line-height: 3vh; | |||
} | |||
} | |||
@media screen and (orientation: landscape) { | |||
input:focus { | |||
border: 0.1vw solid #000; | |||
outline: none; /* 可选,用于去除默认的外边框样式 */ | |||
} | |||
.approval_page { | |||
width: 100vw; | |||
height: 100vh; | |||
background-image: url("/static/img/registerBgc.jpg"); | |||
background-size: 100% 100%; | |||
overflow: auto; | |||
} | |||
.approval_box { | |||
max-width: 100vw; | |||
min-height: 100vh; | |||
background-color:rgba(237,237,237,0.8); | |||
} | |||
.search_people { | |||
width: 60vw; | |||
height: 6vh; | |||
border-radius: 1vh; | |||
margin: 5vh 0 0 20vw; | |||
border: 0 solid #fff; | |||
font-size: 3vh; | |||
text-align: center; | |||
} | |||
.every_info { | |||
height: 7vw; | |||
margin-top: 3vw; | |||
display: flex; | |||
align-items: center; | |||
justify-content: space-around; | |||
font-size: 3vh; | |||
} | |||
#scroll-to-top-btn { | |||
display: none; | |||
position: fixed; | |||
right: 20px; | |||
bottom: 20px; | |||
width: 7vh; | |||
height: 10vw; | |||
color: #fff; | |||
border: none; | |||
border-radius: 5px; | |||
font-size: 3vh; | |||
cursor: pointer; | |||
} | |||
.people_img { | |||
width: 6vw; | |||
height: 6vw; | |||
border-radius: 50%; | |||
} | |||
.pass_nopass { | |||
display: flex; | |||
} | |||
.pass { | |||
background-color: rgb(92, 186, 45); | |||
width: 10vh; | |||
height: 5vh; | |||
border-radius: 1vh; | |||
display: flex; | |||
justify-content: center; | |||
align-items: center; | |||
color: white; | |||
cursor: pointer; | |||
} | |||
.no_pass, .del_pass { | |||
background-color: rgb(187, 44, 45); | |||
width: 10vh; | |||
height: 5vh; | |||
border-radius: 1vh; | |||
display: flex; | |||
justify-content: center; | |||
align-items: center; | |||
margin-left: 2vh; | |||
color: white; | |||
cursor: pointer; | |||
} | |||
.goTop_img { | |||
width: 6vh; | |||
height: 6vh; | |||
} | |||
} | |||
.list_box{ | |||
padding-inline-start: 0px; | |||
} | |||
.uploadImg{ | |||
width: 48% !important; | |||
transform: translate(0%, 0%) !important; | |||
} | |||
.upload-img-box { | |||
position: relative; | |||
} | |||
.upload-img-box .input-box { | |||
display: inline-block; | |||
width: 144px; | |||
height: 144px; | |||
/*border: solid black 1px;*/ | |||
} | |||
.upload-img-box .befor-img { | |||
display: flex; | |||
/*width: 300px;*/ | |||
/*height: 90px;*/ | |||
/*border: solid black 1px;*/ | |||
position: absolute; | |||
top: 0px; | |||
left: 0px; | |||
/*background: #ffffff;*/ | |||
z-index: 30; | |||
align-items: center; | |||
justify-content: center; | |||
} | |||
.upload-img-box .befor-img.hasImg { | |||
display: none; | |||
} | |||
.upload-img-box .after-img { | |||
display: inline-block; | |||
width: 144px; | |||
height: 144px; | |||
border: none; | |||
/*position: absolute;*/ | |||
top: 0px; | |||
left: 0px; | |||
/*background: #ffffff;*/ | |||
z-index: 20; | |||
} | |||
.after-img img, .uploadImg { | |||
/*position: absolute;*/ | |||
width: 100%; | |||
height: 100%; | |||
object-fit: cover; /*根据父容器的尺寸裁剪和缩放图片,以填充整个容器,并保持长宽比例不变。*/ | |||
object-position: center; /*指定对象的位置,如果不设置,则默认是center*/ | |||
background-size: cover; /*背景图片的大小,如果不设置,则默认是auto*/ | |||
background-position: center; | |||
top: 50%; | |||
left: 50%; | |||
transform: translate(-50%, 0%);/*将元素移动到中心*/ | |||
border-radius: 50%; | |||
} | |||
.pass_info{ | |||
color: green; | |||
} | |||
.no_pass_info{ | |||
color: red; | |||
} | |||
</style> | |||
</head> | |||
<body> | |||
<!-- 管理员页面 --> | |||
<div class="approval_page" style="display: none;"> | |||
<div id="scroll_box" class="approval_box"> | |||
<input id="search" class="search_people" value="{{.key}}" type="text" placeholder="🔍 搜索"> | |||
<ul class="list_box"> | |||
{{ range $i, $v := .users }} | |||
<li class="every_info" itemid="{{$v.ID}}"> | |||
<img class="people_img" src="{{$v.Avatar}}" alt=""> | |||
<div class="name">{{$v.Name}}</div> | |||
<div class="people_code">{{$v.Phone}}</div> | |||
<div class="pass_nopass"> | |||
{{ if eq $v.Status 1 }} | |||
<div class="pass_info">通过</div> | |||
{{ else if eq $v.Status 2 }} | |||
<div class="no_pass_info">不通过</div> | |||
<div class="del_pass">删除X</div> | |||
{{ else }} | |||
<div class="pass">通过</div> | |||
<div class="no_pass">不通过</div> | |||
{{ end }} | |||
</div> | |||
</li> | |||
{{ end }} | |||
</ul> | |||
</div> | |||
<a id="scroll-to-top-btn" href=""> | |||
<img class="goTop_img" src="/static/img/goTop.png" alt=""> | |||
</a> | |||
</div> | |||
<script src="/static/js/jquery.min.js"></script> | |||
<script src="/static/js/msg-box.js"></script> | |||
<script> | |||
console.log("9999999"); | |||
var token= sessionStorage.getItem('token'); | |||
console.log(token) | |||
if (!token){ | |||
$.MsgBox.AlertWithCallback("提示", "此页面需要先进行登录", function (){ | |||
window.location.href = "/?type=mgr"; | |||
}); | |||
} else { | |||
$(".approval_page").css("display","block"); | |||
} | |||
$(function(){ | |||
var t=$("#search").val(); | |||
$("#search").val("").focus().val(t); | |||
$('.pass').on("click",function(){ | |||
var id = $(this).parent().parent().attr('itemid'); | |||
$.ajax({ | |||
url: "/pass", | |||
type: "post", | |||
data: { | |||
handle: 1, | |||
id: id | |||
}, | |||
success: function (data) { | |||
$.MsgBox.AlertWithCallback("提示", data.Message, function (){ | |||
location.reload(); | |||
}); | |||
}, | |||
error: function (error) { | |||
console.log(error); | |||
$.MsgBox.Alert("提示", error.responseJSON.Message); | |||
} | |||
}) | |||
}) | |||
$('.no_pass').on("click",function(){ | |||
var id = $(this).parent().parent().attr('itemid'); | |||
$.MsgBox.Confirm("提示", "确定要否决这条注册吗?", function () { | |||
$.ajax({ | |||
url: "/pass", | |||
type: "post", | |||
data: { | |||
handle: 2, | |||
id: id | |||
}, | |||
success: function (data) { | |||
location.reload(); | |||
}, | |||
error: function (error) { | |||
console.log(error); | |||
$.MsgBox.Alert("提示", error.responseJSON.Message); | |||
} | |||
}) | |||
}) | |||
}) | |||
$('.del_pass').on("click",function(){ | |||
var id = $(this).parent().parent().attr('itemid'); | |||
$.MsgBox.Confirm("提示", "确定要删除这条注册吗?", function (){ | |||
$.ajax({ | |||
url: "/pass", | |||
type: "post", | |||
data: { | |||
handle: 4, | |||
id: id | |||
}, | |||
success: function (data) { | |||
location.reload(); | |||
}, | |||
error: function (error) { | |||
console.log(error); | |||
$.MsgBox.Alert("提示", error.responseJSON.Message); | |||
} | |||
}) | |||
}) | |||
}) | |||
$("#search").on('change',function(e){ | |||
window.location.href = "/mgr?key="+$(this).val() | |||
}); | |||
}) | |||
// 点击回到顶部 | |||
var element = document.getElementById('search'); | |||
var observer = new IntersectionObserver(function(entries) { | |||
entries.forEach(function(entry) { | |||
var scrollToTopBtn = document.getElementById('scroll-to-top-btn'); | |||
if (entry.isIntersecting) { | |||
// 元素进入视口,执行代码 | |||
scrollToTopBtn.style.display = 'none'; | |||
} else { | |||
scrollToTopBtn.style.display = 'block'; | |||
} | |||
}); | |||
}); | |||
observer.observe(element); | |||
document.getElementById('scroll-to-top-btn').addEventListener('click', function() { | |||
document.getElementById("scroll_box").scrollTop = 0 | |||
}); | |||
</script> | |||
</body> | |||
</html> |
@@ -0,0 +1,396 @@ | |||
<!DOCTYPE html> | |||
<html lang="en"> | |||
<head> | |||
<meta charset="UTF-8"> | |||
<meta name="viewport" content="width=device-width, initial-scale=1.0"> | |||
<title>注册页面</title> | |||
<style> | |||
body{ | |||
margin: 0; | |||
} | |||
li { | |||
list-style-type: none; | |||
} | |||
@media screen and (orientation: portrait) { | |||
.login { | |||
width: 100vw; | |||
height: 100vh; | |||
background-image: url("/static/img/phoneBgc.jpg"); | |||
background-size: 100% 100%; | |||
background-repeat: no-repeat; | |||
} | |||
.register { | |||
background-image: url("/static/img/registerBgc.jpg") !important; | |||
padding-top: 15vh; | |||
} | |||
.register_loginTitle { | |||
width: 100vw; | |||
font-size: 8vw; | |||
text-align: center; | |||
} | |||
.register_inputBox { | |||
display: flex; | |||
flex-direction: column; | |||
justify-content: center; | |||
align-items: center; | |||
margin-top: 5vh; | |||
position: relative; | |||
} | |||
.register_phoneInput { | |||
width: 50vw; | |||
height: 5vh; | |||
border-radius: 2vw; | |||
background-color: transparent; | |||
font-size: 3vw; | |||
padding-left: 2vw; | |||
border: 1px solid #000; | |||
margin-bottom: 2vh; | |||
} | |||
.register_nameInput { | |||
width: 50vw; | |||
height: 5vh; | |||
border-radius: 2vw; | |||
background-color: transparent; | |||
font-size: 3vw; | |||
padding-left: 2vw; | |||
border: 1px solid #000; | |||
margin-bottom: 2vh; | |||
} | |||
.reg_button { | |||
width: 40vw; | |||
height: 5vh; | |||
background-color: rgb(101, 161, 255); | |||
border-radius: 10vw; | |||
display: flex; | |||
justify-content: center; | |||
align-items: center; | |||
color:#fff; | |||
font-size: 4vw; | |||
margin: 2vh 0 0 30vw; | |||
} | |||
.register_loginButton { | |||
width: 40vw; | |||
height: 5vh; | |||
background-color: rgb(101, 161, 255); | |||
border-radius: 10vw; | |||
display: flex; | |||
justify-content: center; | |||
align-items: center; | |||
color:#fff; | |||
font-size: 4vw; | |||
margin: 2vh 0 0 30vw; | |||
} | |||
#scroll-to-top-btn { | |||
display: none; | |||
position: fixed; | |||
right: 20px; | |||
bottom: 20px; | |||
width: 7vw; | |||
height: 10vh; | |||
color: #fff; | |||
border: none; | |||
border-radius: 5px; | |||
font-size: 3vw; | |||
cursor: pointer; | |||
} | |||
.uploadImg{ | |||
width: 46vw !important; | |||
transform: translate(0%, 0%) !important; | |||
left: 27vw !important; | |||
position: relative; | |||
} | |||
} | |||
@media screen and (orientation: landscape) { | |||
input:focus { | |||
border: 0.1vw solid #000; | |||
outline: none; /* 可选,用于去除默认的外边框样式 */ | |||
} | |||
.login { | |||
width: 100vw; | |||
height: 100vh; | |||
background-image: url("/static/img/phoneBgc_pc.jpg"); | |||
background-size: 100% 100%; | |||
background-repeat: no-repeat; | |||
position: relative; | |||
} | |||
.register { | |||
background-image: url("/static/img/registerBgc_pc.jpg") !important; | |||
} | |||
.register_loginTitle { | |||
width: 100vw; | |||
display: flex; | |||
justify-content: center; | |||
font-size: 4vh; | |||
text-align: center; | |||
position: absolute; | |||
z-index: 10; | |||
top: 10vh; | |||
} | |||
.uploadImg { | |||
width: 15vw; | |||
} | |||
.register_inputBox { | |||
width: 100vw; | |||
display: flex; | |||
flex-direction: column; | |||
justify-content: center; | |||
align-items: center; | |||
position: relative; | |||
padding-top: 42vh; | |||
} | |||
.register_phoneInput { | |||
width: 37vh; | |||
height: 6vh; | |||
border-radius: 2vh; | |||
background-color: transparent; | |||
font-size: 3vh; | |||
border: 0.1vw solid #000; | |||
margin-bottom: 5vh; | |||
padding-left:1vw ; | |||
} | |||
.register_nameInput { | |||
width: 37vh; | |||
height: 6vh; | |||
border-radius: 2vh; | |||
background-color: transparent; | |||
font-size: 3vh; | |||
border: 0.1vw solid #000; | |||
padding-left: 1vw ; | |||
margin-bottom: 2vh; | |||
} | |||
.reg_button { | |||
width: 16vw; | |||
height: 3vw; | |||
background-color: rgb(101, 161, 255); | |||
border-radius: 10vh; | |||
display: flex; | |||
justify-content: center; | |||
align-items: center; | |||
color: #fff; | |||
font-size: 2vw; | |||
/* margin: 2vh 0 0 30vh; */ | |||
position: absolute; | |||
left: 55vw; | |||
top: 65vh; | |||
} | |||
.register_loginButton { | |||
width: 8vw; | |||
height: 2vw; | |||
background-color: rgb(101, 161, 255); | |||
border-radius: 1vw; | |||
display: flex; | |||
justify-content: center; | |||
align-items: center; | |||
color: #fff; | |||
font-size: 3vh; | |||
position: absolute; | |||
left: 46vw; | |||
top: 65vh; | |||
} | |||
.hand:hover{ | |||
cursor: pointer; | |||
} | |||
#scroll-to-top-btn { | |||
display: none; | |||
position: fixed; | |||
right: 20px; | |||
bottom: 20px; | |||
width: 7vh; | |||
height: 10vw; | |||
color: #fff; | |||
border: none; | |||
border-radius: 5px; | |||
font-size: 3vh; | |||
cursor: pointer; | |||
} | |||
.uploadImg{ | |||
width: 200px !important; | |||
transform: translate(0%, 0%) !important; | |||
left: 2vw !important; | |||
position: relative; | |||
} | |||
} | |||
.upload-img-box { | |||
position: relative; | |||
} | |||
.upload-img-box .input-box { | |||
display: inline-block; | |||
width: 144px; | |||
height: 144px; | |||
/*border: solid black 1px;*/ | |||
} | |||
.upload-img-box .befor-img { | |||
display: flex; | |||
/*width: 300px;*/ | |||
/*height: 90px;*/ | |||
/*border: solid black 1px;*/ | |||
position: absolute; | |||
top: 0px; | |||
left: 0px; | |||
/*background: #ffffff;*/ | |||
z-index: 30; | |||
align-items: center; | |||
justify-content: center; | |||
} | |||
.upload-img-box .befor-img.hasImg { | |||
display: none; | |||
} | |||
.upload-img-box .after-img { | |||
display: inline-block; | |||
width: 144px; | |||
height: 144px; | |||
border: none; | |||
/*position: absolute;*/ | |||
top: 0px; | |||
left: 0px; | |||
/*background: #ffffff;*/ | |||
z-index: 20; | |||
} | |||
.after-img img, .uploadImg { | |||
/*position: absolute;*/ | |||
width: 100%; | |||
height: 100%; | |||
object-fit: cover; /*根据父容器的尺寸裁剪和缩放图片,以填充整个容器,并保持长宽比例不变。*/ | |||
object-position: center; /*指定对象的位置,如果不设置,则默认是center*/ | |||
background-size: cover; /*背景图片的大小,如果不设置,则默认是auto*/ | |||
background-position: center; | |||
top: 50%; | |||
left: 50%; | |||
transform: translate(-50%, 0%);/*将元素移动到中心*/ | |||
border-radius: 50%; | |||
} | |||
</style> | |||
</head> | |||
<body> | |||
<!-- 注册页面 --> | |||
<div class="register login"> | |||
<div class="register_loginTitle "> | |||
<div class="upload-img-box"> | |||
<div class="input-box"> | |||
<input type="file" id="img-file" hidden="hidden" name="选择图片"> | |||
</div> | |||
<div class="befor-img"> | |||
<img class="uploadImg hand" src="/static/img/upload.png" alt=""> | |||
</div> | |||
<div class="after-img"> | |||
<img id="img-box" src="" width="30%" height="auto"> | |||
</div> | |||
</div> | |||
</div> | |||
<div class="register_inputBox"> | |||
<input class="register_nameInput" name="staffName" type="text" placeholder="员工姓名"> | |||
<input class="register_phoneInput" name="staffPhone" type="text" placeholder="员工手机号"> | |||
</div> | |||
<div class="register_loginButton hand">注册人脸</div> | |||
</div> | |||
<script src="/static/js/jquery.min.js"></script> | |||
<script src="/static/js/msg-box.js"></script> | |||
<script> | |||
$(function(){ | |||
$.MsgBox = { | |||
Alert: function(title, msg) { | |||
GenerateHtml("alert", title, msg); | |||
btnOk(); //alert只是弹出消息,因此没必要用到回调函数callback | |||
btnNo(); | |||
}, | |||
Confirm: function(title, msg, callback) { | |||
GenerateHtml("confirm", title, msg); | |||
btnOk(callback); | |||
btnNo(); | |||
} | |||
} | |||
$(".register_loginButton").on("click",function() { | |||
var staffPhone = $(".register_phoneInput").val(); | |||
var staffName = $(".register_nameInput").val(); | |||
const regex = /^1[3-9]\d{9}$/; | |||
if (staffPhone == "" || !regex.test(staffPhone)){ | |||
$.MsgBox.Alert("提示", "手机号为空或不合法,请检查"); | |||
return; | |||
} | |||
if (staffName == ""){ | |||
$.MsgBox.Alert("提示", "员工姓名为空,请检查"); | |||
return; | |||
} | |||
var img = $("#img-box").attr("src"); | |||
console.log(img); | |||
$.ajax({ | |||
url: "/register", | |||
type: "post", | |||
data: { | |||
staffPhone: staffPhone, | |||
staffName: staffName, | |||
avatar: img | |||
}, | |||
success: function(data) { | |||
$.MsgBox.Alert("提示", data.Message); | |||
}, | |||
error: function(error) { | |||
console.log(error); | |||
$.MsgBox.Alert("提示", error.responseJSON.Message); | |||
} | |||
}) | |||
}) | |||
$(document).on("click", ".upload-img-box .befor-img,.upload-img-box .after-img", function (e) { | |||
$(".input-box input").trigger("click"); | |||
}) | |||
// 使用input 的change事件,监听当文件上传的值进行改变的时候,才触发事件。 | |||
$(document).on("change", ".upload-img-box #img-file", function () { | |||
var file = $("#img-file")[0].files[0]; | |||
console.log(file); | |||
// file 内容包括: lastModified , lastModifiedDate , name , size , type | |||
var formdata = new FormData(); | |||
formdata.append('file', file); | |||
if (window.FileReader) { | |||
var fr = new FileReader(); | |||
fr.onloadend = function (e) { | |||
// console.log(this.result); | |||
// document.getElementById("portrait").src = e.target.result; | |||
$("#img-box").attr("src",e.target.result) | |||
$(".upload-img-box .befor-img").addClass("hasImg") | |||
}; | |||
//给FileReader对象一个读取完成的方法, | |||
//使用readAsDataURL会返回一个url | |||
//这个值就保存在事件对象的result里 | |||
//img通过加载这个地址,完成图片的加载 | |||
fr.readAsDataURL(file); | |||
} | |||
//判断图片大小 | |||
if (file.size > 3 * 1024 * 1024) { | |||
alert("上传图片不能大于3M"); | |||
} | |||
//判断图片数据类型 | |||
if (!/.(gif|jpg|jpeg|png|GIF|JPG|bmp)$/.test(file.name)) { | |||
alert("图片类型必须是.gif,jpeg,jpg,png,bmp中的一种"); | |||
} | |||
}) | |||
}) | |||
</script> | |||
</body> | |||
</html> |
@@ -0,0 +1,40 @@ | |||
<!DOCTYPE html> | |||
<html lang="en"> | |||
<head> | |||
<meta charset="UTF-8"> | |||
<meta http-equiv="X-UA-Compatible" content="IE=edge"> | |||
<meta name="viewport" content="width=device-width, initial-scale=1.0"> | |||
<title>Register</title> | |||
<link rel="stylesheet" href="/static/styles.css"> | |||
</head> | |||
<body> | |||
<h1>Register</h1> | |||
{{if .Message}} | |||
<p>{{.Message}}</p> | |||
{{end}} | |||
<form action="/register" method="post"> | |||
<label for="username">姓名:</label> | |||
<input type="text" id="username" name="username" required><br> | |||
{{ range $i, $v := .users }} | |||
<label >{{ $v.Name }}</label> | |||
{{ end }} | |||
<label for="phone">电话:</label> | |||
<input type="phone" id="phone" name="phone" required><br> | |||
<label for="level">员工类型:</label> | |||
<select> | |||
<option value="10">员工</option> | |||
<option value="71">领导</option> | |||
</select><br> | |||
<label for="level">性别:</label> | |||
<select> | |||
<option value="1">男</option> | |||
<option value="2">女</option> | |||
</select><br> | |||
<input type="submit" value="Register"> | |||
</form> | |||
<a href="/">Home</a> | |||
</body> | |||
</html> |