Vite tel input 國際電話輸入法套件

安裝 vue3-tel-input 國際電話輸入法套件

vue3-tel-input

1
npm i --save vue3-tel-input

main.ts 引入

1
2
3
4
5
6
7
8
9
10
11
12
import { createApp } from 'vue'
// @ts-ignore
import VueTelInput from 'vue3-tel-input'

// @ts-ignore 參數
const VueTelInputOptions = {
mode: "international",
onlyCountries: ['NG', 'GH', "GB", "US", "CA"]
}
const app = createApp(App)
app.use(VueTelInput, VueTelInputOptions);
app.mount('#app')

Vite sass安裝

Sass安裝

1
npm install --save sass sass-loader

package.json內的dependencies會有sass sass-loader的版本訊息如圖片

assets新增scss資料夾;新增檔案allStyle.scss; main.ts引入

1
2
//main.ts
import './assets/scss/allStyle.scss'

src/assets/scss新增public.scss

1
2
//allStyle.scss
@import "./public.scss";

錯誤訊息

Deprecation Warning [import]: Sass @import rules are deprecated and will be removed in Dart Sass 3.0.0.
棄用警告 [import]:Sass @import 規則已棄用,將在 Dart Sass 3.0.0 中刪除。

修改方式

1
@use "./public.scss";

public.scss

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
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
/*建立全域變數*/
:root {
--bs-blue: #0d6efd;
--bs-indigo: #6610f2;
--bs-purple: #6f42c1;
--bs-pink: #d63384;
--bs-red: #dc3545;
--bs-orange: #fd7e14;
--bs-yellow: #ffc107;
--bs-green: #198754;
--bs-teal: #20c997;
--bs-cyan: #0dcaf0;
--bs-black: #000;
--bs-white: #fff;
--bs-gray: #6c757d;
--bs-gray-dark: #343a40;
--bs-gray-100: #f8f9fa;
--bs-gray-200: #e9ecef;
--bs-gray-300: #dee2e6;
--bs-gray-400: #ced4da;
--bs-gray-500: #adb5bd;
--bs-gray-600: #6c757d;
--bs-gray-700: #495057;
--bs-gray-800: #343a40;
--bs-gray-900: #212529;
--bs-primary: #0d6efd;
--bs-secondary: #6c757d;
--bs-success: #198754;
--bs-info: #0dcaf0;
--bs-warning: #ffc107;
--bs-danger: #dc3545;
--bs-light: #f8f9fa;
--bs-dark: #212529;
--bs-primary-rgb: 13,110,253;
--bs-secondary-rgb: 108,117,125;
--bs-success-rgb: 25,135,84;
--bs-info-rgb: 13,202,240;
--bs-warning-rgb: 255,193,7;
--bs-danger-rgb: 220,53,69;
--bs-light-rgb: 248,249,250;
--bs-dark-rgb: 33,37,41;
--bs-primary-text-emphasis: #052c65;
--bs-secondary-text-emphasis: #2b2f32;
--bs-success-text-emphasis: #0a3622;
--bs-info-text-emphasis: #055160;
--bs-warning-text-emphasis: #664d03;
--bs-danger-text-emphasis: #58151c;
--bs-light-text-emphasis: #495057;
--bs-dark-text-emphasis: #495057;
--bs-primary-bg-subtle: #cfe2ff;
--bs-secondary-bg-subtle: #e2e3e5;
--bs-success-bg-subtle: #d1e7dd;
--default-color: hotpink;
--bs-bg-color: #ffff;
--bs-text-color: #808080;
--bs-line-height: 1.5;
--bs-font-weight: 400;
--bs-font-size: 14px;
--bs-font-family:"Mabry Pro","Noto Sans TC","微軟正黑體","Microsoft JhengHei","Heiti TC","黑體","Nunito Sans",sans-serif;
}
/*套用變數*/
body {
margin: 0;
font-family: var(--bs-font-family);
font-size: var(--bs-font-size);
font-weight: var(--bs-font-weight);
line-height: var(--bs-line-height);
color: var(--bs-dark-text-emphasis);
background-color: var(--bs-bg-color);
-webkit-text-size-adjust: 100%;
-webkit-tap-highlight-color: transparent;
}

github sass安裝

Vite 動態title

安裝 vue-page-title

vue-page-title

