About Time

new Date():現在時間(字符)

1
new Date();

console.log(Wed Jan 04 2023 15:14:33 GMT+0800 (台北標準時間))

1
2
3
4
5
6
7
8
9
10
const dateObject = new Date() 
const year = new Date().getFullYear() //年
const month = new Date().getMonth() //月+1
const day = new Date().getDay() //星期幾
const date = new Date().getDate() //日期
const hour = new Date().getHours() //0-24 小時
const minute = new Date().getMinutes() //0-59 分鐘
const second = new Date().getSeconds() //0-59 秒
const ms = new Date().getMilliseconds() //0-999
const timestamp = new Date().getTime(); //時間搓

TimeStamp 時間搓

1
Date.now();

console.log(‘TimeStamp’,1672816660300)

UTC(Universal Time Coordinated : 世界統一時間、世界標準時間

GMT(格林威治標準時間),格林威治標準時間(也稱為格林威治時間)

Unix 时间戳:這是基於 UTC 1970.01.01 00:00:00 到現在的總秒數,所以這個總秒數全世界都是這樣的,也就是說 Unix 的時間戳和時區無關

timezone時區

1
2
3
const timezoneByMins = new Date().getTimezoneOffset() //-480
//除以60後正負相轉才是時區
const timezone = -(new Date().getTimezoneOffset()/60) //-8

台灣時間 UTC +8

1
2
3
4
5
const date = new Date()

console.log(date.toLocaleString()) //2023/01/04 下午4:33:41
console.log(date.toLocaleDateString()) //2023/01/04
console.log(date.toLocaleTimeString()) //下午4:33:41

日期字串格式

這個 ISO 8601 Extended Format 格式大概長這樣:

1
YYYY-MM-DDTHH:mm:ss.sssZ

表單type 取得的 time 為 ‘10:00’這種格式如何改為時間搓

邏輯:獲得現在時間 =>切割時間與分鐘 => 設定時間與分鐘 =>獲得的時間字符getTime()

1
2
3
4
5
6
7
8
9
10
11
12
let now = new Date();
//表單type 取得的 time 為 '10:00'
const hourMinute = '10:00';
//split() 方法可以用來根據你指定的分隔符號,將字串切割成一個字串陣列。
var [hour, minute] = hourMinute.split(':');
now.setHours(hour) ;//setHours()方法依據本地時間來設定日期物件中的小時
now.setMinutes(minute);//setMinutes()方法依據本地時間來設定日期物件中的分鐘
now.setSeconds(0);
now.setMilliseconds(0);

console.log('現在時間',now) // Sat Apr 20 2024 10:00:00 GMT+0800 (台北標準時間);
console.log('時間搓',now.getTime()) // now.getTime()

控制時間與製作計時器的函式

setTimeout:延遲了某段時間後,才去執行的指定的程式碼,只會執行一次就結束

1
2
3
4
5
6
7
//一秒後執行
setTimeout(
()=>{
alert("Hello!");
}
,1000)

時鐘setInterval:設定時間的間隔

//無限次的設置定時器執行

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<template>
<div>
<div class="today">{{ today }}</div>
<div class="time">{{ time }}</div>
</div>
</template>
<script setup lang="ts">
import { ref, onMounted } from 'vue';
//moment時間套件
import moment from 'moment';

const today = ref<any>(moment(new Date()).format("yyyy MM DD"));
const time = ref<any>();
onMounted(()=>{
setInterval(()=>{
time.value = new Date().getHours() + ':' + new Date().getMinutes() + ':' + new Date().getSeconds();
},1000)
})
</script>

clearInterval():取消setInterval()設的定時器

Vue3 動態 Web title

Vue 動態 Title

每個網頁都會有WebTitle ,在Vue 的專案內必須要全局中才能獲取到,
在App.vue 內必須使用

當打開網頁Home時塞入localStorage.setItem(‘pageClass’,’pageHome’),
綁定body document.querySelector(‘body’) => 將 localStorage.getItem(‘pageClass’)設定屬性setAttribute 到body的Class,且將網頁主題名稱塞入titleTag

  • Pinia全局綁定title 與 切換時改變title
  • 綁定body 設定屬性 setAttribute class 改變body class
  • 監控 watchEffect 改變
  • 1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    import { defineStore } from 'pinia';

    export const usePageStore = defineStore('page', () => {

    const setPageClass = (pageClass:string) => {
    document.querySelector('body')?.setAttribute('class', pageClass);
    }
    const getPageClass=()=>{
    let pageClass:any | string =localStorage.getItem('pageClass');
    switch (pageClass) {
    case pageClass:
    document.querySelector('body')?.setAttribute('class', pageClass);
    break
    }
    }
    const changeTitleTag = (title: string) => {
    const titleTag = document.querySelector('title');

    if (titleTag != null) {
    titleTag.innerText = '採購系統'+' | '+title;
    }
    }

    return{
    setPageClass,getPageClass,changeTitleTag
    }
    })

    引入頁面
    首頁頁面

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    <template>
    <div>{{ title }}</div>
    </template>

    <script setup lang="ts">
    import { ref, onMounted,watchEffect } from 'vue'
    import { usePageStore } from '../stores/titleTag'

    const storePageTag = usePageStore()
    const {getPageClass,changeTitleTag,setPageClass} = storePageTag
    const title = ref<string>('首頁')
    const pageClass = ref<string>('homePage')
    watchEffect(() => {
    getPageClass();
    setPageClass(pageClass.value)
    })
    onMounted(() => {
    changeTitleTag(title.value);
    });
    </script>

    登入頁面

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    <template>
    <div>{{ title }}</div>
    </template>

    <script setup lang="ts">
    import { ref, onMounted,watchEffect } from 'vue'
    import { usePageStore } from '../stores/titleTag'
    const storePageTag = usePageStore()
    const {getPageClass,changeTitleTag,setPageClass} = storePageTag
    const title = ref<string>('請先登入')
    const pageClass = ref<string>('loginPage')
    watchEffect(() => {
    getPageClass();
    setPageClass(pageClass.value)
    })
    onMounted(() => {
    changeTitleTag(title.value);

    });
    </script>

    Node express 權限管理

    權限管理

    資料表設計
    • 使用者資料表: `users` 使用者,上面綁角色role_id,每個使用者都有一種角色
    • 角色資料表: `roles` 角色,用來設定權限用
    • 模組資料表: `module_permissions` 模組權限,用來綁定底下功能權限
    • 功能資料表: `func_permissions` 功能權限,用來綁底層的權限
    • 權限資料表: `permissions` 用來綁func_permissions與permission_types的表
    • 權限型別資料表: `permission_types` 權限分類,可自行定義分類,如:查看、新增、編輯、刪除…等
    使用者 => (一對多) 角色 => (一對多) 模組 => (一對多) 功能 => (一對多) 權限 => (多對一) 權限型別

    根據使用者角色獲得頁面檢視權限

    1
    2
    3
    4
    SELECT users.id, users.uId, users.userName, users.userEmail, users.userPassword, users.userPhone, users.roleId, users.token ,modulePermissions.modulePermissionId,modulePermissions.modulePermissionName,modulePermissions.pageLink 
    FROM `users`
    INNER JOIN `modulePermissions`
    ON users.uId=modulePermissions.roleId WHERE users.userName =?

    bcryptjs密碼加密與驗證

    安裝bcryptjs bcryptjs
    密碼加密,此套件的加密是不可逆的,所以沒有辦法從加密後的結果回推原始密碼,相對安全性提高非常多

    1
    2
    npm install bcryptjs --save

    加密後的 bcrypt 分為四個部分:

    • Bcrypt
      該字串為 UTF-8 編碼,並且包含一個終止符
    • Round
      (回合數)每增加一次就加倍雜湊次數,預設10次
    • Salt
      (加鹽)128 bits 22個字元
    • Hash
      (雜湊)138 bits 31個字元

    Node express MySql 註冊與登入

    註冊

    因爲註冊使用到bcryptjs密碼加密功能,
    bcrypt加密語法

    1
    2
    3
    4
    5
    6
    //引入bcryptjs密碼加密
    const bcrypt = require('bcryptjs')

    const saltRounds = 10;
    const hashPassword = bcrypt.hashSync(密碼, saltRounds)

    models.users.js

    1
    INSERT INTO `users` (column1, column2, column3...) SET (value1, value2, value3...)

    token

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    //bcryptjs密碼加密
    const bcrypt = require('bcryptjs')
    //載入 jsonwebtoken
    const jwt = require('jsonwebtoken')
    // 建立使用者
    var User = function(newUser){
    this.uId = newUser.uId;
    this.userName = newUser.userName;
    this.userEmail = newUser.userEmail;
    this.userPassword = bcrypt.hashSync(newUser.userPassword, 3);//bcrypt.hashSync(newUser.userPassword, 12)
    this.userPhone= newUser.userPhone;
    this.roleId= newUser.roleId;
    this.token = jwt.sign({_id: newUser.uId ,username: newUser.userName,email: newUser.userEmail}, 'RESTFULAPI',{expiresIn: "24h"}).toString();//jwt
    this.createdAt= newUser.createdAt;
    this.updatedAt= newUser.updatedAt;
    this.deletedAt= newUser.deletedAt;
    }
    User.create = function (newUser, callback) {
    db.query('INSERT INTO users SET ?', newUser, callback);
    };
    module.exports = User;

    登入

    尋找帳號與密碼驗證 => 內連結的模組資料表的資料內容 (取出modulePermissionId與modulePermissionName 並且新增到menu )
    使用資料庫語法:

    1
    2
    3
    4

    SELECT 顯示欄位 FROM `資料表1` INNER JOIN `資料表2` ON 資料表1uId=資料表2roleId WHERE 資料表1.欄位名 ='';
    //例如
    SELECT users.id, users.uId, users.userName, users.userEmail, users.userPassword, users.userPhone, users.roleId, users.token ,modulePermissions.modulePermissionId,modulePermissions.modulePermissionName FROM `users` INNER JOIN `modulePermissions` ON users.uId=modulePermissions.roleId WHERE users.userName =?;

    登入時必須帳號登入時驗證密碼(bcrypt.compareSync(密碼, 密碼加密))

    bcrypt驗證語法

    1
    bcrypt.compareSync(密碼, 密碼加密)

    models.users.js

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    'use strict';

    var db = require('../config/database');
    //bcryptjs密碼加密
    const bcrypt = require('bcryptjs')
    //載入 jsonwebtoken
    const jwt = require('jsonwebtoken')

    User.userName = (userName, result) =>
    {
    let sql = 'SELECT users.id, users.uId, users.userName, users.userEmail, users.userPassword, users.userPhone, users.roleId, users.token ,modulePermissions.modulePermissionId,modulePermissions.modulePermissionName FROM `users` INNER JOIN `modulePermissions` ON users.uId=modulePermissions.roleId WHERE users.userName =?';
    db.query(sql, userName, (err, row, fields) =>
    {
    if (err) result(err, null,);
    result(null, row);
    });
    };

    controllers.users.js

    • bcrypt.hashSync(密碼, SaltRound)
    • bcrypt.compareSync(密碼,加密密碼)
    加密後的 bcrypt 分為四個部分:
    • Bcrypt
      該字串為 UTF-8 編碼,並且包含一個終止符
    • Round
      (回合數)每增加一次就加倍雜湊次數,預設10次
    • Salt
      (加鹽)128 bits 22個字元
    • Hash
      (雜湊)138 bits 31個字元
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    const User = require('../models/users');

    exports.login = async (req, res, next) =>
    {
    /*
    #swagger.summary='登入',
    #swagger.description = '' */

    /* #swagger.parameters['body'] = {
    in: 'body',
    description: '',
    required: true,
    schema: { $ref: "#/definitions/Login" }
    } */

    /* #swagger.security = [{
    "apiKeyAuth": []
    }] */

    const userName = req.body.userName;
    const userPassword = req.body.userPassword;

    try {
    //檢查是否有userName 帳號
    User.userName(userName, (error, item) =>
    {
    if (item.length != 0 && bcrypt.compareSync(userPassword, item[0].userPassword) ) {
    // console.log('登入item', item)
    console.log('登入驗證密碼', bcrypt.compareSync(userPassword, item[0].userPassword))
    let menu = [];
    // forEach
    item.forEach(el => {
    let query = {
    modulePermissionId: el.modulePermissionId,
    modulePermissionName: el.modulePermissionName,
    }
    menu.push(query)
    });
    let loginValue = {
    userName: item[0].userName,
    token: item[0].token,
    menu: menu,
    }
    return res.status(200).json(loginValue);
    } else {
    return res.status(400).send('沒有userName')
    }
    })
    }
    catch (error) {
    return res.status(500).json({message: error.message})
    }
    }
    routes/users.js
    1
    2
    3
    4
    5
    var express = require('express');
    var router = express.Router();
    const userController = require('../controllers/users');

    router.post('/login', userController.login);

    MySql 目錄

    AUTO INCREMENT 欄位會自動遞增資料行的值

    AUTO_INCREMENT 欄位會自動遞增資料行的值

    AUTO INCREMENT 欄位會自動遞增資料行的值,因為每次新增資料時欄位值都會自動遞增也就是說 AUTO INCREMENT 欄位值會是唯一的,該欄位用途就像是一個識別碼或流水號,而 AUTO INCREMENT 常與 Primary Key 一起搭配使用。
    將 users 資料表中的 id 欄位 AUTO INCREMENT 欄位會自動遞增資料行的值,

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    CREATE TABLE `users` ( 
    id INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
    uId INT NOT NULL UNIQUE,
    userName VARCHAR(30) NOT NULL,
    userEmail VARCHAR(50) NOT NULL,
    userPassword VARCHAR(30) NOT NULL,
    userPhone VARCHAR(10) NOT NULL,
    roleId INT NOT NULL,
    createdAt TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
    updatedAt TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
    deletedAt TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
    );
    CREATE TABLE `users` (
    id INT NOT NULL AUTO_INCREMENT,
    uId INT NOT NULL,
    userName VARCHAR(50) NOT NULL,
    userEmail VARCHAR(30)NOT NULL,
    userPassword VARCHAR(30) NOT NULL,
    userPhone VARCHAR(10) NOT NULL,
    roleId INT NOT NULL,
    createdAt TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
    updatedAt TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
    deletedAt TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ,
    PRIMARY KEY (id),
    UNIQUE (uId)
    );
    參考:AUTO INCREMENT 欄位 (SQL AUTO INCREMENT column)

    PRIMARY KEY 主鍵限制 與 AUTO INCREMENT 欄位會自動遞增資料行的值

    PRIMARY KEY 主鍵限制 (SQL PRIMARY KEY Constraint)

    PRIMARY KEY 用來保證欄位在資料表中的唯一性,主鍵欄位中的每一筆資料在資料表中都必需是獨一無二的。
    PRIMARY KEY 有點類似 UNIQUE 加上 NOT NULL。

    一個資料表中只能有一個 PRIMARY KEY,但是可以有多個 UNIQUE。
    將 users 資料表中的 id 欄位設為主鍵:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    CREATE TABLE `users` ( 
    id INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
    uId INT NOT NULL UNIQUE,
    userName VARCHAR(30) NOT NULL,
    userEmail VARCHAR(50) NOT NULL,
    userPassword VARCHAR(30) NOT NULL,
    userPhone VARCHAR(10) NOT NULL,
    roleId INT NOT NULL,
    createdAt TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
    updatedAt TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
    deletedAt TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
    );
    CREATE TABLE `users` (
    id INT NOT NULL AUTO_INCREMENT,
    uId INT NOT NULL,
    userName VARCHAR(50) NOT NULL,
    userEmail VARCHAR(30)NOT NULL,
    userPassword VARCHAR(30) NOT NULL,
    userPhone VARCHAR(10) NOT NULL,
    roleId INT NOT NULL,
    createdAt TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
    updatedAt TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
    deletedAt TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ,
    PRIMARY KEY (id),
    UNIQUE (uId)
    );

    參考:PRIMARY KEY 主鍵限制 (SQL PRIMARY KEY Constraint)

    AUTO_INCREMENT 欄位會自動遞增資料行的值

    AUTO INCREMENT 欄位會自動遞增資料行的值,因為每次新增資料時欄位值都會自動遞增也就是說 AUTO INCREMENT 欄位值會是唯一的,該欄位用途就像是一個識別碼或流水號,而 AUTO INCREMENT 常與 Primary Key 一起搭配使用。
    將 users 資料表中的 id 欄位 AUTO INCREMENT 欄位會自動遞增資料行的值,

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    CREATE TABLE `users` ( 
    id INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
    uId INT NOT NULL UNIQUE,
    userName VARCHAR(30) NOT NULL,
    userEmail VARCHAR(50) NOT NULL,
    userPassword VARCHAR(30) NOT NULL,
    userPhone VARCHAR(10) NOT NULL,
    roleId INT NOT NULL,
    createdAt TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
    updatedAt TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
    deletedAt TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
    );
    CREATE TABLE `users` (
    id INT NOT NULL AUTO_INCREMENT,
    uId INT NOT NULL,
    userName VARCHAR(50) NOT NULL,
    userEmail VARCHAR(30)NOT NULL,
    userPassword VARCHAR(30) NOT NULL,
    userPhone VARCHAR(10) NOT NULL,
    roleId INT NOT NULL,
    createdAt TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
    updatedAt TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
    deletedAt TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ,
    PRIMARY KEY (id),
    UNIQUE (uId)
    );
    參考:AUTO INCREMENT 欄位 (SQL AUTO INCREMENT column)

    建立一個新資料庫

    SQL 語句不區分大小寫

    1
    CREATE DATABASE 新資料庫名稱;

    參考:CREATE DATABASE 語法(Syntax)

    創建table

    1
    2
    3
    4
    5
    6
    CREATE TABLE 資料表名稱 (
    欄位column_name1 欄位屬性data_type,
    欄位column_name2 欄位屬性data_type,
    欄位column_name3 欄位屬性data_type,
    ···
    );
    例如:建立資料表table 名稱 users
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    CREATE TABLE `users` ( 
    id INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
    uId INT NOT NULL UNIQUE,
    userName VARCHAR(30) NOT NULL,
    userEmail VARCHAR(50) NOT NULL,
    userPassword VARCHAR(30) NOT NULL,
    userPhone VARCHAR(10) NOT NULL,
    roleId INT NOT NULL,
    createdAt TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
    updatedAt TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
    deletedAt TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
    );
    CREATE TABLE `users` (
    id INT NOT NULL AUTO_INCREMENT,
    uId INT NOT NULL,
    userName VARCHAR(50) NOT NULL,
    userEmail VARCHAR(30)NOT NULL,
    userPassword VARCHAR(30) NOT NULL,
    userPhone VARCHAR(10) NOT NULL,
    roleId INT NOT NULL,
    createdAt TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
    updatedAt TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
    deletedAt TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ,
    PRIMARY KEY (id),
    UNIQUE (uId)
    );
    參考:CREATE TABLE 是我們在資料庫中用來建立一個新資料表的語法

    新增資料至某資料表: INSERT INTO 是用來新增資料至某資料表 (table)

    1
    2
    3
    4
    5
    INSERT INTO table_name (column1, column2, column3...)
    VALUES (value1, value2, value3...);
    or
    INSERT INTO table_name
    VALUES (value1, value2, value3...);
    例如:新增資料至users資料表
    1
    INSERT INTO `users`(`uId`, `userName`, `userEmail`, `userPassword`, `userPhone`, `roleId`, `createdAt`, `updatedAt`, `deletedAt`) VALUES ('1735223063','laraHuang','laraHuang@gmail.com','Lara123456','0910123456','1735223063','2024-12-26 22:24:23','2024-12-26 22:24:23','2024-12-26 22:24:23')

    參考:INSERT INTO 是用來新增資料至某資料表 (table)