1
yarn add vue-page-title # npm i --save vue-page-title

在mail.ts內新增

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
import { createApp } from 'vue';

import { pageTitle } from 'vue-page-title';//引入vue-page-title

import VueGtag from 'vue-gtag-next';//引入ga
// @ts-ignore
import VueTelInput from 'vue3-tel-input';//引入國際電話下拉表單
// @ts-ignore
import 'vue3-tel-input/dist/vue3-tel-input.css'//引入國際電話下拉表單style
//引入router
import router from './router/index'
import App from './App.vue'

const app = createApp(App)
app.use(router)
app.use(pageTitle({ router }));//動態title
app.use(i18n);//i18n
app.use(pinia);//pinia

app.use(VueGtag, {
property: {
//id: 你的 google 分析追蹤碼
id: import.meta.env.VITE_API_URL,
},
})
app.use(VueTelInput, allCountries);//使用國際電話下拉表單

app.mount('#app')

router meta title名字

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
import { createRouter, createWebHashHistory } from 'vue-router';
import FooComponent from 'path/to/foo-component';
import HomeComponent from 'path/to/home-component';

const routes = [
{
path: '/',
component: HomeComponent,
meta: {
title: import.meta.env.VITE_API_TITLE +'Home Page', // Title must be a string.
},
},
{
path: '/foo',
component: FooComponent,
meta: {
title: 'Foo Page',
},
},
];

export default createRouter({
history: createWebHashHistory(),
routes,
});
結論:
  1. 安裝 vue-page-title
  2. main.ts引入 vue-page-title
  3. main.ts使用與Router搭配使用 app.use(pageTitle({ router }))
  4. router page 必須加入 meta: { title: 'Page Name', },


vue-page-title 範例

導入數據分析 Vue gtag

安裝vue-gtag-next

1
npm i -D vue-gtag-next

在main.ts內導入

1
2
3
4
5
6
7
8
9
10
11
12
//引入
import VueGtag from 'vue-gtag-next'

const app = createApp(App)
//使用
app.use(VueGtag, {
property: {
//id: 你的 google 分析追蹤碼
id: import.meta.env.VITE_API_URL,
},
})
app.mount('#app')

Stylelint

Stylelint

StyleLint 是一套檢查 CSS Coding Style

  • 安裝 stylelint npm install stylelint -D
  • 安裝 CSS 配置 npm install stylelint-config-standard -D
  • 安裝 SCSS 配置 npm install stylelint-config-sass-guidelines stylelint-scss -D
  • 安裝其他配置 可以參考 Stylelint 官方Github
  • 建立 .stylelintrc.cjs

    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
    module.exports = {
    // 繼承推薦規範配置
    extends: [
    "stylelint-config-standard",
    "stylelint-config-recommended-scss",
    "stylelint-config-recommended-vue/scss",
    "stylelint-config-html/vue",
    "stylelint-config-recess-order",
    ],
    // 指定不同文件對應的解析器
    overrides: [
    {
    files: ["**/*.{vue,html}"],
    customSyntax: "postcss-html",
    },
    {
    files: ["**/*.{css,scss}"],
    customSyntax: "postcss-scss",
    },
    ],
    // 自定義規則
    rules: {
    "import-notation": "string", // 指定導入CSS文件的方式("string"|"url")
    "selector-class-pattern": null, // 選擇器類名命名規則
    "custom-property-pattern": null, //自定義屬性命名規則
    "keyframes-name-pattern": null, // 動畫節點樣式命名規則
    "no-descending-specificity": null, // 允許無降序特異性
    // 允許 global 、export 、deep偽類
    "selector-pseudo-class-no-unknown": [
    true,
    {
    ignorePseudoClasses: ["global", "export", "deep"],
    },
    ],
    // 允許未知屬性
    "property-no-unknown": [
    true,
    {
    ignoreProperties: ["menuBg", "menuText", "menuActiveText"],
    },
    ],
    },
    };

    在 VS Code setting.json 加入自動修正錯誤,

    1
    2
    3
    4
    "editor.codeActionsOnSave": {
    "source.fixAll.eslint": true,
    "source.fixAll.stylelint": true
    },

    VS Code 安裝 stylelint套件

    套用到專案

    1
    2
    3
    4
    // 檢查錯誤
    npx stylelint "**/*.css"
    // 修正錯誤
    npx stylelint "**/*.css" --fix

    或是在 package.json 內設定,透過 npm run lint:style 去執行

    1
    2
    3
    4
    5
    6
    7
    8
    / package.json

    {
    "scripts": {
    "check:style": "stylelint **/*.{css,scss,sass,vue}",
    "lint:style": "stylelint **/*.{css,scss,sass,vue} --fix"
    }
    }

    stylelint參考資料

    stylelint失效問題

    Dayjs

    安裝

    dayjs官網
    所有程式碼都應該在這兩種環境中運行,並且所有單元測試都在這兩種環境中運行。

    目前,ci 系統使用以下瀏覽器:Windows XP 上的 Chrome、Windows 7 上的 IE 8、9 和 10、Windows 10 上的 IE 11、Linux 上最新的 Firefox 以及 OSX 10.8 和 10.11 上最新的 Safari。

    瀏覽器使用

    cdn

    1
    2
    3
    <!-- CDN example (jsDelivr) -->
    <script src="https://cdn.jsdelivr.net/npm/dayjs@1/dayjs.min.js"></script>
    <script>dayjs().format()</script>

    typescript

    參閱官網Typescript安裝

    1
    2
    3
    npm install --save dayjs
    import * as dayjs from 'dayjs'
    dayjs().format()

    區域設定和插件導入

    要使用語言環境和插件,您首先需要匯入目標語言和插件。

    1
    2
    3
    4
    5
    6
    import * as dayjs from 'dayjs'
    import * as isLeapYear from 'dayjs/plugin/isLeapYear' // import plugin
    import 'dayjs/locale/zh-cn' // import locale

    dayjs.extend(isLeapYear) // use plugin
    dayjs.locale('zh-cn') // use locale

    處理打包dayjs錯誤訊息

    打包dayjs錯誤訊息

    1
    2
    3
    4
    5
    6
    { //tsconfig.json
    "compilerOptions": {
    "esModuleInterop": true,
    "allowSyntheticDefaultImports": true,
    }
    }

    npm

    1
    2
    3
    4
    5
    npm install --save dayjs
    # or
    yarn add --save dayjs
    # or
    pnpm add --save dayjs

    npm 引入或使用

    1
    2
    3
    4
    5
    // 引入 Day.js
    const dayjs = require('dayjs')

    // 或使用 ES6 import 方式引入 Day.js,(Angular ,Vue,React 使用頁面引入方法)
    import dayjs from 'dayjs'

    使用方式

    dayjs取得目前時間為字符

    1
    2
    const now = new Date();//等同 dayjs(new Date());"2024-04-20T05:25:08.194Z"
    const now = dayjs() // 等同 dayjs(new Date());"2024-04-20T05:25:08.194Z"

    可傳入 Data 物件取得目前時間

    1
    const now = dayjs(new Date());"2024-04-20T05:25:08.194Z";

    *從字符”2024-04-20T05:25:08.194Z”取得時間搓

    1
    2
    const timestamp = new Date().getTime();
    console.log('timestamp',timestamp);//1713590708194

    取得特定時間的年月日時等資訊

    1
    2
    3
    4
    5
    6
    7
    8
    console.log('取得現在年份', dayjs().year())
    console.log('取得現在月份', dayjs().month() + 1)
    console.log('取得現在日', dayjs().date())
    console.log('取得星期', dayjs().day())
    console.log('取得時', dayjs().hour())
    console.log('取得分', dayjs().minute())
    console.log('取得秒', dayjs().second())
    console.log('取得豪秒',dayjs().millisecond())

    取得 UTC 時間

    1
    2
    3
    4
    5
    6
    7
    dayjs.extend(utc)

    // 取得本地時間
    dayjs().format() //2019-03-06T08:00:00+08:00

    // 取得 UTC 時間
    dayjs.utc().format() // 2019-03-06T00:00:00Z

    驗證返回的時間是否正確

    1
    2
    dayjs(null).isValid() // false
    dayjs().isValid() // true

    取得

    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
    // 取得毫秒
    dayjs().millisecond()
    // 設定毫秒,如傳入數字在 0-999 範圍外,會進位到秒。
    dayjs().millisecond(100)

    // 取得秒
    dayjs().seconds()
    // 設定秒,如傳入數字在 0-59 範圍外,會進位到分鐘。
    dayjs().seconds(30)


    // 取得分鐘
    dayjs().minute()
    // 設定秒,如傳入數字在 0-59 範圍外,會進位到小時。
    dayjs().minute(30)

    // 取得小時
    dayjs().hour()
    // 設定小時,如傳入數字在 0-23 範圍外,會進位到天數。
    dayjs().hour(12)

    // 取得天數
    dayjs().date()
    // 設定天數,如傳入數字在 0-月份天數 範圍外,會進位到月份。
    dayjs().date(1)

    // 取得星期(幾)
    dayjs().day()
    // 設定星期(幾),如傳入數字在 0-6 範圍外,會進位到週。
    dayjs().day(0)

    // 取得月份
    dayjs().month()
    // 設定月份,如傳入數字在 0-11 範圍外,會進位到年。
    dayjs().month(6)

    // 取得年份
    dayjs().year()
    // 設定年份
    dayjs().year(2020)

    格式化時間

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    dayjs().format("YYYY-MM-DD HH:mm:ss"); // 2025-03-25 21:11:06

    // 默認返回 ISO 8601 時間字串,例:'2020-05-15T10:59:34+08:00'
    dayjs().format()

    // 返回 'YYYYescape 2019-01-25T00:00:00-02:00Z'
    dayjs('2019-01-25').format('[YYYYescape] YYYY-MM-DDTHH:mm:ssZ[Z]')

    // 返回 '25/01/2019'
    dayjs('2019-01-25').format('DD/MM/YYYY')

    加減時間

    1
    2
    3
    4
    5
    // 取得現在日加1日
    dayjs().add(1, "day").date();

    // 取得現在日減1日
    dayjs().subtract(1, "day").date();

    計算時間差

    1
    2
    3
    4
    // 計算兩個時間的時間差(天)
    dayjs().diff(dayjs("2025-03-24"), "day"); //-3
    // 計算兩個時間的時間差分鐘
    dayjs().diff(dayjs("2025-03-20 11:00"), "minute"); //-43

    起始時間 / 結束時間

    1
    2
    dayjs().startOf("day").format('YYYY/MM/DD')
    dayjs().endOf("day").format('YYYY/MM/DD')

    轉換成 unix 時間戳記

    使用 valueOf() 可以將時間轉換成 unix 時間戳記

    1
    2
    3
    4
    5
    6
    7
    dayjs().valueOf() // 1742437455396

    // 情境:時間戳 => YYYY-MM-DD HH:mm:s
    dayjs(item.buildDate).format('YYYY-MM-DD HH:mm:ss')

    //情境:YYYY-MM-DD HH:mm:s => 時間戳
    dayjs(item.buildDate).valueOf()

    Node express MySql & Swagger

    使用 Express-Generator 來自動產生環境

    參考epxress generator 安裝
    node版本 14.20.1

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    //全域方法安裝express-generator
    npm install express-generator -g

    //项目初始化:專案名稱
    express -e 專案名稱

    //cd 專案名稱,到專案
    cd 專案名稱

    //啟動
    npm start

    到此網址觀看
    http://localhost:3000

    安裝mysql

    1
    npm install --save mysql

    安裝dotenv環境變數

    1
    npm install --save dotenv

    環境變數:新增.env

    1
    2
    3
    4
    5
    //.env
    DB_HOST=資料庫主機
    DB_USER=使用者
    DB_PASSWORD=密碼
    DB_NAME=資料庫名稱

    加入DB主機,使用者名稱,帳密,資料表名稱

    連接MySQL資料庫 Connecting to MySQL
    Create a new folder named config, and add database.js in this folder.
    新增 config資料夾內新增database.js

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    //database.js
    const mysql = require('mysql');
    require('dotenv').config();

    const connection = mysql.createConnection({
    host: process.env.DB_HOST,
    user: process.env.DB_USER,
    password: process.env.DB_PASSWORD,
    database: process.env.DB_NAME
    });

    connection.connect((err) => {
    if (err) throw err;
    console.log('連接MySQL資料庫');
    });

    module.exports = connection;

    定義使用者
    新增models/users.js

    • 載入資料庫const db = require('../config/database');
    • 獲取使用者陣列getAllUsers 函式 db.query('SELECT * FROM users', callback); SQL SELECT
    • 獲取單一使用者getUserById 函式 db.query('SELECT * FROM users WHERE id = ?', [id], callback) SQL WHERE
    • 建立單一使用者getUserById 函式 db.query('INSERT INTO users SET ?', newTodo, callback)SQL WHERE
    • 修改單一使用者updateUser 函式 db.query('UPDATE users SET ? WHERE id = ?', [updatedTodo, id], callback); SQL UPDATE
    • 刪除單一使用者deleteUser 函式 db.query('DELETE FROM users WHERE id = ?', [id], callback) SQL DELETE
    • 輸出getAllUsers,getUserById,getUserById,createUser,updateUser,deleteUser
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    //users.js
    const db = require('../config/database');
    //獲取所有
    exports.getAllUsers = (callback) =>
    {
    db.query('SELECT * FROM users', callback);
    };
    //獲取單一
    exports.getUserById = (id, callback) =>{
    db.query('SELECT * FROM users WHERE id = ?', [id], callback);
    };
    //建立單一
    exports.createUser = (newTodo, callback) =>{
    db.query('INSERT INTO users SET ?', newTodo, callback);
    };
    //修改單一
    exports.updateUser = (id, updatedTodo, callback)=>{
    db.query('UPDATE users SET ? WHERE id = ?', [updatedTodo, id], callback);
    };
    //刪除單一
    exports.deleteUser = (id, callback) =>{
    db.query('DELETE FROM users WHERE id = ?', [id], callback);
    };

    建立控制器
    新增controllers/userController.js

  • 引入models/users

  • 加入swagger名稱與描述必須語法

  • 獲取單一,修改單一,刪除單一都必須有唯一碼req.params.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
    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
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    //controllers/userController.js
    //引入models/users
    const User = require('../models/users');

    //獲取所有
    exports.getAllUsers = (req, res) => {
    User.getAllUsers((err, Users) =>
    {
    /* #swagger.tags = ['獲取所有使用者']
    #swagger.description = '' */
    if (err) throw err;
    res.json(Users);
    });
    };
    //獲取單一
    exports.getUserById = (req, res) =>
    {
    /* #swagger.tags = ['獲取單一使用者']
    #swagger.description = '' */
    User.getUserById(req.params.id, (err, User) => {
    if (err) throw err;
    res.json(User);
    });
    };
    //建立單一
    exports.createUser = (req, res) =>
    {
    /* #swagger.tags = ['新增單一使用者']
    #swagger.description = '' */
    /* #swagger.parameters['obj'] = {
    in: 'body',
    description: '',
    required: true,
    schema: { $ref: "#/definitions/AddUser" }
    } */
    const newUser = {
    name: req.body.name,
    address: req.body.address,
    country: req.body.country
    };

    User.createUser(newUser, (err, result) => {
    if (err) throw err;
    res.json({ message: '成功建立使用者',newUser,result});
    });
    };
    //修改立單一
    exports.updateUser = (req, res) =>
    {
    /* #swagger.tags = ['修改單一使用者']
    #swagger.description = '' */
    /* #swagger.parameters['obj'] = {
    in: 'body',
    description: '',
    required: true,
    schema: { $ref: "#/definitions/AddUser" }
    } */
    const updatedUser = {
    name: req.body.name,
    address: req.body.address,
    country: req.body.country
    };

    User.updateUser(req.params.id, updatedUser, (err, result) => {
    if (err) throw err;
    res.json({ message: '成功更新使用者',updatedUser,result});
    });
    };
    //刪除單一
    exports.deleteUser = (req, res) =>
    {
    /* #swagger.tags = ['刪除單一使用者']
    #swagger.description = '' */
    User.deleteUser(req.params.id, (err, result) => {
    if (err) throw err;
    res.json({ message: '成功刪除使用者!',result });
    });
    };

    swagger.js
    definitionss內的AddUser是預設參數

    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
    const swaggerAutogen = require('swagger-autogen')();
    //內容
    const doc = {
    info: {
    "version": "1.0.0",
    "title": "Node Mysql Restful Api",
    description: "larahuang2024/06/29"
    },

    host:['localhost:3000'], //"localhost:3000"
    basePath: "/",
    schemes: ['http'],//, 'https
    consumes: ['application/json'],
    produces: ['application/json'],
    //安全定義
    securityDefinitions: {

    apiKeyAuth:{
    type: "apiKey",
    in: "header",
    name: "Authorization",
    description: ""
    }
    },
    //定義
    definitions: {
    AddUser: {
    $name: "Lara",
    $address: '三重',
    $country: '新北市'
    },

    }
    }
    const outputFile = './swagger.json';
    const endpointsFiles = ['./index.js'];
    swaggerAutogen(outputFile, endpointsFiles,doc);

    Node express OAuth 2.0 使用 nodemailer 套件透過 gmail 發送電子信箱

    node 14.20.1

    步驟

    1. 申請 Google 認證模式OAuth
      以上獲得
      • CLINENT_ID
      • CLINENT_SECRET
      • REFRESHTOKEN
      • ACCESSTOKEN
    2. 安裝nodemailer

    一.申請 Google 認證模式OAuth

    一.Google 更改認證模式,Nodemailer 官方文件 也推薦改使用 OAuth 2.0 來介接 Gmail

    建立 OAuth
    Console
    Cloud Google

    1. 建立一個新專案 2.專案名 3.Api服務,搜尋Gmail Api 4.啟用Gmail Api 5.憑證->Auth 用戶端 ID 6選取外部 測試使用者 憑證 → 建立憑證 → OAuth 用戶端 ID
    取得用戶端編號Client ID與用戶端密鑰Client Secret 網路應用程式 已授權的重新導向 URI」選擇「新增 URL」
    https://developers.google.com/oauthplayground
    取得 Refresh token 與 Access token

    接下來請開啟這個網址這裡,然後點一下右上齒輪,並將「Use your own OAuth credentials」打勾輸入剛剛的 Client ID 以及 Client Secret



    Step2 取得Token


    以上獲得
    • CLINENT_ID
    • CLINENT_SECRET
    • REFRESHTOKEN
    • ACCESSTOKEN
    加到環境變數內請三考

    二.nodemailer:發信功能串接

    安裝 nodemailer
    nodemailer官網

    1
    npm install --save nodemailer 

    新增一個頁面router

    1
    2
    3
    // routes
    var contact = require('./routes/contact');
    app.use('/contact', contact);

    到contact 頁面

    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
    var express = require('express');
    var router = express.Router();
    var nodemailer = require('nodemailer');

    //環境變數
    require('dotenv').config()
    router.get('/', (req, res)=> {
    res.render('contact');
    });
    //這是寄送的成功訊息
    router.get('/review', (req, res)=> {
    res.render('contactReview');
    });

    //這是寄送的表單
    router.post('/post', (req, res) =>
    {
    const transporter = nodemailer.createTransport({
    host: 'smtp.gmail.com',
    port: 465,
    secure: true,
    auth: {
    type: "OAuth2",
    user: process.env.ACCOUNT,
    clientId: process.env.GMAIL_CLINENT_ID,
    clientSecret: process.env.GMAIL_CLINENT_SECRET,
    refreshToken: process.env.GMAIL_CLINENT_REFRESHTOKEN,
    accessToken: process.env.GMAIL_CLINENT_ACCESSTOKEN,
    }
    });
    let mail = req.body.email;
    var mailOptions = {
    form: '"我自己"<xxx@gmail.com>',
    to :`xxx@gmail.com,${mail}`,
    subject:req.body.title+':'+req.body.username +'的訂單',
    text: req.body.description
    }
    transporter.sendMail(mailOptions, (error, info) =>
    {
    console.log('info',info);
    if(error){
    return console.log(error,'訂單沒有送出!');
    }
    res.redirect('review');
    })
    });
    module.exports = router;

    token 有失效的問題

    刷新令牌
    刷新令牌2

    // 完整程式碼https://github.com/hsiangfeng/node-nodemailer-finish
    //https://hackmd.io/@yy933/Hy9rKyAE3?utm_source=preview-mode&utm_medium=rec

    參考文獻
    全端勇士之路 Node.js-OAuth 2.0 & nodemailer & Gmail
    Send mails from Gmail using Nodemaile
    Sending Emails with Node.js Using SMTP, Gmail, and OAuth2
    Sending Emails with Node.js Using SMTP, Gmail, and OAuth2
    Use Expressjs to send mails with gmail OAuth 2.0 and nodemailer
    OAUTH2
    Nodemailer/Gmail - What exactly is a refresh token and how do I get one?