commit 3f342cee87b5effeda58a2893e58f6a4ad951deb Author: DATAEXPRESS\4734 Date: Fri Feb 6 15:09:39 2026 +0800 first commit diff --git a/basecore/cloud_addtime.txt b/basecore/cloud_addtime.txt new file mode 100644 index 0000000..d28befc --- /dev/null +++ b/basecore/cloud_addtime.txt @@ -0,0 +1,34 @@ +DELIMITER // + +CREATE OR REPLACE PROCEDURE cloud_addtime( + IN date_utc DATETIME +) +/* + Function : 因為所有的雲端主機, 都是存 UTC, 要 -8 換為 Taipei 時間 + Description: 1.如果有多國的來源, 這個方法並不徹底, 目前先暫用 + 2.目前測試 -8 看起來就正常 + 3.這個 stored procedure 只是單純地在 select xx日期 時, 將時間 -8 hrs, 並不會異動資料庫的內容 + 純粹是配合 Azure Cloud 主機的運作而已 + CALL cloud_addtime(NOW()); + Build Date : 2022/12/03 + + Modify History + Item Who Date Modify Docs + ==== ========== ========== ================================================ + 1 Michael 2022/12/03 Init +*/ +BEGIN + DECLARE date_taipei DATETIME; + DECLARE diff_hours SMALLINT; + + SELECT pvalue INTO diff_hours FROM sys_parameter WHERE systemid = 'sys' AND pid = 'diff_hours'; + IF diff_hours IS NULL THEN + SET diff_hours = 8; + END IF; + + SET date_taipei = DATE_ADD(date_utc, INTERVAL diff_hours HOUR); + + SELECT date_taipei AS result; -- You can select the result or do something else with it +END // + +DELIMITER ; diff --git a/basecore/cloud_adjusttime.txt b/basecore/cloud_adjusttime.txt new file mode 100644 index 0000000..56b41fd --- /dev/null +++ b/basecore/cloud_adjusttime.txt @@ -0,0 +1,35 @@ +DELIMITER // + +CREATE OR REPLACE PROCEDURE cloud_adjusttime( + IN date_utc DATETIME, + IN base INT +) +/* + Function : 因為所有的雲端主機, 都是存 UTC, 要 -8 換為 Taipei 時間, 原 cloud_addtime 的反向 udf, FullCalendar 存檔前使用 + Description: 1.如果有多國的來源, 這個方法並不徹底, 目前先暫用 + 2.目前測試 -8 看起來就正常 + 3.這個 stored procedure 只是單純地在 select xx日期 時, 將時間 -8 hrs, 並不會異動資料庫的內容 + 純粹是配合 Azure Cloud 主機的運作而已 + CALL cloud_adjusttime(NOW(), -1); + Build Date : 2023/2/11 + + Modify History + Item Who Date Modify Docs + ==== ========== ========== ================================================ + 1 Michael 2023/02/11 Init +*/ +BEGIN + DECLARE date_taipei DATETIME; + DECLARE diff_hours SMALLINT; + + SELECT pvalue INTO diff_hours FROM sys_parameter WHERE systemid = 'sys' AND pid = 'diff_hours'; + IF diff_hours IS NULL THEN + SET diff_hours = 8; + END IF; + + SET date_taipei = DATE_ADD(date_utc, INTERVAL diff_hours * base HOUR); + + SELECT date_taipei AS result; -- You can select the result or do something else with it +END // + +DELIMITER ; diff --git a/basecore/gf_trans_json_v7.txt b/basecore/gf_trans_json_v7.txt new file mode 100644 index 0000000..0b51d95 --- /dev/null +++ b/basecore/gf_trans_json_v7.txt @@ -0,0 +1,61 @@ +DELIMITER // + +CREATE OR REPLACE FUNCTION `gf_trans_json_v7` ( + p_source TEXT, + p_actions VARCHAR(1) -- C(reate) 或 U(pdate) +) +/* + function : 將 amis 傳入的字串, 轉為標準 json 格式後回傳給 orm_api(配合 mariadb) + 修改自 gf_trans_json(已不使用) + description: 呼叫範例 SELECT gf_trans_json_v7('xxxx', 'C'); + build date : 2021/09/26 + + modify history + item who date modify docs + ==== ========== ========== ================================================ + 1 michael 2021/09/26 新增 + 2 [改寫者] 2023/11/15 改寫為 MariaDB 版本並最佳化 +*/ +RETURNS TEXT +DETERMINISTIC +BEGIN + DECLARE v_max INT; + DECLARE v_now INT; + DECLARE v_rets TEXT; + DECLARE v_rows_pos INT; + DECLARE v_rows_diff_pos INT; + + IF p_actions = 'C' THEN + SET v_rets = SUBSTRING(p_source, 2, CHAR_LENGTH(p_source) - 1); + + -- step1: 先移除數字鍵 (最佳化:使用迴圈而非逐次檢查) + SET v_now = 0; + WHILE v_now <= 1000 DO + IF INSTR(v_rets, CONCAT('"', v_now, '":')) > 0 THEN + SET v_rets = REPLACE(v_rets, CONCAT('"', v_now, '":'), ''); + END IF; + SET v_now = v_now + 1; + END WHILE; + + -- 移除結尾多餘的 } 字符 + IF RIGHT(v_rets, 2) = '}}' THEN + SET v_rets = LEFT(v_rets, CHAR_LENGTH(v_rets) - 1); + END IF; + + SET v_rets = CONCAT('{[', v_rets, ']}'); + ELSEIF p_actions = 'U' THEN + -- 找出 rows 和 rowsDiff 的位置 + SET v_rows_pos = INSTR(p_source, '"rows":'); + SET v_rows_diff_pos = INSTR(p_source, '"rowsDiff":'); + + -- 擷取 rows 內容並格式化 + SET v_rets = SUBSTRING(p_source, 1, v_rows_diff_pos - 3); + SET v_rets = SUBSTRING(v_rets, v_rows_pos + 8, CHAR_LENGTH(v_rets)); + + SET v_rets = CONCAT('{[', v_rets, ']}'); + END IF; + + RETURN v_rets; +END // + +DELIMITER ; \ No newline at end of file diff --git a/basecore/sysexec.txt b/basecore/sysexec.txt new file mode 100644 index 0000000..e87f70b --- /dev/null +++ b/basecore/sysexec.txt @@ -0,0 +1,62 @@ +DELIMITER // + +CREATE OR REPLACE PROCEDURE `sysexec` ( + IN p_token VARCHAR(100), + IN p_sql LONGTEXT +) +/* + function : 傳入 Insert/Update 的 sql 指令並執行 + description: 不允許 drop delete 這類的 sql 語法 + build date : 2018/05/05 + + modify history + item who date modify docs + ==== ========== ========== ================================================ + 1 Michael 2018-11-05 init + 2 [改寫者] 2023-11-15 改寫為 MariaDB 版本並最佳化 +*/ +BEGIN + DECLARE v_userid VARCHAR(100); + DECLARE v_exstr LONGTEXT; + DECLARE v_code INT; + DECLARE v_msg VARCHAR(255); + + -- 根據傳入的 token 取得 userid + SELECT userid INTO v_userid FROM sys_users WHERE token = p_token LIMIT 1; + + IF v_userid IS NULL THEN + SET v_code = 9; + SET v_msg = '請先登入系統再執行!!'; + + SELECT v_code AS code, v_msg AS msg; + SELECT ''; + ELSEIF LOCATE('delete ', LOWER(p_sql)) > 0 OR LOCATE('drop ', LOWER(p_sql)) > 0 THEN + SET v_code = 4; + SET v_msg = '內含不允許執行的 sql 語法, 請重新輸入?!'; + + SELECT v_code AS code, v_msg AS msg; + SELECT ''; + ELSE + BEGIN + DECLARE EXIT HANDLER FOR SQLEXCEPTION + BEGIN + SET v_code = 9; + SET v_msg = '語法有錯,請檢查語法後再重新執行!!'; + + SELECT v_code AS code, v_msg AS msg; + SELECT ''; + END; + + SET v_code = 0; + SET v_msg = '成功執行 SQL 語法'; + + SELECT v_code AS code, v_msg AS msg; + SET @dynamic_sql = p_sql; + PREPARE stmt FROM @dynamic_sql; + EXECUTE stmt; + DEALLOCATE PREPARE stmt; + END; + END IF; +END // + +DELIMITER ; \ No newline at end of file diff --git a/basecore/trans_cname.txt b/basecore/trans_cname.txt new file mode 100644 index 0000000..460ad34 --- /dev/null +++ b/basecore/trans_cname.txt @@ -0,0 +1,67 @@ +DELIMITER // + +CREATE OR REPLACE FUNCTION `trans_cname` ( + p_fieldname VARCHAR(100), + p_fieldcn NVARCHAR(100) +) +/* + Function : 根據 zen_fields,zen_dd_erp,zen_dd 的內容, 回傳可能的中文欄位 Title + Description: 通常是配合 sp=zen_fieldspec_best 使用 + Build Date : 2021/11/25 + + Modify History + Item Who Date Modify Docs + ==== ========== ========== ================================================ + 1 Michael 2021/11/25 新增 + 2 [改寫者] 2023-11-15 改寫為 MariaDB 版本並最佳化 +*/ +RETURNS NVARCHAR(100) +DETERMINISTIC +BEGIN + DECLARE v_ret NVARCHAR(100); + DECLARE v_dd_id VARCHAR(100); + DECLARE v_dd_name VARCHAR(100); + + SET v_ret = p_fieldcn; + + IF p_fieldcn = '' OR p_fieldname = p_fieldcn THEN + -- 先找 zen_fields + SELECT fieldcn INTO v_ret + FROM zen_fields + WHERE fieldname = p_fieldname + AND fieldname <> fieldcn + AND IFNULL(fieldcn, '') <> '' + LIMIT 1; + + -- 新增 zen_dd_erp(原 erp) + IF IFNULL(v_ret, '') = '' THEN + SELECT fieldcn INTO v_ret + FROM zen_dd_erp + WHERE fieldname = p_fieldname + AND fieldname <> fieldcn + AND IFNULL(fieldcn, '') <> '' + LIMIT 1; + END IF; + + -- 再找 zen_dd + IF IFNULL(v_ret, '') = '' THEN + SELECT fieldname, cname INTO v_dd_id, v_dd_name + FROM zen_dd + WHERE LOCATE(fieldname, p_fieldname) > 0 + LIMIT 1; + + IF IFNULL(v_dd_id, '') <> '' THEN + SET v_ret = REPLACE(p_fieldname, v_dd_id, v_dd_name); + END IF; + END IF; + END IF; + + -- 實在找不到的話, 只能回傳 fieldname + /* IF IFNULL(v_ret, '') = '' THEN + SET v_ret = p_fieldname; + END IF; */ + + RETURN v_ret; +END // + +DELIMITER ; \ No newline at end of file diff --git a/basecore/usp_GetErrorInfo_v2.txt b/basecore/usp_GetErrorInfo_v2.txt new file mode 100644 index 0000000..a315ee5 --- /dev/null +++ b/basecore/usp_GetErrorInfo_v2.txt @@ -0,0 +1,22 @@ +DELIMITER // + +CREATE OR REPLACE PROCEDURE `usp_GetErrorInfo_v2`() +/* + 傳回簡化錯誤訊息, 通常配合 DECLARE EXIT HANDLER FOR SQLEXCEPTION 中使用 + 對應 MS-SQL 的 usp_GetErrorInfo_v2 +*/ +BEGIN + -- 獲取錯誤資訊 + DECLARE v_err_msg TEXT; + + GET DIAGNOSTICS CONDITION 1 + v_err_msg = MESSAGE_TEXT; + + -- 返回簡化格式 + SELECT + 1 AS code, -- 預設錯誤代碼 + v_err_msg AS msg, + 0 AS recno; +END // + +DELIMITER ; \ No newline at end of file diff --git a/basecore/zen_bpm_define.txt b/basecore/zen_bpm_define.txt new file mode 100644 index 0000000..ceaf8ca --- /dev/null +++ b/basecore/zen_bpm_define.txt @@ -0,0 +1,121 @@ +DELIMITER // + +CREATE OR REPLACE FUNCTION zen_bpm_define ( + p_FunctionTag VARCHAR(100), + p_FunctionTag_org VARCHAR(100), + p_pk VARCHAR(100), + p_ip VARCHAR(100), -- ijѥ~ǤJγ]ww]ȡAMariaDB ѼƤ䴩ܼƷw] + p_db VARCHAR(100) +) +RETURNS LONGTEXT +LANGUAGE SQL +DETERMINISTIC +BEGIN + DECLARE v_rets LONGTEXT; + DECLARE v_crlf CHAR(1); + DECLARE v_type CHAR(1); + + -- ]wŸ [cite: 3, 4] + SET v_crlf = CHAR(10); + + -- P_O_ñ֥ view + IF INSTR(p_FunctionTag_org, '_') > 0 THEN + SET v_type = 'Y'; + ELSE + SET v_type = 'N'; + END IF; + + -- }lզX JSON r [cite: 5] + SET v_rets = CONCAT( + ' {', v_crlf, + ' "type": "button-toolbar",', v_crlf, + ' "buttons": [', v_crlf + ); + + -- ھ @type Mwse [cite: 5] + IF v_type = 'N' THEN + -- Wes [cite: 5, 6] + SET v_rets = CONCAT(v_rets, + ' {', v_crlf, + ' "type": "button",', v_crlf, + ' "label": "We",', v_crlf, + ' "actionType": "ajax",', v_crlf, + ' "confirmText": "TwnWeH",', v_crlf, + ' "disabledOn": "${flow_status != ''N''}",', v_crlf, + ' "api": {', v_crlf, + ' "method": "post",', v_crlf, + ' "url": "${ls:base_ip}/xapi/v3/${ls:base_db}/bpmm02_spread/1/",', v_crlf, + ' "data": {', v_crlf, + ' "para01": "', p_FunctionTag, '",', v_crlf, + ' "para02": "${personid}",', v_crlf, + ' "para03": "${', p_pk, '}"', v_crlf, + ' },', v_crlf, + ' "dataType": "form"', v_crlf, + ' },', v_crlf, + ' "level": "primary"', v_crlf, + ' },', v_crlf + ); + ELSE + -- PNB^B@os (ñּҦ) [cite: 10, 15, 20] + SET v_rets = CONCAT(v_rets, + -- PN [cite: 11, 12] + ' {', v_crlf, + ' "type": "button", "label": "PN", "actionType": "dialog", "level": "success",', v_crlf, + ' "disabledOn": "${ls:bpm_signable == 0}",', v_crlf, + ' "dialog": { "title": "PN", "size": "lg", "body": { "type": "service", "schemaApi": {', v_crlf, + ' "method": "post", "url": "${ls:base_ip}/xapi/v3/${ls:wizard_db}/zen_showsource/0/",', v_crlf, + ' "data": { "para01": "bpmm11_i", "para02": "beta@${', p_pk, '}" }, "dataType": "form"', v_crlf, + ' } } }', v_crlf, + ' },', v_crlf, + -- ^ [cite: 15, 16, 17] + ' {', v_crlf, + ' "type": "button", "label": "^", "actionType": "dialog", "level": "danger",', v_crlf, + ' "disabledOn": "${ls:bpm_signable == 0}",', v_crlf, + ' "dialog": { "title": "^", "size": "lg", "body": { "type": "service", "schemaApi": {', v_crlf, + ' "method": "post", "url": "${ls:base_ip}/xapi/v3/${ls:wizard_db}/zen_showsource/0/",', v_crlf, + ' "data": { "para01": "bpmm12_i", "para02": "beta@${', p_pk, '}" }, "dataType": "form"', v_crlf, + ' } } }', v_crlf, + ' },', v_crlf, + -- @o [cite: 20, 21, 22] + ' {', v_crlf, + ' "type": "button", "label": "@o", "actionType": "dialog", "level": "dark",', v_crlf, + ' "disabledOn": "${ls:bpm_cancelable > 0}",', v_crlf, + ' "dialog": { "title": "@o", "size": "lg", "body": { "type": "service", "schemaApi": {', v_crlf, + ' "method": "post", "url": "${ls:base_ip}/xapi/v3/${ls:wizard_db}/zen_showsource/0/",', v_crlf, + ' "data": { "para01": "bpmm13_i", "para02": "beta@${', p_pk, '}" }, "dataType": "form"', v_crlf, + ' } } }', v_crlf, + ' },', v_crlf + ); + END IF; + + -- ñ־{ [cite: 25, 26, 27] + SET v_rets = CONCAT(v_rets, + ' {', v_crlf, + ' "type": "button", "label": "ñ־{", "actionType": "dialog", "level": "warning",', v_crlf, + ' "dialog": { "title": "ñ־{", "size": "lg", "body": { "type": "service", "schemaApi": {', v_crlf, + ' "method": "post", "url": "${ls:base_ip}/xapi/v3/${ls:wizard_db}/zen_showsource/0/",', v_crlf, + ' "data": { "para01": "bpmq11", "para02": "beta@${', p_pk, '}", "_tag": "', p_FunctionTag, '" },', v_crlf, + ' "dataType": "form", "requestAdaptor": "local_set_params(51, api.data._tag); return { ...api, data: { ...api.data }};"', v_crlf, + ' } } }', v_crlf, + ' },', v_crlf + ); + + -- ˵y{ñ֤H [cite: 30, 31, 32] + SET v_rets = CONCAT(v_rets, + ' {', v_crlf, + ' "type": "button", "label": "˵y{ñ֤H", "actionType": "dialog", "level": "secondary",', v_crlf, + ' "dialog": { "title": "˵y{ñ֤H", "size": "lg", "body": { "type": "service", "schemaApi": {', v_crlf, + ' "method": "post", "url": "${ls:base_ip}/xapi/v3/${ls:wizard_db}/zen_showsource/0/",', v_crlf, + ' "data": { "para01": "bpmq12", "para02": "beta@${', p_pk, '}", "_tag": "', p_FunctionTag, '" },', v_crlf, + ' "dataType": "form", "requestAdaptor": "local_set_params(51, api.data._tag); return { ...api, data: { ...api.data }};"', v_crlf, + ' } } }', v_crlf, + ' }', v_crlf, + ' ]', v_crlf, + ' },', v_crlf, + ' { "type": "divider" },', v_crlf + ); + + RETURN v_rets; +END // + +DELIMITER ; \ No newline at end of file diff --git a/basecore/zen_create_table.txt b/basecore/zen_create_table.txt new file mode 100644 index 0000000..5f58e06 --- /dev/null +++ b/basecore/zen_create_table.txt @@ -0,0 +1,180 @@ +DELIMITER // + +CREATE OR REPLACE PROCEDURE `zen_create_table` ( + IN p_tablename VARCHAR(100), + IN p_source_type VARCHAR(1) -- 1:zen_newtable_d 2:zen_fields join zen_function +) +/* + Function : 配合 api 可以直接產生 table 的 sp + Description: 因為只能在相同的 db 執行, 所以在 zenWinzard 或 zenBusiness 都要有此 sp 及 zen_newtable_m/zen_newtable_d + 在平台的架構中雖然放在 Wizard Menu 中, 但手改 json 連到 zenBusiness(zenEIS) 等 ERP DB, + 因為通常需要新增的 table 都是 MIS 要擴充功能用的 + CALL zen_create_table('tmp_test01','2'); + + 2023-07-07 + 因為希望參考 iCoder 的作法, 匯入 zen_fields 後, 直接就產生程式(接近一鍵產生程式碼), 所以新增 p_source_typ=2 + 但是 zen_fields 是 zenWinzard 的 table, 如果是分離型 db 架構, 就無法支援 p_source_typ=2 這很傷腦筋, 怎麼辦? 如果傳入 db ?? + 看樣子只能先獨立建立 table (p_source_typ=1), 然後匯入 zen_fields, 再產生 Code, 先這樣吧 + + 2023-08-26 用資料庫的同義字功能, 已解決分離式資料庫的問題 + + Build Date : 2022/02/16 + + Modify History + Item Who Date Modify Docs + ==== ========== ========== ================================================ + 1 Michael 2022/02/16 Init + 2 Michael 2023/06/28 新增也可以根據 zen_function/zen_fields 來產生 Table 的寫法(必須配合 zen_function 也已經新增定義才行) + 3 Michael 2023/07/29 create table 後, 要多 select 0 as code 才不會報錯 + 4 [改寫者] 2023-11-15 改寫為 MariaDB 版本並最佳化 +*/ +BEGIN + DECLARE v_sql LONGTEXT; + DECLARE v_rets LONGTEXT; + DECLARE v_maxcount INT; + DECLARE v_currid INT; + DECLARE v_nextrowid INT; + + DECLARE v_fieldname VARCHAR(100); + DECLARE v_field_type VARCHAR(100); + DECLARE v_field_len SMALLINT; + DECLARE v_is_pk CHAR(1); + DECLARE v_is_auto CHAR(1); + DECLARE v_sql_tail VARCHAR(100); + DECLARE v_sql_pk VARCHAR(100); + DECLARE v_row_count INT; + + -- 創建臨時表來存儲字段信息 + DROP TEMPORARY TABLE IF EXISTS temp_table_fields; + CREATE TEMPORARY TABLE temp_table_fields ( + fieldname VARCHAR(100), + field_type VARCHAR(100), + field_len SMALLINT, + is_pk CHAR(1), + is_auto CHAR(1), + rowid INT AUTO_INCREMENT PRIMARY KEY + ); + + -- 根據來源類型填充臨時表 + IF IFNULL(p_source_type, '1') = '1' THEN + INSERT INTO temp_table_fields (fieldname, field_type, field_len, is_pk, is_auto) + SELECT fieldname, field_type, field_len, is_pk, is_auto + FROM zen_newtable_d + WHERE tablename = p_tablename; + ELSE + -- 使用同義字(Synonym)解決跨資料庫問題 + INSERT INTO temp_table_fields (fieldname, field_type, field_len, is_pk, is_auto) + SELECT + x1.fieldname, + CASE + WHEN x1.fieldobject IN ('textarea','input-file','link-file','input-image','nvarchar') THEN 'varchar' + WHEN x1.fieldobject IN ('int','decimal','smallint') THEN x1.fieldobject + WHEN x1.fieldobject IN ('radios','progress') THEN 'smallint' + WHEN x1.fieldobject = 'input-number' THEN 'int' + WHEN x1.fieldobject IN ('input-datetime','datetime') THEN 'datetime' + WHEN x1.fieldobject = 'input-date' THEN 'date' + WHEN LOCATE('cycle', x1.fieldobject) > 0 THEN x1.fieldobject -- 獨立判斷 + ELSE 'varchar' + END field_type, + x1.fieldlength AS field_len, + CASE WHEN LOCATE(x1.fieldname, x2.mainkey) > 0 THEN 'Y' ELSE 'N' END is_pk, + x2.isautoinc AS is_auto + FROM zen_fields x1 + LEFT JOIN zen_function x2 ON x1.functiontag = x2.functiontag + WHERE x1.tablename = p_tablename AND x1.fieldobject <> 'formula'; + END IF; + + -- 初始化變量 + SELECT MAX(rowid), MIN(rowid) INTO v_maxcount, v_currid FROM temp_table_fields; + + SET v_rets = ''; + SET v_sql_pk = ''; + + -- 構建字段定義 + WHILE v_currid <= v_maxcount DO + -- 取得當前字段信息 + SELECT fieldname, field_type, field_len, is_pk, is_auto + INTO v_fieldname, v_field_type, v_field_len, v_is_pk, v_is_auto + FROM temp_table_fields + WHERE rowid = v_currid; + + SET v_sql_tail = ''; + IF v_is_pk = 'Y' THEN + SET v_sql_tail = ' NOT NULL'; + SET v_sql_pk = CONCAT(v_sql_pk, v_fieldname, ','); + END IF; + + IF v_is_auto = 'Y' THEN + SET v_sql_tail = CONCAT(v_sql_tail, ' AUTO_INCREMENT'); + END IF; + + IF LOCATE('transfer', v_field_type) > 0 OR v_field_len < 0 THEN + SET v_rets = CONCAT(v_rets, ' ', v_fieldname, ' ', v_field_type, '(255)', v_sql_tail, ','); + ELSEIF LOCATE('cycle', v_field_type) > 0 THEN + IF v_field_type IN ('cycle-frequency','cycle-weeks','cycle-months') THEN + SET v_rets = CONCAT(v_rets, ' ', v_fieldname, ' varchar(200)', v_sql_tail, ','); + ELSE + SET v_rets = CONCAT(v_rets, ' ', v_fieldname, ' datetime ', v_sql_tail, ','); + END IF; + ELSEIF LOCATE('char', v_field_type) > 0 THEN + IF v_field_len <= 0 THEN + SET v_rets = CONCAT(v_rets, ' ', v_fieldname, ' ', v_field_type, '(200)', v_sql_tail, ','); + ELSE + SET v_rets = CONCAT(v_rets, ' ', v_fieldname, ' ', v_field_type, '(', v_field_len, ')', v_sql_tail, ','); + END IF; + ELSE + SET v_rets = CONCAT(v_rets, ' ', v_fieldname, ' ', v_field_type, v_sql_tail, ','); + END IF; + + -- 取得下一筆資料 + SELECT MIN(rowid) INTO v_nextrowid FROM temp_table_fields WHERE rowid > v_currid; + SET v_currid = v_nextrowid; + END WHILE; + + -- 處理主鍵定義 + IF v_sql_pk = '' THEN + SET v_sql_pk = ''; + SET v_rets = SUBSTRING(v_rets, 1, CHAR_LENGTH(v_rets) - 1); + ELSE + SET v_sql_pk = CONCAT(' PRIMARY KEY (', SUBSTRING(v_sql_pk, 1, CHAR_LENGTH(v_sql_pk) - 1), ')'); + END IF; + + -- 只有當有字段定義時才創建表 + IF v_rets <> '' THEN + -- 檢查表是否存在,如果存在且無數據則刪除 + SET @sql_check = CONCAT('SELECT COUNT(*) INTO @row_count FROM information_schema.tables ', + 'WHERE table_schema = DATABASE() AND table_name = \'', p_tablename, '\''); + PREPARE stmt FROM @sql_check; + EXECUTE stmt; + DEALLOCATE PREPARE stmt; + + IF @row_count > 0 THEN + SET @sql_check = CONCAT('SELECT COUNT(*) INTO @row_count FROM ', p_tablename); + PREPARE stmt FROM @sql_check; + EXECUTE stmt; + DEALLOCATE PREPARE stmt; + + IF @row_count <= 0 THEN + SET @sql = CONCAT('DROP TABLE ', p_tablename); + PREPARE stmt FROM @sql; + EXECUTE stmt; + DEALLOCATE PREPARE stmt; + END IF; + END IF; + + -- 創建新表 + SET v_sql = CONCAT('CREATE TABLE ', p_tablename, '(', + v_rets, + v_sql_pk, ');'); + + -- 執行創建表的SQL + PREPARE stmt FROM v_sql; + EXECUTE stmt; + DEALLOCATE PREPARE stmt; + + -- 返回成功信息 + SELECT 0 AS code, 'OK' AS msg; + END IF; +END // + +DELIMITER ; \ No newline at end of file diff --git a/basecore/zen_fieldspec_best.txt b/basecore/zen_fieldspec_best.txt new file mode 100644 index 0000000..d4bdcf6 --- /dev/null +++ b/basecore/zen_fieldspec_best.txt @@ -0,0 +1,286 @@ +DELIMITER // + +CREATE OR REPLACE PROCEDURE `zen_fieldspec_best` ( + IN p_functiontag VARCHAR(100) +) +/* + Function : 針對 zen_field 的內容, 根據 schema 給出最接近的預設值, 以簡化設定動作 + Description: + Build Date : 2021/08/14 + Call Sample: + CALL zen_fieldspec_best('abc01'); + + Modify History + Item Who Date Modify Docs + ==== ========== ========== ================================================ + 1 Michael 2021-11-25 新增 fieldblock = 90 的判斷(detail) + 2 Michael 2022-04-16 update zen_fields set fieldro = Y (Read Only 預設) + 3 Michael 2022-10-02 加入對 Query 的支援(根據 tag 判斷) + 4 Michael 2023-02-09 加入 flow_status 預設值=N + 5 Michael 2023-09-01 加入 2個系統欄位的預設值 create_user/create_date + 6 [改寫者] 2023-11-15 改寫為 MariaDB 版本並最佳化 +*/ +BEGIN + /* + 根據下列內容設定 + fieldobject 更換為最合理的物件 + fieldcn ==> dd ? (date=日期, id=代號, Name=名稱, 描述 取已經存在的同名? 建立一個常用習慣的詞庫? 這可以和 dd 並存) + fieldwidth 根據 length 推算 width(Grid 顯示寬度) + --fielddefault 日期=today 等 + --fieldchecknull + --fieldds,fieldsh + cellx,celly + */ + + DECLARE v_imax INT; + DECLARE v_inow INT; + DECLARE v_cnt INT; + DECLARE v_x INT; + DECLARE v_y INT; + DECLARE v_row INT; + DECLARE v_line INT; + DECLARE v_block INT; + DECLARE v_tablename VARCHAR(100); + DECLARE v_fieldname VARCHAR(100); + DECLARE v_fieldcn VARCHAR(100); + DECLARE v_fld_type VARCHAR(100); + DECLARE v_fieldobject VARCHAR(100); + DECLARE v_fieldlength INT; + DECLARE v_fld_width VARCHAR(10); + DECLARE v_jump SMALLINT; + -- + DECLARE v_report_type VARCHAR(100); + DECLARE v_type_f SMALLINT; + DECLARE v_type_q SMALLINT; + + -- 創建臨時表 + DROP TEMPORARY TABLE IF EXISTS tmp_fields; + DROP TEMPORARY TABLE IF EXISTS tmp_query_fields; + + -- upgrade data(防錯) + UPDATE zen_fields SET datatype = fieldobject WHERE functiontag = p_functiontag AND datatype IS NULL; + + /* + 根據 p_functiontag 識別是 Form or Query + */ + SELECT COUNT(*) INTO v_type_f FROM zen_fields WHERE functiontag = p_functiontag; + SELECT COUNT(*) INTO v_type_q FROM zen_report_fields WHERE functiontag = p_functiontag; + + IF v_type_f > 0 THEN + -- 創建臨時表並插入數據 + CREATE TEMPORARY TABLE tmp_fields AS + SELECT * FROM zen_fields WHERE functiontag = p_functiontag; + + SELECT MAX(fieldid), MIN(fieldid), COUNT(*) + INTO v_imax, v_y, v_cnt + FROM tmp_fields; + + SET v_row = 1; + IF v_cnt > 10 AND v_cnt <= 30 THEN + SET v_row = 2; + ELSEIF v_cnt > 30 THEN + SET v_row = 2; + END IF; + + SET v_x = 1; + SET v_line = 1; + + WHILE v_y <= v_imax DO + SELECT tablename, fieldname, fieldcn, datatype, fieldlength, fieldblock + INTO v_tablename, v_fieldname, v_fieldcn, v_fieldobject, v_fieldlength, v_block + FROM tmp_fields WHERE fieldid = v_y; + + /* step 1: 設定 object */ + -- varchar, char, nvarchar ... + SET v_fld_type = v_fieldobject; + IF LOCATE('char', v_fieldobject) > 0 THEN + IF v_fieldlength >= 200 THEN + SET v_fld_type = 'textarea'; + ELSEIF v_fieldlength = 1 THEN + SET v_fld_type = 'switch'; + ELSE + SET v_fld_type = 'input-text'; + END IF; + END IF; + + IF LOCATE('int', v_fieldobject) > 0 OR LOCATE('decimal', v_fieldobject) > 0 THEN + SET v_fld_type = 'input-number'; + END IF; + + IF LOCATE('date', v_fieldobject) > 0 THEN + SET v_fld_type = 'input-date'; + END IF; + + -- 防錯 + IF v_fld_type = '' THEN + SET v_fld_type = 'input-text'; + END IF; + + /* + step 2: 推估 width(暫時保留, 但在 amis 中, width 已經幾乎不必設定) + */ + IF v_fld_type = 'input-date' OR v_fld_type = 'input-number' THEN + SET v_fld_width = 80; + ELSE + IF v_fieldlength <= 10 THEN + SET v_fld_width = 80; + ELSEIF v_fieldlength <= 20 THEN + SET v_fld_width = 120; + ELSE + SET v_fld_width = 200; + END IF; + END IF; + + -- 判斷如果是 detail, fieldblock = 90 + SELECT COUNT(*) INTO v_cnt FROM zen_function WHERE detail_table = v_tablename; + IF v_cnt > 0 THEN + SET v_block = 90; + END IF; + + /* + step3: 推算 x/y + */ + SET v_jump = 0; + IF v_row = 2 AND v_fieldlength >= 50 THEN + IF v_x = 1 THEN + SET v_jump = 1; + ELSE + SET v_x = 1; + SET v_line = v_line + 1; + END IF; + END IF; + + IF v_row = 3 AND v_fieldlength >= 50 THEN + IF v_x = 1 THEN + SET v_jump = 1; + ELSE + SET v_x = 1; + SET v_line = v_line + 1; + END IF; + END IF; + + /* + step 4: update & cname(dd) + */ + UPDATE zen_fields + SET fieldobject = v_fld_type, + fieldwidth = v_fld_width, + cellx = v_x, + celly = v_line, + fieldblock = v_block, + fieldcn = trans_cname(v_fieldname, v_fieldcn) + WHERE fieldid = v_y; + + IF v_row = 1 THEN + SET v_line = v_line + 1; + ELSEIF v_row = 2 THEN + SET v_x = v_x + 1; + IF v_x > 2 OR (v_jump = 1) THEN + SET v_x = 1; + SET v_line = v_line + 1; + END IF; + ELSEIF v_row = 3 THEN + SET v_x = v_x + 1; + IF v_x > 3 OR (v_jump = 1) THEN + SET v_x = 1; + SET v_line = v_line + 1; + END IF; + END IF; + + SELECT MIN(fieldid) INTO v_y FROM tmp_fields WHERE fieldid > v_y; + END WHILE; + + /* + 批次更新(不需逐筆寫入) + step 5: setup read only(create_user ..) + step 6: flow_status 的預設值為 N + */ + UPDATE zen_fields + SET fieldro = 'Y' + WHERE functiontag = p_functiontag + AND fieldname IN ('create_user','create_date','update_user','update_date') + AND IFNULL(fieldro, '') = ''; + + UPDATE zen_fields + SET fielddefault = '$ls:userid' + WHERE functiontag = p_functiontag + AND fieldname = 'create_user' + AND IFNULL(fielddefault, '') = ''; + + UPDATE zen_fields + SET fielddefault = 'today' + WHERE functiontag = p_functiontag + AND fieldname = 'create_date' + AND IFNULL(fielddefault, '') = ''; + + UPDATE zen_fields + SET fielddefault = '自動編碼' + WHERE functiontag = p_functiontag + AND fieldname = 'billno' + AND IFNULL(fielddefault, '') = ''; + + UPDATE zen_fields + SET fielddefault = 'today' + WHERE functiontag = p_functiontag + AND fieldname = 'billdate' + AND IFNULL(fielddefault, '') = ''; + + UPDATE zen_fields + SET fielddefault = 'N' + WHERE functiontag = p_functiontag + AND fieldname = 'flow_status' + AND IFNULL(fielddefault, '') = ''; + + -- hidden 的 ds 和 sh 都應該設為 Y ,20230926 + UPDATE zen_fields + SET fieldds = 'Y', fieldsh = 'Y' + WHERE functiontag = p_functiontag + AND fieldobject = 'hidden'; + + SELECT 0 AS code, 'OK' AS msg; + + ELSEIF v_type_q > 0 THEN + -- 處理查詢字段 + CREATE TEMPORARY TABLE tmp_query_fields AS + SELECT * FROM zen_report_fields WHERE functiontag = p_functiontag; + + SELECT MAX(fieldid), MIN(fieldid) + INTO v_imax, v_y + FROM tmp_query_fields; + + SELECT COUNT(*) INTO v_cnt FROM tmp_query_fields; + + SET v_x = 1; + SET v_line = 1; + + WHILE v_y <= v_imax DO + SELECT fieldname, fieldcn, fieldobject, report_type + INTO v_fieldname, v_fieldcn, v_fieldobject, v_report_type + FROM tmp_query_fields WHERE fieldid = v_y; + + /* + step 1: update cname(dd) + */ + UPDATE zen_report_fields + SET fieldcn = trans_cname(v_fieldname, v_fieldcn) + WHERE fieldid = v_y AND fieldname = fieldcn; + + /* + step 2: setup display + */ + UPDATE zen_report_fields + SET fieldds = 'Y' + WHERE fieldid = v_y; + + SELECT MIN(fieldid) INTO v_y FROM tmp_query_fields WHERE fieldid > v_y; + END WHILE; + + SELECT 0 AS code, 'OK' AS msg; + END IF; + + -- 清理臨時表 + DROP TEMPORARY TABLE IF EXISTS tmp_fields; + DROP TEMPORARY TABLE IF EXISTS tmp_query_fields; +END // + +DELIMITER ; \ No newline at end of file diff --git a/basecore/zen_get_ext_button.txt b/basecore/zen_get_ext_button.txt new file mode 100644 index 0000000..f2849b9 --- /dev/null +++ b/basecore/zen_get_ext_button.txt @@ -0,0 +1,258 @@ +DELIMITER // + +CREATE OR REPLACE FUNCTION zen_get_ext_button( + p_functionTag VARCHAR(20), + p_button_type CHAR(1), + p_ip VARCHAR(100), -- 'https://api.gex.com.tw:5443' + p_db VARCHAR(100) -- 'zenBusiness' +) +RETURNS TEXT +/* + function : 回傳擴充 button 的設定內容 + description: + build date : 2022/2/5 + + call sample: + SELECT zen_get_ext_button('basm67','U'); + + modify history + item who date modify docs + ==== ========== ========== ================================================ + 1 Michael 2022-2-5 新增 + 2 Michael 2023-1-29 重新想清處並定義相關設定, 然後修改相關程式, 詳細請參見註解 + 3 Michael 2023-02-01 為了更加彈性, @ip 及 @db 這2個欄位改傳入 ${ls:xxxx}, 測試可行(程式要調整前端呼叫的程式) +*/ +BEGIN + DECLARE v_cnt INT; + DECLARE v_crlf VARCHAR(2); + DECLARE v_comma VARCHAR(1); + DECLARE v_fcaption VARCHAR(100); + DECLARE v_icon VARCHAR(100); + DECLARE v_related_menuid VARCHAR(100); + DECLARE v_rets TEXT; + DECLARE v_para_field VARCHAR(100); + DECLARE v_new_para_field VARCHAR(100); + DECLARE v_ls_paras_field VARCHAR(100); -- button 按下後, 要帶到另一個表單的 pk 值 + DECLARE v_ls_paras_no INT; -- 參數代號 zenutil.js -> function local_set_params(id, value) + DECLARE v_imax INT; + DECLARE v_inow INT; + -- + DECLARE p_uuid VARCHAR(100); + DECLARE v_sp_name VARCHAR(100); -- sp_name + DECLARE v_para1 VARCHAR(100); -- 有 token 一定要放在第一個 + DECLARE v_para2 VARCHAR(100); + DECLARE v_para3 VARCHAR(100); + DECLARE v_para4 VARCHAR(100); + DECLARE v_data_para1 VARCHAR(200); + DECLARE v_data_para2 VARCHAR(200); + + -- 臨時表儲存 JSON 數據 + DROP TEMPORARY TABLE IF EXISTS temp_jsondata; + CREATE TEMPORARY TABLE temp_jsondata ( + rowid INT AUTO_INCREMENT PRIMARY KEY, + fcaption VARCHAR(20), + icon VARCHAR(50), + related_menuid VARCHAR(200), -- 關聯功能(或是呼叫某 sp) + para_field VARCHAR(100), + ls_paras_field VARCHAR(100), + ls_paras_no INT + ); + + SET v_crlf = CONCAT(CHAR(13), CHAR(10)); + + -- 插入資料到臨時表 + INSERT INTO temp_jsondata (fcaption, icon, related_menuid, para_field, ls_paras_field, ls_paras_no) + SELECT + fcaption, icon, related_menuid, para_field, ls_paras_field, ls_paras_no + FROM zen_function_button fn + WHERE fn.FunctionTag = p_functionTag AND button_type = p_button_type + ORDER BY buttonid; + + -- 回傳 options [] + SELECT COUNT(*) INTO v_imax FROM temp_jsondata; + SET v_inow = 1; + SET v_rets = ''; + SET v_comma = ','; + + WHILE v_inow <= v_imax DO + -- 取得當前行數據 + SELECT fcaption, icon, related_menuid, para_field, ls_paras_field, ls_paras_no + INTO v_fcaption, v_icon, v_related_menuid, v_para_field, v_ls_paras_field, v_ls_paras_no + FROM temp_jsondata + WHERE rowid = v_inow; + + IF IFNULL(v_icon, '') = '' THEN + SET v_icon = 'fas fa-binoculars'; + END IF; + + IF IFNULL(v_ls_paras_no, 0) = 0 THEN + SET v_ls_paras_no = 0; + END IF; + + /* + 只要後 2個參數 ls_paras_field,ls_paras_no 有值, 就表示是呼叫外部專案, 否則就只是單純的 v_new_para_field + 接下來, 判斷 para_field 是否為空 + a.如果為空, 表示要傳入 ls_paras_field 這個欄位的值 + b.如果不為空, 且首碼為 _ , 表示要傳入固定字串, 否則還是傳入 ls_paras_field 這個欄位的值(自定義變數, 防錯而已) + Michael 2023-1-29 好難理解阿, 會這麼複雜, 是因為不斷擴充定義, 且沒有完全考慮清楚的後果, 目前這樣定義應該是 OK 的 + */ + SET v_data_para1 = ''; + SET v_data_para2 = ''; + SET v_new_para_field = ''; + + -- 取得傳遞參數的資料 + IF IFNULL(v_ls_paras_field, '') <> '' AND IFNULL(v_ls_paras_no, 0) > 0 THEN + -- 防錯碼(重複設定) + IF IFNULL(v_para_field, '') = CONCAT('_', v_ls_paras_field) THEN + SET v_para_field = ''; + END IF; + + IF IFNULL(v_para_field, '') = '' THEN + SET v_data_para1 = CONCAT(',', v_crlf, ' "_', v_ls_paras_field, '": "${', v_ls_paras_field, '}"', v_crlf); + SET v_data_para2 = CONCAT(',', v_crlf, ' "requestAdaptor": "local_set_params(', CAST(v_ls_paras_no AS CHAR), ',api.data._', v_ls_paras_field, '); return { ...api, data: { ...api.data }};"', v_crlf); + ELSEIF SUBSTRING(v_para_field, 1, 1) = '_' THEN + -- 表示要傳入固定值內容, 非欄位值內容 + SET v_data_para1 = CONCAT(',', v_crlf, ' "', v_para_field, '": "', v_ls_paras_field, '"', v_crlf); + SET v_data_para2 = CONCAT(',', v_crlf, ' "requestAdaptor": "local_set_params(', CAST(v_ls_paras_no AS CHAR), ',api.data.', v_para_field, '); return { ...api, data: { ...api.data }};"', v_crlf); + ELSE + -- 要自己命名變數(防錯而已, 不應有此設定) + SET v_data_para1 = CONCAT(',', v_crlf, ' "_', v_para_field, '": "${', v_ls_paras_field, '}"', v_crlf); + SET v_data_para2 = CONCAT(',', v_crlf, ' "requestAdaptor": "local_set_params(', CAST(v_ls_paras_no AS CHAR), ',api.data._', v_para_field, '); return { ...api, data: { ...api.data }};"', v_crlf); + END IF; + ELSE + IF IFNULL(v_para_field, '') <> '' THEN + SET v_new_para_field = CONCAT('@${', v_para_field, '}'); + END IF; + END IF; + + -- 新支援 button call sp 並傳參數 + IF LOCATE(',', v_related_menuid) > 0 THEN + IF IFNULL(v_icon, '') = '' THEN + SET v_icon = 'fab fa-angellist text-success'; + END IF; + + -- 取出 sp 及參數(目前做多允許 4 個參數) + SET p_uuid = UUID(); + CALL gp_split(p_uuid, v_related_menuid,','); + select col INTO v_sp_name from _split where guid = p_uuid and rowid = 1; + select col INTO v_para1 from _split where guid = p_uuid and rowid = 2; + select col INTO v_para2 from _split where guid = p_uuid and rowid = 3; + select col INTO v_para3 from _split where guid = p_uuid and rowid = 4; + select col INTO v_para4 from _split where guid = p_uuid and rowid = 5; + DELETE FROM _split WHERE guid = p_uuid; + + -- 要特殊控制 db, 目前先 hard code 2023-02-04 Michael + IF v_sp_name = 'zen_showsource' THEN + SET p_db = '${ls:wizard_db}'; + END IF; + + IF IFNULL(v_para1, '') = '' THEN SET v_para1 = ''; END IF; + IF IFNULL(v_para2, '') = '' THEN SET v_para2 = ''; END IF; + IF IFNULL(v_para3, '') = '' THEN SET v_para3 = ''; END IF; + IF IFNULL(v_para4, '') = '' THEN SET v_para4 = ''; END IF; + + IF v_para1 = 'token' THEN + SET v_para1 = CONCAT(' "token": "${ls:token}"', IF(v_para2 = '', '', ','), v_crlf); + IF v_para2 <> '' THEN + SET v_para2 = CONCAT(' "para02": "${', v_para2, '}"', IF(v_para3 = '', '', ','), v_crlf); + END IF; + IF v_para3 <> '' THEN + SET v_para3 = CONCAT(' "para03": "${', v_para3, '}"', IF(v_para4 = '', '', ','), v_crlf); + END IF; + IF v_para4 <> '' THEN + SET v_para4 = CONCAT(' "para04": "${', v_para4, '}"', v_crlf); + END IF; + ELSE + IF v_para1 <> '' THEN + SET v_para1 = CONCAT(' "para01": "${', v_para1, '}"', IF(v_para2 = '', '', ','), v_crlf); + END IF; + IF v_para2 <> '' THEN + SET v_para2 = CONCAT(' "para02": "${', v_para2, '}"', IF(v_para3 = '', '', ','), v_crlf); + END IF; + IF v_para3 <> '' THEN + SET v_para3 = CONCAT(' "para03": "${', v_para3, '}"', IF(v_para4 = '', '', ','), v_crlf); + END IF; + IF v_para4 <> '' THEN + SET v_para4 = CONCAT(' "para04": "${', v_para4, '}"', v_crlf); + END IF; + END IF; + + -- button & call sp + SET v_rets = CONCAT(v_rets, + '{', v_crlf, + ' "type": "button",', v_crlf, + ' "icon": "', v_icon, '",', v_crlf, + ' "actionType": "ajax",', v_crlf, + ' "tooltip": "', v_fcaption, '",', v_crlf, + ' "confirmText": "確定要執行本作業?",', v_crlf, -- 將本公告設為已讀 + ' "api": {', v_crlf, + ' "method": "post",', v_crlf, + ' "url": "', p_ip, '/xapi/v2/', p_db, '/', v_sp_name, '/1/",', v_crlf, + ' "data": {', v_crlf, + v_para1, v_para2, v_para3, v_para4, + ' },', v_crlf, + ' "dataType": "form"', v_crlf, + ' }', v_crlf, + ' }', v_comma, v_crlf); + + SET v_inow = v_inow + 1; + ELSE + /* + 此處目前總共有3種情況, 稍後繼續改 + 1.呼叫擴充子表單, 如 person call person_agent, 要傳 personid + 2.呼叫另一支程式, 如 會議記錄 call 協同工作單, 要傳 functiontag (來源單別) + 3.呼叫外部專案程式, 如行事曆 call FullCalendar, 傳參必須透過 local_set_params + 4.執行 sp, (在前一段程式專門處理了) + 5.其他(目前無) + + related_menuid 關聯表單代號 + para_field 傳參欄名 -> 欄位名稱前是否要加 _ , 主要是看是否為外部專案程式, 如果是呼叫外部程式, 才要加 _ , 且要在 data 區定義 + ls_paras_field 擴充參數名 + ls_paras_no 參數代碼 + + PS: 昨天晚上查了半天, 怎麼我產生的程式 ${ls:query_id} 都不見了, 後來才發現是因為 zen_showsource 這支 core sp 會在顯示 Code 時 replace + 資料庫中的 code 是 ok 的。所以這並不是問題, 一個問題是因為現在是利用 orm_api 的 para 8, 這個機制一般 ok, + 但是 basperson_agent 同時有 personid 和 agentid 時就有問題, 可能要改用 para 9/10 才行, Thinking + */ + SET v_rets = CONCAT(v_rets, + '{', v_crlf, + ' "type": "button",', v_crlf, + -- Inner 不須加 title, level 可以後續手動修改 + IF(p_button_type = 'U', + CONCAT(' "label": "', v_fcaption, '",', v_crlf, + ' "level": "success",', v_crlf), + ''), + ' "icon": "', v_icon, '",', v_crlf, + ' "actionType": "dialog",', v_crlf, + ' "tooltip": "', v_fcaption, '",', v_crlf, + ' "dialog": {', v_crlf, + ' "//title": "新增-', v_fcaption, '",', v_crlf, + ' "actions": [],', v_crlf, + ' "size": "full",', v_crlf, + ' "body": {', v_crlf, + ' "type": "service",', v_crlf, + ' "schemaApi": {', v_crlf, + ' "method": "post",', v_crlf, + ' "url": "', p_ip, '/xapi/v2/${ls:wizard_db}/zen_showsource/0/",', v_crlf, + ' "data": {', v_crlf, + ' "para01": "', v_related_menuid, '",', v_crlf, + ' "para02": "beta', v_new_para_field, '"', v_crlf, + v_data_para1, + ' },', v_crlf, + ' "dataType": "form"', v_crlf, + v_data_para2, + ' }', v_crlf, + ' }', v_crlf, + ' }', v_crlf, + ' }', v_comma, v_crlf); + + SET v_inow = v_inow + 1; + END IF; + END WHILE; + + DROP TEMPORARY TABLE IF EXISTS temp_jsondata; + + RETURN IFNULL(v_rets, ''); +END // + +DELIMITER ; \ No newline at end of file diff --git a/basecore/zen_get_keyvalue.txt b/basecore/zen_get_keyvalue.txt new file mode 100644 index 0000000..fdb6a79 --- /dev/null +++ b/basecore/zen_get_keyvalue.txt @@ -0,0 +1,87 @@ +DELIMITER // + +CREATE OR REPLACE FUNCTION zen_get_keyvalue( + p_tablename VARCHAR(100), + p_fieldname VARCHAR(20) +) +RETURNS TEXT +DETERMINISTIC +/* + Function : 改寫成 api 給 amis 呼叫時, 如果一個 Form 上有多個 select 是固定內容 + Description: 如上 + Build Date : 2022/02/16 + + Modify History + Item Who Date Modify Docs + ===M= ========== ========== ================================================ + 1 Michael 2022/02/16 Init +*/ +BEGIN + DECLARE v_cnt INT; + DECLARE v_crlf VARCHAR(2); + DECLARE v_comma VARCHAR(1); + DECLARE v_value VARCHAR(100); + DECLARE v_label VARCHAR(100); + DECLARE v_rets TEXT; + DECLARE v_imax INT; + DECLARE v_inow INT; + DECLARE v_rowid INT DEFAULT 1; + + -- 臨時表儲存 JSON 數據 + DROP TEMPORARY TABLE IF EXISTS temp_jsondata; + CREATE TEMPORARY TABLE temp_jsondata ( + rowid INT AUTO_INCREMENT PRIMARY KEY, + value VARCHAR(100), + label VARCHAR(100) + ); + + SET v_crlf = CONCAT(CHAR(13), CHAR(10)); + + -- 檢查是否有設定到 tablename + SELECT COUNT(*) INTO v_cnt FROM zen_keyvalue + WHERE tablename = p_tablename AND fieldname = p_fieldname; + + IF v_cnt > 0 THEN + INSERT INTO temp_jsondata (value, label) + SELECT keyid AS value, keyvalue AS label + FROM zen_keyvalue + WHERE tablename = p_tablename AND fieldname = p_fieldname; + ELSE + INSERT INTO temp_jsondata (value, label) + SELECT keyid AS value, keyvalue AS label + FROM zen_keyvalue + WHERE tablename = 'xxxx' AND fieldname = p_fieldname; + END IF; + + -- 回傳 options [] + SELECT COUNT(*) INTO v_imax FROM temp_jsondata; + SET v_inow = 1; + SET v_rets = ''; + SET v_comma = ','; + + WHILE v_inow <= v_imax DO + IF v_inow = v_imax THEN + SET v_comma = ''; + END IF; + + SELECT value, label INTO v_value, v_label + FROM temp_jsondata + WHERE rowid = v_inow; + + SET v_rets = CONCAT(v_rets, + ' {', v_crlf, + ' "label": "', v_label, '",', v_crlf, + ' "value": "', v_value, '"', v_crlf, + ' }', v_comma, v_crlf); + + SET v_inow = v_inow + 1; + END WHILE; + + SET v_rets = CONCAT('"options": [ ', v_rets, ' ],', v_crlf); + + DROP TEMPORARY TABLE IF EXISTS temp_jsondata; + + RETURN v_rets; +END // + +DELIMITER ; \ No newline at end of file diff --git a/basecore/zen_get_mapping.txt b/basecore/zen_get_mapping.txt new file mode 100644 index 0000000..5ad2687 --- /dev/null +++ b/basecore/zen_get_mapping.txt @@ -0,0 +1,81 @@ +DELIMITER // + +CREATE OR REPLACE FUNCTION zen_get_mapping( + p_tablename VARCHAR(100), + p_fieldname VARCHAR(20) +) +/* + Function : Rewrite as an API for AMIS to call. Display JSON content with mapping icons + Description: As above + Build Date : 2022/02/16 + + Modify History + Item Who Date Modify Docs + ==== ========== ========== ================================================ + 1 Michael 2022/02/16 Init +*/ +RETURNS TEXT +BEGIN + DECLARE v_cnt INT; + DECLARE v_crlf VARCHAR(2); + DECLARE v_comma VARCHAR(1); + DECLARE v_value VARCHAR(100); + DECLARE v_label VARCHAR(100); + DECLARE v_keydesc VARCHAR(100); + DECLARE v_rets TEXT; + DECLARE v_imax INT; + DECLARE v_inow INT; + + -- 创建临时表来存储JSON数据 + DROP TEMPORARY TABLE IF EXISTS temp_jsondata; + CREATE TEMPORARY TABLE temp_jsondata ( + value VARCHAR(100), + label VARCHAR(100), + keydesc VARCHAR(100), + rowid INT AUTO_INCREMENT PRIMARY KEY + ); + + SET v_crlf = CONCAT(CHAR(13), CHAR(10)); + + -- 检查是否有设置到 tablename + SELECT COUNT(*) INTO v_cnt FROM zen_keyvalue + WHERE tablename = p_tablename AND fieldname = p_fieldname; + + IF v_cnt > 0 THEN + INSERT INTO temp_jsondata (value, label, keydesc) + SELECT keyid AS value, keyvalue AS label, keydesc + FROM zen_keyvalue + WHERE tablename = p_tablename AND fieldname = p_fieldname; + ELSE + INSERT INTO temp_jsondata (value, label, keydesc) + SELECT keyid AS value, keyvalue AS label, keydesc + FROM zen_keyvalue + WHERE tablename = 'xxxx' AND fieldname = p_fieldname; + END IF; + + -- 返回 options [] + SELECT COUNT(*) INTO v_imax FROM temp_jsondata; + SET v_inow = 1; + SET v_rets = ''; + SET v_comma = ','; + + WHILE v_inow <= v_imax DO + IF v_inow = v_imax THEN + SET v_comma = ''; + END IF; + + SELECT value, label, keydesc INTO v_value, v_label, v_keydesc + FROM temp_jsondata WHERE rowid = v_inow; + + SET v_rets = CONCAT(v_rets, + -- ' "', v_value, '": "', v_label, '"', v_comma); + ' "', v_value, '": "', v_label, '"', v_comma); + SET v_inow = v_inow + 1; + END WHILE; + + SET v_rets = CONCAT('"map": { ', v_rets, ' },', v_crlf); + + RETURN v_rets; +END // + +DELIMITER ; diff --git a/basecore/zen_get_picker.txt b/basecore/zen_get_picker.txt new file mode 100644 index 0000000..da516de --- /dev/null +++ b/basecore/zen_get_picker.txt @@ -0,0 +1,51 @@ +DELIMITER // + +CREATE PROCEDURE zen_get_picker ( + IN functiontag VARCHAR(100), -- pickerId, basm501=product, basm610=customer + IN fieldname VARCHAR(100), -- return correct field name + IN formsize VARCHAR(10) -- form size 可以由此控制 +) +/* + 因為 picker 是統一的需求, 為了統一控管, 改為 service + schemaApi, 同時也可以大幅縮端程式碼 + 目前測試時有一個 issue 尚待處理, 原定義在 picker 內的 label 會因改為 service + schemaApi 而不顯示, 影響排版 + + 這樣的寫法可以執行, 但無法 update picker.name 傳參數會有問題 + { + "type": "service", + "schemaApi": "get:/pages/zen_picker_basm601.json" + }, + + 以下的寫法測試仍有問題(不會報錯, 但 picker 未顯示) + { + "type": "service", + "schemaApi": { + "method": "post", + "url": "http://127.0.0.1:5050/xapi/v2/zenWizard/zen_get_picker/3/", + "data": { + "para01": "basm61", + "para02": "para05", + "para03": "lg" + }, + "dataType": "form" + } + }, + + CALL zen_get_picker('basm601', 'para05'); +*/ +BEGIN + DECLARE picker TEXT; + DECLARE version VARCHAR(20); + + SET version = 'picker'; + + -- get and replace data + SELECT jsoncode INTO picker FROM zen_jsoncode WHERE functiontag = functiontag AND version = version; + SET picker = REPLACE(picker, '@fieldname@', fieldname); + SET picker = REPLACE(picker, '@formsize@', formsize); + + -- return ds + SELECT 0 AS code, 'OK' AS msg; + SELECT picker AS jsoncode; +END // + +DELIMITER ; diff --git a/basecore/zen_import_fields.txt b/basecore/zen_import_fields.txt new file mode 100644 index 0000000..c481dde --- /dev/null +++ b/basecore/zen_import_fields.txt @@ -0,0 +1,91 @@ +DELIMITER // + +CREATE OR REPLACE PROCEDURE zen_import_fields( + IN p_functiontag VARCHAR(100), + IN p_tablename VARCHAR(100) +) +/* + Function : 回傳指定 table 的 schema 並寫入 zen_fields + Description: + Build Date : 2021/08/14 + Modified : 2025/08/09 (轉換為 MariaDB 並加入自動寫入功能) + + Call Sample: + CALL zen_import_fields('abc01','clinic'); + + Modify History + Item Who Date Modify Docs + ==== ========== ========== ================================================ + 1 Michael + 2 Assistant 2025/08/09 轉換為 MariaDB 並加入自動寫入功能 +*/ +BEGIN + DECLARE v_count INT; + + -- 檢查 zen_fields 表中是否已存在該 functiontag 的記錄 + SELECT COUNT(*) INTO v_count + FROM zen_fields + WHERE functiontag = p_functiontag; + + -- 創建臨時表存儲表結構 + DROP TEMPORARY TABLE IF EXISTS temp_schema; + CREATE TEMPORARY TABLE temp_schema ( + tablename VARCHAR(60), + fieldname VARCHAR(60), + seqno INT, + fieldobject VARCHAR(20), + fieldlength INT, + fielddefault VARCHAR(200), + fieldchecknull VARCHAR(10), + fieldcn NVARCHAR(60) + ); + + -- 從 information_schema 讀取表結構 + INSERT INTO temp_schema + SELECT + p_tablename AS tablename, + COLUMN_NAME AS fieldname, + ORDINAL_POSITION AS seqno, + DATA_TYPE AS fieldobject, + CHARACTER_MAXIMUM_LENGTH AS fieldlength, + COLUMN_DEFAULT AS fielddefault, + IF(IS_NULLABLE = 'YES', 'Y', 'N') AS fieldchecknull, + COLUMN_COMMENT AS fieldcn + FROM information_schema.COLUMNS + WHERE TABLE_NAME = p_tablename + AND TABLE_SCHEMA = DATABASE() + ORDER BY ORDINAL_POSITION; + + -- 處理空值 + UPDATE temp_schema SET fieldcn = '' WHERE fieldcn IS NULL; + + -- 如果 zen_fields 中沒有該 functiontag 的記錄,則插入新記錄 + IF v_count = 0 THEN + INSERT INTO zen_fields ( + functiontag, seqno, tablename, fieldname, fieldcn, fielden, fieldlength, + fieldwidth, fieldobject, fielddefault, fieldchecknull, fieldblock, + fieldds, fieldsh, fieldfm, fieldro, cellno, cellx, celly, cellline, datatype + ) + SELECT + p_functiontag, seqno, tablename, fieldname, fieldcn, '' AS fielden, fieldlength, + 120 AS fieldwidth, fieldobject, fielddefault, fieldchecknull, 0 AS fieldblock, + CASE WHEN seqno <= 6 THEN 'Y' ELSE 'N' END AS fieldds, 'Y' AS fieldsh, + '' AS fieldfm, 'N' AS fieldro, 0 AS cellno, 1 AS cellx, 1 AS celly, 1 AS cellline, fieldobject + FROM temp_schema; + END IF; + + -- 返回結果 + SELECT 0 AS code, 'ok' AS msg; + + SELECT + p_functiontag AS functiontag, seqno, tablename, fieldname, fieldcn, '' AS fielden, fieldlength, + 120 AS fieldwidth, fieldobject, fielddefault, fieldchecknull, 0 AS fieldblock, + CASE WHEN seqno <= 6 THEN 'Y' ELSE 'N' END AS fieldds, 'Y' AS fieldsh, + '' AS fieldfm, 'N' AS fieldro, 0 AS cellno, 1 AS cellx, 1 AS celly, 1 AS cellline + FROM temp_schema; + + DROP TEMPORARY TABLE IF EXISTS temp_schema; + +END // + +DELIMITER ; \ No newline at end of file diff --git a/basecore/zen_null.txt b/basecore/zen_null.txt new file mode 100644 index 0000000..17fd06d --- /dev/null +++ b/basecore/zen_null.txt @@ -0,0 +1,18 @@ +DELIMITER // + +CREATE OR REPLACE PROCEDURE zen_null() +/* + 為了執行 js 跑一段假的 api +*/ +BEGIN + DECLARE code INT; + DECLARE msg VARCHAR(255); + + -- Return a fake response + SELECT 0 AS code, 'OK' AS msg; + + -- Return an empty result set + SELECT * FROM sys_users WHERE 1 = 0; +END // + +DELIMITER ; diff --git a/basecore/zen_parse_sp.txt b/basecore/zen_parse_sp.txt new file mode 100644 index 0000000..f9ace2b --- /dev/null +++ b/basecore/zen_parse_sp.txt @@ -0,0 +1,124 @@ +DELIMITER // + +CREATE PROCEDURE zen_parse_sp( + IN actiontype VARCHAR(10), -- fields/parain + IN sp_name VARCHAR(200), + IN functiontag VARCHAR(200) +) +/* + function : 想辦法取得 sp 最後回傳的欄位名稱列表 + description: 有跨 db 的語法, 記得測試完後要移除 + build date : 2021/12/02 + + call sample: + CALL zen_parse_sp('gexrpt_opor02'); + + modify history + item who date modify docs + ==== ========== ========== ================================================ + 1 michael 2021/12/02 新增 +*/ +BEGIN + DECLARE sql_text TEXT; + DECLARE data_text TEXT; + DECLARE pos INT; + DECLARE ret2_col VARCHAR(100); + DECLARE ret2_fieldobject VARCHAR(100); + DECLARE ret2_related_provider VARCHAR(100); + DECLARE ret2_default_value VARCHAR(100); + DECLARE ret2_celly SMALLINT; + DECLARE ret2_seqno INT; + DECLARE ret2_rowid INT; + + SELECT text INTO sql_text + FROM information_schema.routines + WHERE routine_name = sp_name AND routine_type = 'PROCEDURE'; + + -- 回傳的欄位 + IF actiontype = 'fields' THEN + SELECT 0 AS code, 'ok' AS msg; + + CREATE TEMPORARY TABLE ret2 AS + SELECT + functiontag, + column_name AS fieldname, + column_name AS fieldcn, + CASE WHEN LOCATE('date', data_type) > 0 THEN 'static-date' ELSE 'static' END AS fieldobject, + ordinal_position AS seqno + FROM information_schema.columns + WHERE table_schema = DATABASE() AND table_name = sp_name; + + SELECT * FROM ret2; + + -- 傳入的參數 + ELSEIF actiontype = 'parain' THEN + -- 取得 () 內的資料 + SET pos = LOCATE('/*', sql_text); + IF pos > 0 THEN + SET sql_text = SUBSTRING(sql_text, 1, pos - 5); + END IF; + + SET pos = LOCATE('as', sql_text); + IF pos > 0 THEN + SET sql_text = SUBSTRING(sql_text, 1, pos - 5); + END IF; + + SET pos = LOCATE('(', sql_text); + SET data_text = SUBSTRING(sql_text, pos + 1, LENGTH(sql_text)); + + CREATE TEMPORARY TABLE ret2 ( + col VARCHAR(100), + fieldobject VARCHAR(100), + related_provider VARCHAR(100), + default_value VARCHAR(100), + celly SMALLINT, + rowid INT AUTO_INCREMENT, + PRIMARY KEY (rowid) + ); + + -- 開始分析(, 分隔) + INSERT INTO ret2 (col) + SELECT col FROM gf_split(data_text, ','); + + UPDATE ret2 SET col = SUBSTRING(col, LOCATE('@', col), LENGTH(col)); + UPDATE ret2 SET col = SUBSTRING(col, 1, LOCATE(' ', col) - 1); + + -- 想辦法給定一些 default + UPDATE ret2 SET fieldobject = 'input-text', default_value = '*'; + + UPDATE ret2 SET + fieldobject = 'input-date', + default_value = 'today' + WHERE LOCATE('date', col) > 0; + + UPDATE ret2 SET + fieldobject = 'picker', + related_provider = 'basm61' + WHERE LOCATE('cust', col) > 0; + + UPDATE ret2 SET + fieldobject = 'picker', + related_provider = 'basm51' + WHERE LOCATE('product', col) > 0; + + UPDATE ret2 SET + fieldobject = 'picker', + related_provider = 'basm67' + WHERE LOCATE('person', col) > 0; + + -- 如果第一個 para 是 token + SELECT COUNT(*) INTO pos FROM ret2 WHERE rowid = 1 AND LOCATE('token', col) > 0; + IF pos > 0 THEN + UPDATE ret2 SET default_value = '${ls:token}' WHERE LOCATE('token', col) > 0; + END IF; + + SELECT 0 AS code, 'ok' AS msg; + + SELECT functiontag, col AS fcaption, 1 AS celly, rowid - pos AS seqno, fieldobject, related_provider, default_value + FROM ret2; + + END IF; + +END // + +DELIMITER ; diff --git a/basecore/zen_picker.txt b/basecore/zen_picker.txt new file mode 100644 index 0000000..9f99253 --- /dev/null +++ b/basecore/zen_picker.txt @@ -0,0 +1,272 @@ +DELIMITER // + +CREATE OR REPLACE FUNCTION zen_picker( + p_picker_tag VARCHAR(100), -- 傳入 popup 的資料來源 functiontag + p_fieldname NVARCHAR(100), -- 呼叫端的欄位 + p_fieldcname NVARCHAR(100), -- 呼叫端的欄位名稱 + p_actiontype CHAR(2), -- (R)ead/(E)dit/(Q)uery + p_ip VARCHAR(100), -- 'https://api.gex.com.tw:5443' + p_db VARCHAR(100), -- 'zenBusiness' + p_source_tag VARCHAR(100) -- 原呼叫功能(常需要參考原 tag 的設定) +) +RETURNS TEXT +/* + function : amis Wizard 中負責產生 picker 相關程式片段的 udf + description: + build date : 2021/10/10 + + modify history + item who date modify docs + ==== ========== ========== ================================================ + 1 michael 2021/10/10 新增 + 2 Michael 2023-02-01 為了更加彈性, @ip 及 @db 這2個欄位改傳入 ${ls:xxxx}, 測試可行(程式要調整前端呼叫的程式) + 3 Michael 2023-09-01 新增 picker 可以傳回多欄位的設定 + 4 Michael 2023-09-25 依 amis 建議 keywords 的變數不要用 - + 5 Michael 2024-01-23 @visibleOn 新增欄位, 配合週期性行事曆, 會設定條件顯示/不顯示本元件 + 6 Michael 2024-03-03 修改 labelField 的顯示判斷 +*/ +BEGIN + DECLARE v_ret TEXT; + DECLARE v_dd_table VARCHAR(100); + DECLARE v_dd_pk VARCHAR(100); + DECLARE v_dd_functionname VARCHAR(100); + DECLARE v_dd_name VARCHAR(100); + DECLARE v_labelField VARCHAR(100); + DECLARE v_fieldchecknull VARCHAR(10); -- New + DECLARE v_dd_fieldname VARCHAR(100); + DECLARE v_dd_Fieldcn NVARCHAR(100); + DECLARE v_dd_FieldWidth VARCHAR(10); + DECLARE v_dd_field_object VARCHAR(100); + DECLARE v_dd_field_display_name CHAR(1); + DECLARE v_query_filter VARCHAR(200); + DECLARE v_query_grid TEXT; + DECLARE v_date_fmt VARCHAR(100); + DECLARE v_obj VARCHAR(100); + DECLARE v_FieldWidth VARCHAR(10); + DECLARE v_dvalue VARCHAR(100); + DECLARE v_q_filter VARCHAR(100); + DECLARE v_q_inputClassName VARCHAR(100); + DECLARE v_visibleOn VARCHAR(100); + DECLARE v_vKey VARCHAR(100); + DECLARE v_vVal VARCHAR(100); + DECLARE v_crlf VARCHAR(2); + DECLARE v_imax INT; + DECLARE v_inow INT; + DECLARE v_ipos INT; + + -- 與原呼叫端相關(視情況新增) + DECLARE v_fielddefault NVARCHAR(100); -- 新增的預設值(若無則空) + DECLARE v_iscolumnmatch CHAR(1); -- 是否傳回多欄位 + DECLARE v_dd_fieldblock INT; + + -- 臨時表儲存 JSON 數據 + DROP TEMPORARY TABLE IF EXISTS temp_jsondata_picker; + CREATE TEMPORARY TABLE temp_jsondata_picker ( + rowid INT AUTO_INCREMENT PRIMARY KEY, + fieldname VARCHAR(100), + Fieldcn NVARCHAR(100), + fieldobject VARCHAR(100), + field_display_name CHAR(1), + FieldWidth VARCHAR(10) + ); + + -- 取得欄位設定, 多取是否必填 + -- M-D 表單惡裡可能會取到 2筆資料, 要防錯 20250906 (取表頭) + SELECT fielddefault, iscolumnmatch, fieldblock, FieldWidth, visibleOn, fieldchecknull + INTO v_fielddefault, v_iscolumnmatch, v_dd_fieldblock, v_FieldWidth, v_visibleOn, v_fieldchecknull + FROM zen_fields + WHERE functiontag = p_source_tag AND fieldname = p_fieldname LIMIT 1; + -- and fieldblock < 90; + + SET v_crlf = CONCAT(CHAR(13), CHAR(10)); + + -- 防錯(Query) + IF p_ip = '' THEN SET p_ip = '${ls:base_ip}'; END IF; + IF p_db = '' THEN SET p_db = '${ls:base_db}'; END IF; + + -- 取得資料 + SELECT maintable, mainkey, functionname + INTO v_dd_table, v_dd_pk, v_dd_functionname + FROM zen_function + WHERE functiontag = p_picker_tag; + + -- 插入資料到臨時表 + INSERT INTO temp_jsondata_picker (fieldname, Fieldcn, fieldobject, field_display_name, FieldWidth) + SELECT fieldname, Fieldcn, fieldobject, field_display_name, CAST(FieldWidth AS CHAR) + FROM zen_fields + WHERE functiontag = p_picker_tag AND fieldds = 'Y' + ORDER BY celly, cellx; + + -- 計算 _group (body-group) 排列 + SELECT MAX(rowid) INTO v_imax FROM temp_jsondata_picker; + SELECT MIN(rowid) INTO v_inow FROM temp_jsondata_picker; + -- SET v_inow = 1; + SET v_query_filter = ''; + SET v_query_grid = ''; + + WHILE v_inow <= v_imax DO + SELECT fieldname, Fieldcn, fieldobject, field_display_name, FieldWidth + INTO v_dd_fieldname, v_dd_Fieldcn, v_dd_field_object, v_dd_field_display_name, v_dd_FieldWidth + FROM temp_jsondata_picker + WHERE rowid = v_inow; + + IF v_dd_field_display_name = 'Y' THEN + SET v_labelField = v_dd_fieldname; + END IF; + + IF v_dd_field_object = 'input-text' THEN + SET v_query_filter = CONCAT(v_query_filter, v_dd_fieldname, ','); + END IF; + + SET v_obj = 'text'; + SET v_date_fmt = ''; + + IF v_dd_field_object = 'input-date' THEN + SET v_obj = 'static-date'; + SET v_date_fmt = CONCAT(' "format": "YYYY-MM-DD",', v_crlf); + END IF; + + SET v_query_grid = CONCAT(v_query_grid, + ' {', v_crlf, + ' "type": "', v_obj, '",', v_crlf, + ' "name": "', v_dd_fieldname, '",', v_crlf, + ' "label": "', v_dd_Fieldcn, '",', v_crlf, + v_date_fmt, + ' "toggled": true', v_crlf, + ' },'); + + SET v_inow = v_inow + 1; + END WHILE; + + IF v_query_filter <> '' THEN + SET v_query_filter = SUBSTRING(v_query_filter, 1, CHAR_LENGTH(v_query_filter) - 1); + END IF; + + IF v_query_grid <> '' THEN + SET v_query_grid = CONCAT(SUBSTRING(v_query_grid, 1, CHAR_LENGTH(v_query_grid) - 1), v_crlf); + END IF; + + -- Query 有2處要修改 + IF p_actiontype = 'Q' THEN + SET v_dvalue = '*'; + SET v_q_filter = ''; + SET v_q_inputClassName = ' "inputClassName": "w-60",'; + ELSE + -- 新增也可以給預設值 2023/1/14 Michael + IF v_fielddefault <> '' THEN + IF SUBSTRING(v_fielddefault, 1, 3) = 'ls:' THEN + SET v_fielddefault = CONCAT('${', v_fielddefault, '}'); + END IF; + END IF; + + SET v_dvalue = v_fielddefault; + SET v_q_filter = ''; + SET v_q_inputClassName = ''; + END IF; + + -- 動態顯式否 + IF IFNULL(v_visibleOn, '') <> '' THEN + SET v_ipos = LOCATE(',', v_visibleOn); + IF v_ipos > 0 THEN + SET v_vKey = SUBSTRING(v_visibleOn, 1, v_ipos - 1); + SET v_vVal = SUBSTRING(v_visibleOn, v_ipos + 1, 100); + SET v_q_inputClassName = CONCAT(' "visibleOn": "this.', v_vKey, ' == \\"', v_vVal, '\\"",'); + END IF; + END IF; + + -- 加入是否必填 + IF (IFNULL(v_fieldchecknull, '') = 'Y' or IFNULL(v_fieldchecknull, '') = 'A') THEN + SET v_q_inputClassName = CONCAT(' "required": true,', v_crlf, v_q_inputClassName); + END IF; + + IF SUBSTRING(p_actiontype, 1, 1) = 'E' OR p_actiontype = 'Q' THEN + SET v_ret = CONCAT('{', v_crlf, + ' "type": "picker",', v_crlf, + ' "name": "', p_fieldname, '",', v_crlf, + ' "joinValues": ', IF(v_iscolumnmatch = 'Y', 'false', 'true'), ',', v_crlf, + ' "valueField": "', v_dd_pk, '",', v_crlf, + ' "labelField": "', + IF((v_dd_fieldblock >= 90 AND v_iscolumnmatch = 'Y') OR IFNULL(v_labelField, '') = '', + v_dd_pk, v_labelField), '",', v_crlf, + IF(v_dd_fieldblock >= 90 OR IFNULL(v_labelField, '') = '', + CONCAT(' "width": ', v_FieldWidth, ',', v_crlf), ''), + ' "label": "', p_fieldcname, '",', v_crlf, + v_q_inputClassName, v_crlf, + ' "source": {', v_crlf, + ' "method": "post",', v_crlf, + ' "url": "', p_ip, '/xapi/v2/', p_db, '/orm_api/3/",', v_crlf, + ' "data": {', v_crlf, + ' "token": "${ls:token}",', v_crlf, + ' "page": "${page}",', v_crlf, + ' "perPage": "${perPage}",', v_crlf, + ' "keywords": "${', p_fieldname, '_keywords}",', v_crlf, + ' "_$_tableName": "', v_dd_table, '",', v_crlf, + ' "_$_pk": "', v_dd_pk, '",', v_crlf, + ' "_$_action": "P",', v_crlf, + ' "_$_query_filter": "1^10^', v_dd_pk, '^*^^^', v_query_filter, v_q_filter, '"', v_crlf, + ' },', v_crlf, + ' "dataType": "form"', v_crlf, + ' },', v_crlf, + ' "size": "', IF(v_imax > 6, 'lg', 'md'), '",', v_crlf, + ' "value": "', v_dvalue, '",', v_crlf, + ' "multiple": false,', v_crlf, + ' "pickerSchema": {', v_crlf, + ' "mode": "table",', v_crlf, + ' "tableClassName": "myGridHeader_a",', v_crlf, + ' "title": "', v_dd_functionname, '",', v_crlf, + ' "name": "', v_dd_table, '_', p_fieldname, '",', v_crlf, + ' "headerToolbar": {', v_crlf, + ' "wrapWithPanel": false,', v_crlf, + ' "type": "form",', v_crlf, + ' "className": "text-right",', v_crlf, + ' "target": "', v_dd_table, '_', p_fieldname, '",', v_crlf, + ' "mode": "inline",', v_crlf, + ' "body": [', v_crlf, + ' {', v_crlf, + ' "type": "input-text",', v_crlf, + ' "name": "', p_fieldname, '_keywords",', v_crlf, + ' "addOn": {', v_crlf, + ' "type": "submit",', v_crlf, + ' "label": "查詢",', v_crlf, + ' "tooltip": "輸入 * 可以查詢全部資料",', v_crlf, + ' "level": "primary",', v_crlf, + ' "icon": "fa fa-search pull-left"', v_crlf, + ' }', v_crlf, + ' }', v_crlf, + ' ]', v_crlf, + ' },', v_crlf, + ' "columns": [', v_crlf, + v_query_grid, + ' ]', v_crlf, + ' }', v_crlf, + '}', v_crlf); + ELSE -- for View + SET v_ret = CONCAT('{', v_crlf, + ' "type": "picker",', v_crlf, + ' "name": "', p_fieldname, '",', v_crlf, + ' "disabled": true,', v_crlf, + ' "joinValues": true,', v_crlf, + ' "valueField": "', v_dd_pk, '",', v_crlf, + ' "labelField": "', IFNULL(v_labelField, ''), '",', v_crlf, + ' "label": "', p_fieldcname, '",', v_crlf, + ' "source": {', v_crlf, + ' "method": "post",', v_crlf, + ' "url": "', p_ip, '/xapi/v2/', p_db, '/orm_api/3/",', v_crlf, + ' "data": {', v_crlf, + ' "token": "${ls:token}",', v_crlf, + ' "_$_tableName": "', v_dd_table, '",', v_crlf, + ' "_$_pk": "', v_dd_pk, '",', v_crlf, + ' "_$_action": "P",', v_crlf, + ' "_$_query_filter": "1^10^', v_dd_pk, '^*^^^', v_query_filter, '^${', p_fieldname, '}"', v_crlf, + ' },', v_crlf, + ' "dataType": "form"', v_crlf, + ' }', v_crlf, + '}', v_crlf); + END IF; + + DROP TEMPORARY TABLE IF EXISTS temp_jsondata_picker; + + RETURN v_ret; +END // + +DELIMITER ; \ No newline at end of file diff --git a/basecore/zen_read_schema.txt b/basecore/zen_read_schema.txt new file mode 100644 index 0000000..b857294 --- /dev/null +++ b/basecore/zen_read_schema.txt @@ -0,0 +1,38 @@ +DELIMITER // + +CREATE OR REPLACE PROCEDURE zen_read_schema ( + IN p_tablename VARCHAR(100) +) +/* + 功能:讀取資料表結構資訊 + 範例:CALL zen_read_schema('pmsproject_class'); +*/ +BEGIN + SELECT + t.TABLE_NAME AS '表格名稱', + c.COLUMN_NAME AS '欄位名稱', + c.ORDINAL_POSITION AS '序號', + c.DATA_TYPE AS '資料型別', + IFNULL(c.CHARACTER_MAXIMUM_LENGTH, '') AS '長度', + '' AS '預設值', + CASE WHEN c.IS_NULLABLE = 'YES' THEN 'N' ELSE 'Y' END AS '是否允許空值', + IFNULL( + (SELECT COLUMN_COMMENT + FROM INFORMATION_SCHEMA.COLUMNS + WHERE TABLE_SCHEMA = t.TABLE_SCHEMA + AND TABLE_NAME = t.TABLE_NAME + AND COLUMN_NAME = c.COLUMN_NAME), + '' + ) AS '欄位描述' + FROM + INFORMATION_SCHEMA.TABLES t + LEFT JOIN INFORMATION_SCHEMA.COLUMNS c ON t.TABLE_NAME = c.TABLE_NAME AND t.TABLE_SCHEMA = c.TABLE_SCHEMA + WHERE + t.TABLE_TYPE = 'BASE TABLE' + AND t.TABLE_NAME = p_tablename + ORDER BY + t.TABLE_NAME, + c.ORDINAL_POSITION; +END// + +DELIMITER ; \ No newline at end of file diff --git a/basecore/zen_showsource.txt b/basecore/zen_showsource.txt new file mode 100644 index 0000000..d7f8d14 --- /dev/null +++ b/basecore/zen_showsource.txt @@ -0,0 +1,111 @@ +DELIMITER // + +CREATE OR REPLACE PROCEDURE zen_showsource ( + IN p_functiontag VARCHAR(100), + IN p_version VARCHAR(100), + IN p_ip varchar(100) +) +/* + function : 配合 amis 的 Service 元件, 取回 jsoncode, 動態產生程式的核心程式 + description: 開啟表單時通常會有預設條件, 這是一個很接近 hard-code 的機制, 但是因為 amis 限制太多, 只好硬開洞解決 + 1.原程式的 crud 若有 ${ls:query_id} ==> 固定變數設定(如下) + "_$_query_filter": "1^10^functiontag,celly,seqno^*^^^functiontag,report_type,report_orderby^${ls:query_id}" + 2.sp 的 @version 內容如果有傳入 @, 那 @ 後的內容就是要 replace 的內容 + 3.就把 ${ls:query_id} replace 掉, 用這種方式解決動態載入程式, 並能限制資料內容 + 4.目前是針對 zen12(如上設定), 呼叫 zen14 先測試使用, 如果沒問題可以考慮變成標準機制 + + 如果 @version 內容中沒有 @, 那就是一般程式, @_W_ 表示是為可編輯 Source 狀態 + build date : 2021/10/17 + + call sample: + CALL zen_showsource('zen14','beta@crmr02','https://api.gex.com.tw:5443') + + modify history + item who date modify docs + ==== ========== ========== ================================================ + 1 michael 2021-10-17 新增 + 2 Michael 2021-10-18 amis 的 crud grid 傳入的 id 似乎是前一筆, 這個 bug 已經有人提, 等改版(已修正) + 3 Michael 2022-02-05 加入防錯 + 4 Michael 2022-07-14 加入 IP Router 新機制(仍維持向上相容) + 5 Michael 2022-11-26 加入例外機制, bpmq11, q12 + 6 Michael 2023-01-25 新增 @values=_W_ 的判斷, 非 _W_ 為 Read Only, 只有在 Source 編輯狀態下, 才會傳入 _W_ + 7 Michael 2023-02-01 為了更加彈性, @ip 這個欄位改傳入 ${ls:base_ip} + 8 Michael 2023-04-04 改依參數檔設定的程式版本別 + 9 Michael 2023-05-20 size=full, 改為 size=xl, 因 amis 3.0 改版 + 10 Michael 2024-02-12 重構程式後, 重新想清楚邏輯後調整 code + 11 Michael 2024/03/06 擴充 json4 及 json5 2個欄位 +*/ +BEGIN + -- @version 最終會是版本別, 目前應該只會是 beta 或 prod + -- @value 則是表單傳值, 要限制開窗表單的資料內容, 若無, 應該要空白 + DECLARE v_version_org VARCHAR(100); + DECLARE v_values VARCHAR(100); + DECLARE v_pvalue VARCHAR(100); + DECLARE v_ipos SMALLINT; + DECLARE v_rets LONGTEXT; + DECLARE v_isNew INT; + DECLARE v_final_version VARCHAR(100); + + /* + 傳入時 @version 可能會有下列內容 + 1.只要含 _W_ 就表示是編輯 source, 直接顯示原內容, 不要有任何 replace + 2.{ls:query_id} + 3.beta@A001 + */ + SET v_version_org = p_version; + SET v_values = ''; + SET v_ipos = INSTR(p_version, '@'); + SET v_final_version = IFNULL(p_version, 'beta'); + + IF v_ipos > 0 THEN + -- _W_: Writeables(編輯 Source Code 的狀態) + SET v_values = SUBSTRING(p_version, v_ipos+1); + SET v_final_version = SUBSTRING(p_version, 1, v_ipos-1); + END IF; + + -- 依設定的程式版本別設定變數 2023/04/04, @version 一定要有值 + IF (SELECT COUNT(*) FROM information_schema.TABLES + WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'sys_parameter') > 0 THEN + SELECT pvalue INTO v_pvalue FROM sys_parameter + WHERE systemid = 'base' AND pid = 'ver_type' LIMIT 1; + + IF v_pvalue IS NOT NULL AND v_pvalue <> '' THEN + SET v_final_version = v_pvalue; + END IF; + END IF; + + -- 取得 JSON 代碼(擴充欄位) + -- SELECT CONCAT(IFNULL(jsoncode,''), IFNULL(jsoncode2,''), IFNULL(jsoncode3,''), + -- IFNULL(jsoncode4,''), IFNULL(jsoncode5,'')) INTO v_rets + + SELECT jsoncode INTO v_rets + FROM zen_jsoncode + WHERE functiontag = p_functiontag AND version = v_final_version; + + -- 只要有 _W_ 就表示不動 code, 完全顯示原本的內容 + IF INSTR(v_version_org, '_W_') <= 0 THEN + -- 主要的核心程式, 替換掉 ls 的內容 + IF v_values <> '' THEN + SET v_rets = REPLACE(v_rets, '${ls:query_id}', v_values); + END IF; + + /* + 這個地方的原寫法是錯的, 本意是當 localStorage 如果未設定值, 執行時會報錯 + 但是會造成只要先讀再寫, ${ls:query_id} 就會被從 json 設定(source code) 中移除, 那就會造成這個設定不見了 + 正確的作法是要確保 ls 一定會在被呼叫前清除, 再傳入 ls 當作參數 + Michael 2023/1/25 + */ + -- 防錯, 若有多餘的設定要防錯 2022-2-5, 加上除外機制 + IF INSTR(v_rets, '${ls:query_id}') > 0 AND (p_functiontag NOT IN ('bpmq11','bpmq12')) THEN + SET v_rets = REPLACE(v_rets, '${ls:query_id}', ''); + END IF; + ELSE + SET v_rets = REPLACE(v_rets, '_W_', ''); + END IF; + + -- 返回結果 + SELECT 0 AS code, 'OK' AS msg; + SELECT v_rets AS jsoncode; +END// + +DELIMITER ; \ No newline at end of file diff --git a/basecore/zen_tri_json_log.txt b/basecore/zen_tri_json_log.txt new file mode 100644 index 0000000..100b413 --- /dev/null +++ b/basecore/zen_tri_json_log.txt @@ -0,0 +1,25 @@ +DELIMITER // + +CREATE TRIGGER zen_tri_json_log +AFTER UPDATE ON zen_jsoncode +FOR EACH ROW +BEGIN + DECLARE v_cnt INT; + + -- 當 json code 被修改, 就記錄到 log + IF OLD.jsoncode <> NEW.jsoncode OR OLD.jsoncode2 <> NEW.jsoncode2 OR OLD.jsoncode3 <> NEW.jsoncode3 THEN + INSERT INTO zen_jsoncode_log (log_date, functiontag, version, jsoncode, jsoncode2, jsoncode3) + VALUES (NOW(), OLD.functiontag, OLD.version, OLD.jsoncode, OLD.jsoncode2, OLD.jsoncode3); + END IF; +END// + +CREATE TRIGGER zen_tri_json_log_delete +AFTER DELETE ON zen_jsoncode +FOR EACH ROW +BEGIN + -- 當記錄被刪除時記錄到 log + INSERT INTO zen_jsoncode_log (log_date, functiontag, version, jsoncode, jsoncode2, jsoncode3) + VALUES (NOW(), OLD.functiontag, OLD.version, OLD.jsoncode, OLD.jsoncode2, OLD.jsoncode3); +END// + +DELIMITER ; \ No newline at end of file diff --git a/basecore/zen_updatesource.txt b/basecore/zen_updatesource.txt new file mode 100644 index 0000000..8ff802b --- /dev/null +++ b/basecore/zen_updatesource.txt @@ -0,0 +1,63 @@ +DELIMITER // + +CREATE OR REPLACE PROCEDURE zen_updatesource ( + IN p_functiontag VARCHAR(100), + IN p_version VARCHAR(100), + IN p_jsoncode MEDIUMTEXT +) +/* + function : 回寫 json code 的內容(前端有修改傳入) + description: + build date : 2021/10/17 + + call sample: + CALL zen_updatesource('abc01','beta','json-code') + + modify history + item who date modify docs + ==== ========== ========== ================================================ + 1 michael 2021-10-17 新增 + 2 Michael 2023-07-09 新增根據 sys_parameter 的 ver_type 判斷版本 + 3 Michael 2024/03/06 擴充 json4 及 json5 2個欄位 +*/ +BEGIN + DECLARE v_zcode MEDIUMTEXT; + DECLARE v_pvalue VARCHAR(100); + DECLARE v_cnt INT; + DECLARE v_final_version VARCHAR(100) DEFAULT IFNULL(p_version, 'beta'); + + -- 依設定的程式版本別設定變數 2023/07/09 + -- 檢查 sys_parameter 表是否存在 + IF (SELECT COUNT(*) FROM information_schema.TABLES WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'sys_parameter') > 0 THEN + SELECT pvalue INTO v_pvalue FROM sys_parameter WHERE systemid = 'base' AND pid = 'ver_type' LIMIT 1; + IF v_pvalue IS NOT NULL AND v_pvalue <> '' THEN + SET v_final_version = v_pvalue; + END IF; + END IF; + + SET v_zcode = p_jsoncode; + + -- 去除編輯用的特殊字串 2024-02-13 + IF INSTR(v_zcode, '_W_') > 0 THEN + SET v_zcode = REPLACE(v_zcode, '_W_', ''); + END IF; + + -- 檢查記錄是否存在 + SELECT COUNT(*) INTO v_cnt FROM zen_jsoncode WHERE functiontag = p_functiontag AND version = v_final_version; + + -- 如果不存在就新增,否則更新 + -- SET v_zcode = REPLACE(v_zcode, '\n', ''); + IF v_cnt <= 0 THEN + INSERT INTO zen_jsoncode (functiontag, version, jsoncode) + VALUES (p_functiontag, v_final_version, v_zcode); + ELSE + UPDATE zen_jsoncode + SET jsoncode = v_zcode + WHERE functiontag = p_functiontag AND version = v_final_version; + END IF; + + -- 回傳成功結果 + SELECT 0 AS code, 'OK' AS msg; +END // + +DELIMITER ; \ No newline at end of file diff --git a/permission/api_log.txt b/permission/api_log.txt new file mode 100644 index 0000000..a2779f6 --- /dev/null +++ b/permission/api_log.txt @@ -0,0 +1,30 @@ +DELIMITER // + +CREATE OR REPLACE PROCEDURE api_log( + IN p_token VARCHAR(100), + IN p_cont TEXT +) +/* + Function : server.js 呼叫使用, 主要是將執行過的 api 都記錄到 log 中 + Description: + Build Date : 2023-12-10 + + Modify History + Item Who Date Modify Docs + ==== ========== ========== ================================================ + 1 Michael 2023-12-10 改寫為 MySQL 版 + +*/ +BEGIN + DECLARE v_userid VARCHAR(20); + + -- 根據傳入的 token 取得 userid + SELECT userid INTO v_userid FROM sys_users WHERE token = p_token; + + -- 新增一筆 api log record (移到 server.js 的共用程式處理較適合) + INSERT INTO sys_apilog (calldate, calluser, api_content) VALUES (NOW(), v_userid, p_cont); + + -- 獨立執行的存儲過程不需要回傳值 +END // + +DELIMITER ; diff --git a/permission/checklogin.txt b/permission/checklogin.txt new file mode 100644 index 0000000..de0027f --- /dev/null +++ b/permission/checklogin.txt @@ -0,0 +1,99 @@ +DELIMITER // + +CREATE OR REPLACE PROCEDURE checklogin( + IN p_token VARCHAR(100), + IN p_userid VARCHAR(100), + IN p_pwd VARCHAR(200), + IN p_logintype VARCHAR(10) -- 由 app 或 web 或其他來源登入 +) +/* + Function : 判斷能否 Login(前端登入時呼叫), 如果可以就傳回 Token + Description: 判斷 Token 是否過期, 若未過期, 傳回 0, 已過期傳回 9, 密碼錯誤傳回 4 + Build Date : 2018/03/02 + + Modify History + Item Who Date Modify Docs + ==== ========== ========== ================================================ + 1 Michael 2018/01/08 開始改寫為 MySQL 版 + 2 Michael 2018-03-20 新增 isstop 帳號停用的判斷 + 3 Michael 2018-03-26 回傳值改為 2個 dataset 傳回 code,msg,recno 後面才接 data 內容 + 4 Michael 2022-11-26 新增 join 部門資料, 存在 localStoreage + 5 Michael 2023-02-04 新增 join 公司名稱, 存在 localStoreage + + Call Sample: + CALL checklogin('token123', 'user01', 'password123', 'web'); +*/ +BEGIN + DECLARE v_uuid VARCHAR(36); + DECLARE v_lastlogintime DATETIME; + DECLARE v_recno INT; + DECLARE v_diffhour INT; + DECLARE v_statuscode INT; + DECLARE v_errMsg VARCHAR(200); + DECLARE v_newtoken VARCHAR(100); + DECLARE v_longday INT; -- 0: token 永久有效 其他: token 的效期天數 + + SET v_longday = 0; -- token 預設永久有效 + SET v_statuscode = 9; + SET v_errMsg = 'Token 過期或錯誤!'; + SET v_recno = 0; + SET v_newtoken = ''; + + -- 檢查 token 是否有效 + SELECT COUNT(*), MAX(lastlogintime) INTO v_recno, v_lastlogintime + FROM sys_users + WHERE userid = p_userid + AND IFNULL(isstop, '') <> 'Y' + AND IFNULL(token, 'null') = p_token + GROUP BY token; + + IF v_recno > 0 THEN + SELECT TIMESTAMPDIFF(HOUR, v_lastlogintime, NOW()) INTO v_diffhour; + IF v_diffhour >= 24*v_longday AND v_longday > 0 THEN + SET v_statuscode = 9; + SET v_errMsg = 'token 已過期,請重新登入!'; + ELSE + SET v_statuscode = 0; + SET v_errMsg = '登入成功!'; + SET v_newtoken = p_token; + END IF; + ELSE + SET v_recno = 0; + SELECT COUNT(*) INTO v_recno + FROM sys_users + WHERE userid = p_userid + AND IFNULL(isstop, '') <> 'Y' + AND IFNULL(pwd, '') = p_pwd; + + IF v_recno > 0 THEN + SET v_uuid = UUID(); + UPDATE sys_users SET token = v_uuid, lastlogintime=NOW() WHERE userid = p_userid; + SET v_newtoken = v_uuid; + SET v_statuscode = 0; + SET v_errMsg = '登入成功!'; + ELSE + SET v_statuscode = 4; + SET v_errMsg = '帳號或密碼輸入錯誤!'; + END IF; + END IF; + + -- 寫入 log(return error) + CALL api_log(v_newtoken, v_errMsg); + + -- 回傳值 dataset[0], 前3個欄位有固定的內容 + SELECT v_statuscode AS code, v_errMsg AS msg, v_recno AS recno; + + -- 回傳值 dataset[1], 順便回傳 user info + SELECT + u.*, + d.departmentid, + d.departmentcname, + IFNULL(x.pvalue, 'Kylin Admin') AS corpname + FROM sys_users u + LEFT JOIN basperson p ON p.personid = u.userid + LEFT JOIN basdepartment d ON d.departmentid = p.departmentid + LEFT JOIN sys_parameter x ON x.pid = 'corpname' + WHERE IFNULL(u.token, 'null') = v_newtoken; +END// + +DELIMITER ; \ No newline at end of file diff --git a/permission/checktoken.txt b/permission/checktoken.txt new file mode 100644 index 0000000..70f6940 --- /dev/null +++ b/permission/checktoken.txt @@ -0,0 +1,59 @@ +DELIMITER // + +CREATE OR REPLACE FUNCTION checktoken( + p_token VARCHAR(200) +) +/* + Function : 判斷傳入的 Token 是否過期, 若未過期, 傳回 userid, 已過期傳回空白 + Description: 判斷 Token 是否過期, 若未過期, 傳回 0, 已過期傳回 9 + 簡單的測試 ok + Build Date : 2018/03/02 + + Modify History + Item Who Date Modify Docs + ==== ========== ========== ================================================ + 1 Michael 2018/01/08 開始改寫為 MySQL 版 + +*/ +RETURNS VARCHAR(100) +DETERMINISTIC +BEGIN + DECLARE v_lastlogintime DATETIME; + DECLARE v_recno INT; + DECLARE v_diffhour INT; + DECLARE v_statuscode INT; + DECLARE v_errMsg VARCHAR(200); + DECLARE v_longday INT; -- 0: token 永久有效 其他: token 的效期天數 + DECLARE v_userid VARCHAR(100); + + SET v_longday = 0; -- token 預設永久有效 + SET v_statuscode = 4; + SET v_userid = ''; + SET v_errMsg = '帳號或密碼錯誤!'; + + SELECT COUNT(*), userid, lastlogintime + INTO v_recno, v_userid, v_lastlogintime + FROM sys_users + WHERE IFNULL(isstop, '') <> 'Y' + AND IFNULL(token, 'null') = p_token + GROUP BY userid, lastlogintime; + + IF v_recno > 0 THEN + -- 如果傳入 token + SELECT TIMESTAMPDIFF(HOUR, v_lastlogintime, NOW()) INTO v_diffhour; + + IF v_diffhour >= 24 * v_longday AND v_longday > 0 THEN + SET v_statuscode = 9; + SET v_errMsg = 'token 已過期,請重新登入!'; + SET v_userid = ''; + ELSE + SET v_statuscode = 0; + SET v_errMsg = 'token 有效!'; + END IF; + END IF; + + -- 回傳值 dataset[0], 前3個欄位有固定的內容 + RETURN IFNULL(v_userid, ''); +END // + +DELIMITER ; \ No newline at end of file diff --git a/permission/editmember.txt b/permission/editmember.txt new file mode 100644 index 0000000..0970b5a --- /dev/null +++ b/permission/editmember.txt @@ -0,0 +1,53 @@ +delimiter // + +create or replace procedure editmember( + in token varchar(100), + in userid varchar(100), + in username nvarchar(100), + in email varchar(100), + in pwd varchar(200) +) +/* + Function : 修改會員資料 + Description: 原則: 傳入內容若是空白就不更新 + Build Date : 2018/04/12 + + Modify History + Item Who Date Modify Docs + ==== ========== ========== ================================================ + 1 Michael 2018/01/08 開始改寫為 MySQL 版 + +*/ +begin + /* + 先寫一個簡單的 insert 版本 + uuid 寫入驗證碼(ddmmyy) + 後面還要再加入判斷檢查的機制, 及 error code 回傳等 .. + */ + + if username <> '' then + update sys_users set username = username where userid = userid and username <> username; + end if; + + if email <> '' then + update sys_users set email = email where userid = userid and email <> email; + end if; + + if pwd <> '' and pwd <> 'nopwd' then + update sys_users set pwd = pwd where userid = userid and pwd <> pwd; + end if; + + -- 回傳 ds1 + select 0 as code, '修改會員成功' as msg, 1 as recno; + + -- 回傳 ds2 + select + coalesce(userid, '') as userid, + coalesce(username, '') as username, + coalesce(email, '') as email, + token + from sys_users where coalesce(token, 'null') = token; + +end // + +delimiter ; diff --git a/permission/get_menustructure.txt b/permission/get_menustructure.txt new file mode 100644 index 0000000..9ce821b --- /dev/null +++ b/permission/get_menustructure.txt @@ -0,0 +1,102 @@ +delimiter // + +create or replace procedure get_menustructure() +/* + Function : 配合 amis 的 transfer, 取得 module-menu 資料, 主要是建立 role-menu permissions 用 + Description: 本 sp 修改自 get_orgstructure + Build Date : 2021/10/19 + + Modify History + Item Who Date Modify Docs + ==== ========== ========== ================================================ + 1 Michael 2021/10/19 + +*/ +begin + +declare max_val int; +declare curr_id int; +declare group_id int; +declare next_group_id int; +declare datas nvarchar(max); +declare footer varchar(600); +declare dept_name varchar(100); +declare emp_name varchar(100); +declare person_id varchar(100); +declare crlf varchar(2); +declare comm varchar(1); + +set crlf = char(10) + char(13); + +select + bp.moduleid, bp.menuid, '(' || bp.moduleid || ')' || bm.modulename as deptname, + '(' || bp.menuid || ')' || bp.caption as empname, + ROW_NUMBER() OVER(PARTITION BY bp.moduleid ORDER BY bp.moduleid, bp.menuid) AS groupid, + ROW_NUMBER() OVER(ORDER BY bp.moduleid, bp.menuid) AS rowid +into #tmp +from sys_menutable bp +left join sys_module bm on bp.moduleid = bm.moduleid +where coalesce(bp.moduleid, '') <> '' +order by bp.moduleid, bp.menuid; + +select count(*) into max_val from #tmp; +select min(rowid) into curr_id from #tmp; + +set datas = ''; +set comm = ''; +while (curr_id <= max_val) do + -- 取得現有資料 + select groupid, deptname, empname, menuid into group_id, dept_name, emp_name, person_id + from #tmp where rowid = curr_id; + + if curr_id = max_val then + set comm = ''; + else + select groupid into next_group_id from #tmp where rowid = curr_id + 1; + if next_group_id = 1 then + set comm = ''; + else + set comm = ','; + end if; + end if; + + if group_id = 1 then + if curr_id > 1 then + set footer = ' ]' || crlf || + ' },' || crlf; + else + set footer = ''; + end if; + + set datas = datas || footer || + ' {' || crlf || + ' "label": "' || dept_name || '",' || crlf || + ' "children": [' || crlf || + ' {' || crlf || + ' "label": "' || emp_name || '",' || crlf || + ' "value": "' || person_id || '"' || crlf || + ' }' || comm || crlf; + else + set datas = datas || + ' {' || crlf || + ' "label": "' || emp_name || '",' || crlf || + ' "value": "' || person_id || '"' || crlf || + ' }' || comm || crlf; + end if; + + set curr_id = curr_id + 1; +end while; + +set datas = ' [' || crlf || datas || + ' ]' || crlf || + ' }' || crlf || + ' ]'; + +drop table #tmp; + +select 0 as code, 'ok' as msg; +select datas as jsoncode; + +end // + +delimiter ; diff --git a/permission/get_module_security.txt b/permission/get_module_security.txt new file mode 100644 index 0000000..d0076d4 --- /dev/null +++ b/permission/get_module_security.txt @@ -0,0 +1,42 @@ +DELIMITER // + +CREATE PROCEDURE get_module_security ( + IN p_token VARCHAR(100), -- 新增 token 判斷 + IN p_moduleid VARCHAR(20) +) +/* + Function : 依 Security 的設定, 判斷該 user 所有 menu 的權限 + Description: 配合 login 後, 寫入 localStorage + Build Date : 2023-12-10 + + Modify History + Item Who Date Modify Docs + ==== ========== ========== ================================================ + 1 Michael 2023-12-10 改寫為 MySQL 版 + +*/ +BEGIN + DECLARE v_recno INT; + DECLARE v_statuscode INT; + DECLARE v_errMsg NVARCHAR(200); + DECLARE v_userid VARCHAR(20); + + SET v_statuscode = 0; + SET v_errMsg = '成功!'; + SET v_recno = 1; + + -- 根據傳入的 token 取得 userid + SELECT userid INTO v_userid FROM sys_users WHERE token = p_token; + + -- 回傳值 dataset[0], 前3個欄位有固定的內容 + SELECT v_statuscode AS code, v_errMsg AS msg, v_recno AS recno; + + -- 回傳值 dataset[1], 實際的資料 + SELECT DISTINCT menuid, controlname FROM sys_rolemenusecurity + WHERE (roleid IN (SELECT DISTINCT roleid FROM sys_userroles WHERE userid = v_userid) OR roleid = '00') + AND EXISTS (SELECT * FROM sys_menutable x WHERE x.menuid = sys_rolemenusecurity.menuid AND moduleid = p_moduleid) + AND controlname <> 'read'; + +END // + +DELIMITER ; diff --git a/permission/get_treedata.txt b/permission/get_treedata.txt new file mode 100644 index 0000000..e69b354 --- /dev/null +++ b/permission/get_treedata.txt @@ -0,0 +1,264 @@ +delimiter // + +create procedure get_treedata( + in p_type varchar(20) default 'sprintid', -- sprint etc.. + in p_para01 nvarchar(100) default '1' -- 特別傳入的參數, 目前是 bookid 會傳入 1, 擴充用途(說明如下) +) +/* + Function : 配合 amis 的 treeview, 取得 year-sprint 類的2階資料 + 目前的寫法只適用於固定2階, 如果階數不固定, 要找時間修改(bom 展開), 暫時不適用 + 擴充 @para, 目前是電子書專用, 如果有 @, @後的就是內文的全文檢索內容 + Description: 可以用在 pbi, 會計科目等左方有 tree-view 的 UX, api 回傳用 6 + 新增 @type 參數 + sprint 取得 year-sprint 資料(給 menu 使用) + basdepartment + acctitle 取得 類別-科目 資料(大部分都是用這個) + eipmxx.idno 避免 key 重複導致的錯誤 + Build Date : 2021/10/19 + + Modify History + Item Who Date Modify Docs + ==== ========== ========== ================================================ + 1 Michael 2021/11/26 + 2 Michael 2021/12/31 新增 on lone books + 3 Michael 2022/04/14 新增 sys_aside_setup, aside 改為依設定即可產生 aside 相關 json 設定 + 4 Michael 2022/06/19 @type 加上 tag.type 以防止重複, tag 僅供識別用 + 5 Michael 2022/07/18 key-value 擴充能支援2層式的 tree(開發中) + 6 Michael 2022/07/27 擴充 @para01 內容, 支援內文查詢過濾 + 7 Michael 2023/01/13 將 @para01 第一碼的 bookid 改為傳入 functag +*/ +as + +declare max_val int; +declare curr_id int; +declare group_id int; +declare next_group_id int; +declare datas nvarchar(max); +declare footer varchar(600); +declare dept_name varchar(100); +declare emp_name varchar(100); +declare person_id varchar(100); +declare crlf varchar(2); +declare comm varchar(1); +declare aside_id varchar(100); +declare group_partitionby varchar(100); +declare group_orderby varchar(100); +declare row_orderby varchar(100); +declare filter_field varchar(100); +declare tablename varchar(100); +declare rel_tablename varchar(100); +declare g_partition1 varchar(100); +declare g_partition2 varchar(100); +declare filter_value varchar(100); +declare para02 varchar(100); +declare pos int; +declare cnt int; +declare sql_cmd nvarchar(max); + +set crlf = char(10) + char(13); + +declare data table ( + xr_id varchar(100), x_id varchar(100), + xr_name varchar(100), x_name varchar(100), + groupid int, rowid int +); + +-- 取得相關設定參數 +select + aside_id, group_partitionby, group_orderby, row_orderby, + filter_field, tablename, rel_tablename, filter_value +into aside_id, group_partitionby, group_orderby, row_orderby, + filter_field, tablename, rel_tablename, filter_value +from sys_aside_setup where aside_id = p_type; + +-- 去除 p_type 中的 tag +set pos = charindex('.', p_type); +if pos > 0 then + set p_type = substring(p_type, pos + 1, len(p_type)); +end if; + +set sql_cmd = ''; +set pos = charindex('@', p_para01); +set para02 = ''; +if pos > 0 then + set para02 = substring(p_para01, pos + 1, 100); + set p_para01 = substring(p_para01, 1, pos - 1); + + -- 將 p_para01 由 functag 改為 bookid, add by Michael 2023/01/13 + select keyid into p_para01 from zen_keyvalue where fieldname = 'book_mapping_id' and keyvalue = p_para01; + if isnull(p_para01, '') = '' then + set p_para01 = '1'; + end if; +end if; + +set cnt = 0; +select count(*) into cnt from zen_keyvalue where fieldname = 'classid' and isnull(keydesc, '') <> ''; + +if isnull(filter_field, '') <> '' and isnull(filter_value, '') <> '' then + set filter_value = char(39) + filter_value + char(39); +end if; + +set sql_cmd = ''; +if p_type <> 'classid' then + if isnull(group_partitionby, '') <> '' then + set g_partition1 = 'Partition by ' + group_partitionby; + set g_partition2 = 'R.' + group_partitionby + ','; + end if; + + if rel_tablename = '' then + if cnt > 0 then + set g_partition1 = 'Partition by keydesc'; + set g_partition2 = 'keydesc,'; + set sql_cmd = + 'insert into sys_aside_temp (aside_guid, xr_id, x_id, xr_name, x_name, groupid, rowid)' + + ' select ' + char(39) + p_type + char(39) + ',' + + case when group_id = '*' then char(39) + group_id + char(39) else group_id end + ',' + row_id + ',' + + case when group_id = '*' then char(39) + group_name + char(39) else group_name end + ',' + row_name + ',' + + ' ROW_NUMBER() OVER(' + g_partition1 + ' ORDER BY ' + group_orderby + ') AS groupid,' + + ' ROW_NUMBER() OVER(ORDER BY ' + g_partition2 + row_orderby + ') AS rowid' + + ' from ' + tablename + + ' where coalesce(' + row_id + ', char(39) + char(39)) <> ' + char(39) + char(39) + filter_value; + else + set sql_cmd = + 'insert into sys_aside_temp (aside_guid, xr_id, x_id, xr_name, x_name, groupid, rowid)' + + ' select ' + char(39) + p_type + char(39) + ',' + + case when group_id = '*' then char(39) + group_id + char(39) else group_id end + ',' + row_id + ',' + + case when group_id = '*' then char(39) + group_name + char(39) else group_name end + ',' + row_name + ',' + + ' ROW_NUMBER() OVER(' + g_partition1 + ' ORDER BY ' + group_orderby + ') AS groupid,' + + ' ROW_NUMBER() OVER(ORDER BY ' + g_partition2 + row_orderby + ') AS rowid' + + ' from ' + tablename + + ' where coalesce(' + row_id + ', char(39) + char(39)) <> ' + char(39) + char(39) + filter_value; + end if; + else + set sql_cmd = + 'insert into sys_aside_temp (aside_guid, xr_id, x_id, xr_name, x_name, groupid, rowid)' + + ' select ' + char(39) + p_type + char(39) + ',' + + case when group_id = '*' then char(39) + 'R.' + group_id + char(39) else 'R.' + group_id end + ',' + 'M.' + row_id + ',' + + case when group_id = '*' then char(39) + 'R.' + group_name + char(39) else 'R.' + group_name end + ',' + 'M.' + row_name + ',' + + ' ROW_NUMBER() OVER(' + g_partition1 + ' ORDER BY ' + 'M.' + group_orderby + ') AS groupid,' + + ' ROW_NUMBER() OVER(ORDER BY ' + g_partition2 + 'M.' + row_orderby + ') AS rowid' + + ' from ' + tablename + ' M' + + ' left join ' + rel_tablename + ' R on M.' + group_partitionby + ' = R.' + group_partitionby + + ' where coalesce(' + 'M.' + row_id + ', char(39) + char(39)) <> ' + char(39) + char(39) + filter_value; + end if; +else + if isnull(group_partitionby, '') = '' then + set sql_cmd = + 'insert into sys_aside_temp (aside_guid, xr_id, x_id, xr_name, x_name, groupid, rowid) ' + + 'select ' + char(39) + p_type + char(39) + ',' + + ' x.' + group_id + ', x.' + row_id + ', b.' + group_name + ', x.' + group_name + ', groupid, rowid' + crlf + + 'from' + crlf + + '(' + crlf + + ' select ' + group_id + ',' + row_id + ',' + group_name + ',' + + case when group_name <> row_name then row_name + ',' else '' end + + group_id + ' as p_classid,' + crlf + + ' ROW_NUMBER() OVER(ORDER BY ' + group_orderby + ') AS groupid,' + crlf + + ' ROW_NUMBER() OVER(ORDER BY ' + row_orderby + ') AS rowid' + crlf + + ' from ' + tablename + crlf + + ' where coalesce(' + group_id + ', char(39) + char(39)) <> ' + char(39) + char(39) + ' and ' + filter_field + ' = ' + p_para01 + crlf + + case when para02 <> '' then ' and book_desc like ' + char(39) + '%' + para02 + '%' + char(39) else '' end + crlf + + ') x' + crlf + + 'left join ' + tablename + ' b on x.p_classid = b.' + row_id + ' and ' + filter_field + ' = ' + p_para01; + else + set sql_cmd = + 'insert into sys_aside_temp (aside_guid, xr_id, x_id, xr_name, x_name, groupid, rowid) ' + + 'select ' + char(39) + p_type + char(39) + ',' + + ' x.' + group_id + ', x.' + row_id + ', b.' + group_name + ', x.' + group_name + ', groupid, rowid' + crlf + + 'from' + crlf + + '(' + crlf + + ' select ' + group_id + ',' + row_id + ',' + group_name + ',' + + case when group_name <> row_name then row_name + ',' else '' end + + group_id + ' as p_classid,' + crlf + + ' ROW_NUMBER() OVER(Partition by ' + group_partitionby + ' ORDER BY ' + group_orderby + ') AS groupid,' + crlf + + ' ROW_NUMBER() OVER(ORDER BY ' + row_orderby + ') AS rowid' + crlf + + ' from ' + tablename + crlf + + ' where coalesce(' + group_id + ', char(39) + char(39)) <> ' + char(39) + char(39) + ' and ' + filter_field + ' = ' + p_para01 + crlf + + case when para02 <> '' then ' and book_desc like ' + char(39) + '%' + para02 + '%' + char(39) else '' end + crlf + + ') x' + crlf + + 'left join ' + tablename + ' b on x.p_classid = b.' + row_id + ' and ' + filter_field + ' = ' + p_para01; + end if; +end if; + +print sql_cmd; +execute immediate sql_cmd; + +-- 配合原程式, 將資料寫入 data +insert into data select xr_id, x_id, xr_name, x_name, groupid, rowid from sys_aside_temp where aside_guid = p_type; +delete from sys_aside_temp where aside_guid = p_type; + +/* 開始 main loop */ +select count(*) into max_val from data; +select min(rowid) into curr_id from data; + +set datas = ''; +set comm = ''; +while (curr_id <= max_val) do + -- get data + select groupid, xr_name, x_id, x_name into group_id, deptname, personid, empname from data where rowid = curr_id; + if curr_id = max_val then + set comm = ''; + else + select groupid into next_group_id from data where rowid = curr_id + 1; + if next_group_id = 1 then + set comm = ''; + else + set comm = ','; + end if; + end if; + + if group_id = 1 then + if curr_id > 1 then + + + +/* 開始 main loop */ +select @max=count(*) from @data; +select @currid=min(rowid) from @data; + +set @datas = ''; +set @comm = ''; +while (@currid <= @max) +begin + -- get data + select @groupid=groupid,@deptname=xr_name,@personid=x_id,@empname=x_name from @data where rowid = @currid; + if @currid = @max + set @comm = '' + else begin + select @next_groupid=groupid from @data where rowid = @currid + 1; + if @next_groupid = 1 set @comm = '' else set @comm = ','; + end; + + if @groupid = 1 begin + if @currid > 1 + set @footer = ' ]' + @crlf + + ' },' + @crlf + else + set @footer = ''; + + set @datas = @datas + @footer + + ' {' + @crlf + + ' "label": "'+@deptname+'",' + @crlf + + ' "children": [' + @crlf + + ' {' + @crlf + + ' "label": "'+@empname+'",' + @crlf + + ' "value": "'+@personid+'"' + @crlf + + ' }' + @comm + @crlf; + end + else + set @datas = @datas + + ' {' + @crlf + + ' "label": "'+@empname+'",' + @crlf + + ' "value": "'+@personid+'"' + @crlf + + ' }' + @comm + @crlf; + + set @currid = @currid + 1; +end; + +set @datas = ' [' + @crlf + @datas + + ' ]' + @crlf + + ' }' + @crlf + + ' ]'; + +select 0 as code,'ok' as msg; +select @datas as jsoncode; + diff --git a/permission/resetpwd.txt b/permission/resetpwd.txt new file mode 100644 index 0000000..897d4ed --- /dev/null +++ b/permission/resetpwd.txt @@ -0,0 +1,48 @@ +DELIMITER // + +CREATE PROCEDURE resetpwd ( + IN p_token VARCHAR(100), + IN p_orgpwd VARCHAR(200), + IN p_newpwd VARCHAR(200), + IN p_newpwd2 VARCHAR(200) +) +/* + Function : 重置密碼 + Description: 修改自 sp=regmember + Build Date : 2023-12-10 + + Modify History + Item Who Date Modify Docs + ==== ========== ========== ================================================ + 1 Michael 2023-12-10 改寫為 MySQL 版 + +*/ +BEGIN + DECLARE v_userid VARCHAR(100); + DECLARE v_err_code SMALLINT; + DECLARE v_err_msg NVARCHAR(100); + + IF p_newpwd <> p_newpwd2 THEN + SET v_err_code = 2; + SET v_err_msg = '新密碼輸入錯誤, 請重新設定'; + ELSE + -- 根據傳入的 token 取得 userid + SELECT userid INTO v_userid FROM sys_users WHERE token = p_token AND pwd = p_orgpwd; + + SET v_err_code = 0; + SET v_err_msg = 'reset pwd ok'; + + IF COALESCE(v_userid, '') <> '' THEN + UPDATE sys_users SET pwd = p_newpwd WHERE userid = v_userid; + ELSE + SET v_err_code = 4; + SET v_err_msg = '原密碼輸入錯誤, 請重新輸入'; + END IF; + END IF; + + -- 回傳 ds1 + SELECT v_err_code AS code, v_err_msg AS msg; + +END // + +DELIMITER ; diff --git a/permission/sysexec.txt b/permission/sysexec.txt new file mode 100644 index 0000000..b6b6e41 --- /dev/null +++ b/permission/sysexec.txt @@ -0,0 +1,38 @@ +DELIMITER // + +CREATE PROCEDURE sysexec ( + IN p_token VARCHAR(100), + IN p_sql TEXT +) +BEGIN + DECLARE v_userid VARCHAR(100); + DECLARE v_exstr TEXT; + + -- 根據傳入的 token 取得 userid + SET v_userid = ''; + SELECT userid INTO v_userid FROM sys_users WHERE token = p_token; + + IF COALESCE(v_userid, '') = '' THEN + SELECT 9 AS code, '請先登入系統再執行!!' AS msg; + SELECT ''; + ELSEIF LOCATE('delete ', p_sql) > 0 OR LOCATE('drop ', p_sql) > 0 THEN + SELECT 4 AS code, '內含不允許執行的 SQL 語法, 請重新輸入?!' AS msg; + SELECT ''; + ELSE + BEGIN + DECLARE EXIT HANDLER FOR SQLEXCEPTION + BEGIN + SELECT 9 AS code, '語法有錯,請檢查語法後再重新執行!!' AS msg; + SELECT ''; + END; + + SELECT 0 AS code, '成功執行 SQL 語法' AS msg; + SET @v_exstr = p_sql; + PREPARE v_exstr FROM @v_exstr; + EXECUTE v_exstr; + END; + END IF; + +END // + +DELIMITER ; diff --git a/permission/udf_myfavor.txt b/permission/udf_myfavor.txt new file mode 100644 index 0000000..4d340d3 --- /dev/null +++ b/permission/udf_myfavor.txt @@ -0,0 +1,125 @@ +DELIMITER // + +CREATE OR REPLACE FUNCTION udf_myfavor( + p_moduleid VARCHAR(100), + p_userid VARCHAR(20), + p_ver_type VARCHAR(10), + p_ip VARCHAR(100), + p_db2 VARCHAR(100) +) +RETURNS LONGTEXT +DETERMINISTIC +/* + function : NǤJr, @split Twά 2, Ǧ^ table, oOSΪk + description: + Isd SELECT udf_myfavor('eip','admin','beta','','') + build date : 2023/11/01 + + modify history + item who date modify docs + ==== ========== ========== ================================================ + 1 michael 2023/11/01 sW +*/ +BEGIN + DECLARE v_ret_menu LONGTEXT; + DECLARE v_imax2 INT; + DECLARE v_y2 INT; + DECLARE v_comma VARCHAR(1); + DECLARE v_id2 VARCHAR(100); + DECLARE v_name2 VARCHAR(100); + DECLARE v_isLocalMenu VARCHAR(1); + DECLARE v_crlf VARCHAR(2); + + -- Ы{ɪӦsxƾ + DROP TEMPORARY TABLE IF EXISTS temp_menu_favor; + CREATE TEMPORARY TABLE temp_menu_favor ( + menuid VARCHAR(100), + caption VARCHAR(100), + isLocalMenu VARCHAR(1), + rowid INT AUTO_INCREMENT PRIMARY KEY + ) ENGINE=MEMORY; + + -- Jƾڨ{ɪ + INSERT INTO temp_menu_favor (menuid, caption, isLocalMenu) + SELECT a.functiontag, b.caption, IFNULL(b.isLocalMenu, 'N') + FROM sys_myfavor a + LEFT JOIN sys_menutable b ON a.functiontag = b.menuid + WHERE module = p_moduleid AND userid = p_userid; + + SET v_ret_menu = ''; + SET v_crlf = CHAR(10); + + -- hj + SELECT IFNULL(MAX(rowid), 0) INTO v_imax2 FROM temp_menu_favor; + SELECT IFNULL(MIN(rowid), 0) INTO v_y2 FROM temp_menu_favor; + + WHILE v_y2 <= v_imax2 AND v_imax2 > 0 DO + IF v_y2 = v_imax2 THEN + SET v_comma = ''; + ELSE + SET v_comma = ','; + END IF; + + SELECT menuid, caption, isLocalMenu + INTO v_id2, v_name2, v_isLocalMenu + FROM temp_menu_favor + WHERE rowid = v_y2; + + IF v_isLocalMenu = 'Y' THEN + -- a json { + SET v_ret_menu = CONCAT( + v_ret_menu, + ' {', v_crlf, + ' "label": "', v_name2, '",', v_crlf, + ' "url": "/', p_moduleid, '/', v_id2, '",', v_crlf, + ' "schemaApi": "get:/pages/', v_id2, '.json"', v_crlf, + ' }', v_comma, v_crlf + ); + ELSE + -- uʺAJ code(test ok, but wait to use) + SET v_ret_menu = CONCAT( + v_ret_menu, + ' {', v_crlf, + ' "label": "', v_name2, '",', v_crlf, + ' "url": "/', p_moduleid, '/', v_id2, '",', v_crlf, + ' "schemaApi": {', v_crlf, + ' "method": "post",', v_crlf, + ' "url": "', p_ip, '/xapi/v2/', p_db2, '/zen_showsource/0/",', v_crlf, + ' "data": {', v_crlf, + ' "para01": "', v_id2, '",', v_crlf, + ' "para02": "', p_ver_type, '",', v_crlf, + ' "para03": "', p_ip, '"', v_crlf, + ' },', v_crlf, + ' "dataType": "form"', v_crlf, + ' }', v_crlf, + ' }', v_comma, v_crlf + ); + END IF; + + SET v_y2 = v_y2 + 1; + END WHILE; + + IF v_ret_menu <> '' THEN + SET v_ret_menu = CONCAT( + ' {', v_crlf, + ' "children": [', v_crlf, + ' {', v_crlf, + ' "label": "ڪ̷R",', v_crlf, + ' "url": "/sys",', v_crlf, + ' "icon": "fa fa-heart-o",', v_crlf, + ' "children": [', v_crlf, + v_ret_menu, + ' ]', v_crlf, + ' }', v_crlf, + ' ]', v_crlf, + ' },', v_crlf + ); + END IF; + + -- Mz{ɪ + DROP TEMPORARY TABLE IF EXISTS temp_menu_favor; + + RETURN v_ret_menu; +END // + +DELIMITER ; \ No newline at end of file diff --git a/permission/verifycode.txt b/permission/verifycode.txt new file mode 100644 index 0000000..8cf1650 --- /dev/null +++ b/permission/verifycode.txt @@ -0,0 +1,39 @@ +DELIMITER // +CREATE PROCEDURE verifycode ( + IN site NVARCHAR(100), + IN email VARCHAR(100) +) +/* + Function : 取得驗證碼, 目前是 for 忘記密碼 + Description: 修改自 sp=regmember + Build Date : 2023-12-10 + + Modify History + Item Who Date Modify Docs + ==== ========== ========== ================================================ + 1 Michael 2023-12-10 改寫為 MySQL 版 + +*/ +BEGIN + /* + 先寫一個簡單的版本 + 後面還要再加入判斷檢查的機制, 及 error code 回傳等 .. + */ + DECLARE verifycode VARCHAR(10); + DECLARE randnum INT; + + SET randnum = ROUND(RAND() * 20, 0); + + IF randnum < 3 THEN + SET randnum = 7; + END IF; + + SET verifycode = randnum * (DAY(NOW()) + MONTH(NOW())) * YEAR(NOW()); + + -- 回傳 ds1 + SELECT 0 AS code, '取得驗證碼' AS msg, 1 AS recno; + + -- 回傳 verifycode + SELECT verifycode AS verifycode; +END// +DELIMITER ; diff --git a/permission/zen_codeinit.txt b/permission/zen_codeinit.txt new file mode 100644 index 0000000..59b7417 --- /dev/null +++ b/permission/zen_codeinit.txt @@ -0,0 +1,103 @@ +DELIMITER // + +CREATE PROCEDURE zen_codeinit ( + IN p_new_ip VARCHAR(100), + IN p_new_db1 VARCHAR(100), -- Business + IN p_new_db2 VARCHAR(100) -- Wizard +) +/* + Function : 登入後設定 zen_jsoncode 的 ip 及 db + Description: 原本想自動化執行, 但穩妥起見, 目前先仍維持手動執行一次(切換環境時), 目前暫不使用, 手動改 ip 即可 + Sample: + Build Date : 2023-12-10 + + Modify History + Item Who Date Modify Docs + ==== ========== ========== ================================================ + 1 Michael 2023-12-10 改寫為 MySQL 版 + +*/ +BEGIN + DECLARE v_cnt INT; + DECLARE v_org_ip VARCHAR(100); + DECLARE v_org_db1 VARCHAR(100); -- Business + DECLARE v_org_db2 VARCHAR(100); -- Wizard + + /* + 要先想辦法解析(或手工設定) 在 zen_jsoncode 內的 ip 及 db + 目前僅先考慮出廠的變更, 也就是 + org 的內容 + ip 只會有 127.0.0.1 和 gcp-api.gex.com.tw 或 api.gex.com.tw + db 只會有 zenBusiness / zenWizard / zenEIS + + db 二合一很簡單, 但是一分為二, 就麻煩了 + */ + + SET v_org_ip = ''; + SELECT COUNT(*) INTO v_cnt FROM zen_jsoncode WHERE jsoncode LIKE '%127.0.0.1%'; + IF v_cnt > 0 THEN + SET v_org_ip = '127.0.0.1'; + ELSE + SELECT COUNT(*) INTO v_cnt FROM zen_jsoncode WHERE jsoncode LIKE '%gcp-api.gex.com.tw%'; + IF v_cnt > 0 THEN + SET v_org_ip = 'gcp-api.gex.com.tw'; + ELSE + SELECT COUNT(*) INTO v_cnt FROM zen_jsoncode WHERE jsoncode LIKE '%api.gex.com.tw%'; + IF v_cnt > 0 THEN + SET v_org_ip = 'api.gex.com.tw'; + END IF; + END IF; + END IF; + + SET v_org_db1 = ''; + SELECT COUNT(*) INTO v_cnt FROM zen_jsoncode WHERE jsoncode LIKE '%zenEIS%'; + IF v_cnt > 0 THEN + SET v_org_db1 = 'zenEIS'; + SET v_org_db2 = 'zenEIS'; + ELSE + SET v_org_db1 = 'zenBusiness'; + SET v_org_db2 = 'zenWizard'; + END IF; + + -- 如果是其他非出廠 SOP 的特殊作業, 只能手工設定 + /* + SET v_org_ip = '127.0.0.1'; + SET v_org_db1 = 'xxxdb1'; + SET v_org_db2 = 'xxxdb2'; + */ + + -- update ip + UPDATE zen_jsoncode + SET jsoncode = REPLACE(jsoncode, v_org_ip, p_new_ip), + jsoncode2 = REPLACE(jsoncode2, v_org_ip, p_new_ip), + jsoncode3 = REPLACE(jsoncode3, v_org_ip, p_new_ip); + + -- 如果 db 是一分為二, 要多判斷 sys + IF v_org_db1 = 'zenEIS' AND p_new_db1 <> 'zenEIS' THEN + UPDATE zen_jsoncode + SET jsoncode = REPLACE(jsoncode, v_org_db1, p_new_db1), + jsoncode2 = REPLACE(jsoncode2, v_org_db1, p_new_db1), + jsoncode3 = REPLACE(jsoncode3, v_org_db1, p_new_db1); + + UPDATE zen_jsoncode + SET jsoncode = REPLACE(jsoncode, v_org_db2, p_new_db2), + jsoncode2 = REPLACE(jsoncode2, v_org_db2, p_new_db2), + jsoncode3 = REPLACE(jsoncode3, v_org_db2, p_new_db2); + ELSE + UPDATE zen_jsoncode + SET jsoncode = REPLACE(jsoncode, v_org_db1, p_new_db1), + jsoncode2 = REPLACE(jsoncode2, v_org_db1, p_new_db1), + jsoncode3 = REPLACE(jsoncode3, v_org_db1, p_new_db1); + + UPDATE zen_jsoncode + SET jsoncode = REPLACE(jsoncode, v_org_db2, p_new_db2), + jsoncode2 = REPLACE(jsoncode2, v_org_db2, p_new_db2), + jsoncode3 = REPLACE(jsoncode3, v_org_db2, p_new_db2); + END IF; + + -- 回傳 ds1 + SELECT 0 AS code, 'ok' AS msg; + +END // + +DELIMITER ; diff --git a/permission/zen_dynamicmenu.txt b/permission/zen_dynamicmenu.txt new file mode 100644 index 0000000..9019613 --- /dev/null +++ b/permission/zen_dynamicmenu.txt @@ -0,0 +1,402 @@ +DELIMITER // +CREATE OR REPLACE PROCEDURE zen_dynamicMenu( + IN p_token VARCHAR(100), + IN p_moduleid VARCHAR(10), + IN p_ip VARCHAR(100), + IN p_db1 VARCHAR(100), + IN p_db2 VARCHAR(100) +) +/* + Function : 根據 menu 產生 amis 所需的 site.json 內容 + Description: 每一筆 menu 都預設先有一個 00 role(EveryOne) + Build Date : 2021/08/14 + CALL zen_dynamicMenu('89b179f7-72a0-11f0-9c5f-d8bbc15c1404','zen','https://api.gex.com.tw:8033','EIS_demo','EIS_demo'); + + Modify History + Item Who Date Modify Docs + ==== ========== ========== ================================================ + 1 Michael 2022-05-05 微調2個判斷, 避免組出的 site menu 因逗號錯誤無法顯示 menu + 2 Michael 2022-05-21 修改 @ip 內容(配合 https 的大改版), 刪除原程式的 http:// 內容 + 3 Michael 2023-02-01 為了更加彈性, @ip 及 @db 這2個欄位改傳入 ${ls:xxxx}, 測試可行(程式要調整前端呼叫的程式) + 4 Michael 2023-02-04 修改 menu 的排序, 改為依 seq_no(原先是 menuid) + 5 Michael 2023-04-04 改依參數檔設定的程式版本別 + 6 Michael 2023-04-22 新增 Wizard 為 zen 模組的相關判斷 +*/ +BEGIN + DECLARE v_rets, v_ret_menu, v_all_menu, v_myfavor LONGTEXT; + DECLARE v_userid VARCHAR(20); + DECLARE v_imax1, v_imax2, v_y1, v_y2, v_x1, v_x2 INT DEFAULT 0; + DECLARE v_pid, v_id1, v_name1, v_id2, v_name2 VARCHAR(100); + DECLARE v_isLocalMenu, v_crlf, v_comma CHAR(1); + DECLARE v_ver_type, v_wizard_model VARCHAR(100); + + -- 宣告一級選單游標 + DECLARE cur_menu00 CURSOR FOR + SELECT menuid, caption + FROM tmp_menu00 + ORDER BY rowid; + + -- 宣告二級選單游標 + DECLARE cur_menu99 CURSOR FOR + SELECT parent_menuid, menuid, caption, isLocalMenu + FROM tmp_menu99 + ORDER BY rowid; + + DECLARE CONTINUE HANDLER FOR NOT FOUND SET @done = TRUE; + + -- 初始化變數 + SET v_crlf = CHAR(10); + SET v_wizard_model = 'zen'; + + -- 取得版本類型(預設 beta) + SELECT COALESCE(pvalue, 'beta') INTO v_ver_type + FROM sys_parameter + WHERE systemid = 'base' AND pid = 'ver_type' + LIMIT 1; + + -- 根據 token 取得使用者 ID + SELECT userid INTO v_userid + FROM sys_users + WHERE token = p_token + LIMIT 1; + + -- 建立臨時表 (取代原來的表變數) + CREATE TEMPORARY TABLE IF NOT EXISTS tmp_menu00 ( + menuid VARCHAR(100), + caption NVARCHAR(100), + rowid INT AUTO_INCREMENT PRIMARY KEY + ); + + CREATE TEMPORARY TABLE IF NOT EXISTS tmp_menu99 ( + parent_menuid VARCHAR(100), + menuid VARCHAR(100), + caption NVARCHAR(100), + isLocalMenu CHAR(1), + rowid INT AUTO_INCREMENT PRIMARY KEY + ); + + TRUNCATE TABLE tmp_menu00; + TRUNCATE TABLE tmp_menu99; + + -- 插入一級選單 (排序用) + INSERT INTO tmp_menu00 (menuid, caption) + SELECT DISTINCT m.menuid, m.caption + FROM sys_menutable m + WHERE m.moduleid = p_moduleid + AND ( + EXISTS ( + SELECT 1 + FROM sys_rolemenusecurity rms + JOIN sys_userroles ur ON ur.roleid = rms.roleid + WHERE ur.userid = v_userid + AND rms.controlname = 'read' + AND rms.menuid = m.menuid + ) + OR EXISTS ( + SELECT 1 + FROM sys_rolemenusecurity rms + WHERE rms.roleid = '00' + AND rms.menuid = m.menuid + ) + ) + AND COALESCE(m.parent_menuid, '') = '' + ORDER BY (SELECT seq_no FROM sys_menutable WHERE menuid = m.menuid); + + -- 插入二級選單 (排序用) + INSERT INTO tmp_menu99 (parent_menuid, menuid, caption, isLocalMenu) + SELECT DISTINCT m.parent_menuid, m.menuid, m.caption, COALESCE(m.isLocalMenu, 'N') + FROM sys_menutable m + WHERE m.moduleid = p_moduleid + AND ( + EXISTS ( + SELECT 1 + FROM sys_rolemenusecurity rms + JOIN sys_userroles ur ON ur.roleid = rms.roleid + WHERE ur.userid = v_userid + AND rms.controlname = 'read' + AND rms.menuid = m.menuid + ) + OR EXISTS ( + SELECT 1 + FROM sys_rolemenusecurity rms + WHERE rms.roleid = '00' + AND rms.menuid = m.menuid + ) + ) + AND COALESCE(m.parent_menuid, '') <> '' + ORDER BY m.parent_menuid, (SELECT seq_no FROM sys_menutable WHERE menuid = m.menuid); + + -- 取得我的最愛選單 + SET v_myfavor = udf_myfavor(p_moduleid, v_userid, v_ver_type, p_ip, p_db2); + + -- 初始化固定 JSON 結構 + SET v_rets = CONCAT( + '{', v_crlf, + ' "pages": [', v_crlf, + ' {', v_crlf, + ' "label": "Home",', v_crlf, + ' "url": "/",', v_crlf, + ' "redirect": "/', CASE WHEN p_moduleid = 'bpm' THEN 'bpm' ELSE 'sys' END, '/dashboard"', v_crlf, + ' },', v_crlf, + ' {', v_crlf, + ' "children": [', v_crlf + ); + + -- 加入 Dashboard 項目 + IF p_moduleid <> 'bpm' THEN + SET v_rets = CONCAT(v_rets, + ' {', v_crlf, + ' "label": "Dash Board",', v_crlf, + ' "url": "/sys/dashboard",', v_crlf, + ' "icon": "fas fa-chart-pie",', v_crlf, + ' "schemaApi": "get:/pages/sys-dashboard.json"', v_crlf, + ' },', v_crlf, + ' {', v_crlf, + ' "label": "電子簽核主頁",', v_crlf, + ' "visible": false,', v_crlf, + ' "url": "/bpm/dashboard",', v_crlf, + ' "icon": "fas fa-chart-pie",', v_crlf, + ' "schemaApi": "get:/pages/bpm-dashboard.json"', v_crlf, + ' }', v_crlf + ); + ELSE + SET v_rets = CONCAT(v_rets, + ' {', v_crlf, + ' "label": "電子簽核主頁",', v_crlf, + ' "url": "/bpm/dashboard",', v_crlf, + ' "icon": "fas fa-chart-pie",', v_crlf, + ' "schemaApi": "get:/pages/bpm-dashboard.json"', v_crlf, + ' },', v_crlf, + ' {', v_crlf, + ' "label": "Dash Board",', v_crlf, + ' "visible": false,', v_crlf, + ' "url": "/sys/dashboard",', v_crlf, + ' "icon": "fas fa-chart-pie",', v_crlf, + ' "schemaApi": "get:/pages/sys-dashboard.json"', v_crlf, + ' }', v_crlf + ); + END IF; + + -- 加入我的最愛 + SET v_rets = CONCAT(v_rets, + ' ]', v_crlf, + ' },', v_crlf, + v_myfavor, v_crlf + -- CASE WHEN v_myfavor IS NOT NULL AND v_myfavor <> '' THEN + -- CONCAT(v_crlf, ',') -- 只有當有內容時才加逗號和內容 + -- ELSE v_crlf + -- END + ); + + -- 處理一級選單 + SET v_imax1 = (SELECT COALESCE(MAX(rowid), 0) FROM tmp_menu00); + SET v_y1 = 1; + + WHILE v_y1 <= v_imax1 DO + -- 取得一級選單資料 + SELECT menuid, caption INTO v_id1, v_name1 + FROM tmp_menu00 + WHERE rowid = v_y1; + + SET v_ret_menu = CONCAT( + ' {', v_crlf, + ' "children": [', v_crlf, + ' {', v_crlf, + ' "label": "', v_name1, '",', v_crlf, + ' "url": "/', p_moduleid, '",', v_crlf, + ' "icon": "fa fa-cube",', v_crlf, + ' "children": [', v_crlf + ); + + -- 處理二級選單 + SET v_imax2 = (SELECT COALESCE(MAX(rowid), 0) FROM tmp_menu99 WHERE parent_menuid = v_id1); + SET v_y2 = (SELECT COALESCE(MIN(rowid), 0) FROM tmp_menu99 WHERE parent_menuid = v_id1); + + WHILE v_y2 <= v_imax2 DO + -- 取得二級選單資料 + SELECT menuid, caption, isLocalMenu INTO v_id2, v_name2, v_isLocalMenu + FROM tmp_menu99 + WHERE rowid = v_y2 + AND parent_menuid = v_id1; + + -- 判斷是否為最後一項 + IF v_y2 = v_imax2 THEN + SET v_comma = ''; + ELSE + SET v_comma = ','; + END IF; + + -- 根據是否為本地選單生成不同結構 + IF v_isLocalMenu = 'Y' THEN + SET v_ret_menu = CONCAT(v_ret_menu, + ' {', v_crlf, + ' "label": "', v_name2, '",', v_crlf, + ' "url": "/', p_moduleid, '/', v_id2, '",', v_crlf, + ' "schemaApi": "get:/pages/', v_id2, '.json"', v_crlf, + ' }', v_comma, v_crlf + ); + ELSE + SET v_ret_menu = CONCAT(v_ret_menu, + ' {', v_crlf, + ' "label": "', v_name2, '",', v_crlf, + ' "url": "/', p_moduleid, '/', v_id2, '",', v_crlf, + ' "schemaApi": {', v_crlf, + ' "method": "post",', v_crlf, + ' "url": "', p_ip, '/xapi/v2/', p_db2, '/zen_showsource/0/",', v_crlf, + ' "data": {', v_crlf, + ' "para01": "', v_id2, '",', v_crlf, + ' "para02": "', v_ver_type, '",', v_crlf, + ' "para03": "', p_ip, '"', v_crlf, + ' },', v_crlf, + ' "dataType": "form"', v_crlf, + ' }', v_crlf, + ' }', v_comma, v_crlf + ); + END IF; + + -- 特殊處理 Wizard 模組 + IF (v_id2 = 'zen01' OR v_id2 = 'zen11') AND p_moduleid = v_wizard_model THEN + -- 加入四項 Wizard 相關功能 + SET v_ret_menu = CONCAT(v_ret_menu, + ' {', v_crlf, + ' "label": "Wizard Function",', v_crlf, + ' "url": "/', v_wizard_model, '/function",', v_crlf, + ' "visible": false,', v_crlf, + ' "schemaApi": {', v_crlf, + ' "method": "post",', v_crlf, + ' "url": "', p_ip, '/xapi/v2/', p_db2, '/zen_showsource/0/",', v_crlf, + ' "data": {', v_crlf, + ' "para01": "zen02",', v_crlf, + ' "para02": "', v_ver_type, '",', v_crlf, + ' "para03": "', p_ip, '"', v_crlf, + ' },', v_crlf, + ' "dataType": "form"', v_crlf, + ' }', v_crlf, + ' },', v_crlf, + ' {', v_crlf, + ' "label": "Wizard Fields",', v_crlf, + ' "url": "/', v_wizard_model, '/fields",', v_crlf, + ' "visible": false,', v_crlf, + ' "schemaApi": {', v_crlf, + ' "method": "post",', v_crlf, + ' "url": "', p_ip, '/xapi/v2/', p_db2, '/zen_showsource/0/",', v_crlf, + ' "data": {', v_crlf, + ' "para01": "zen03",', v_crlf, + ' "para02": "', v_ver_type, '",', v_crlf, + ' "para03": "', p_ip, '"', v_crlf, + ' },', v_crlf, + ' "dataType": "form"', v_crlf, + ' }', v_crlf, + ' },', v_crlf, + ' {', v_crlf, + ' "label": "Query Wizard Function",', v_crlf, + ' "url": "/', v_wizard_model, '/query_function",', v_crlf, + ' "visible": false,', v_crlf, + ' "schemaApi": {', v_crlf, + ' "method": "post",', v_crlf, + ' "url": "', p_ip, '/xapi/v2/', p_db2, '/zen_showsource/0/",', v_crlf, + ' "data": {', v_crlf, + ' "para01": "zen12",', v_crlf, + ' "para02": "', v_ver_type, '",', v_crlf, + ' "para03": "', p_ip, '"', v_crlf, + ' },', v_crlf, + ' "dataType": "form"', v_crlf, + ' }', v_crlf, + ' },', v_crlf, + ' {', v_crlf, + ' "label": "Query Wizard Fields",', v_crlf, + ' "url": "/', v_wizard_model, '/query_fields",', v_crlf, + ' "visible": false,', v_crlf, + ' "schemaApi": {', v_crlf, + ' "method": "post",', v_crlf, + ' "url": "', p_ip, '/xapi/v2/', p_db2, '/zen_showsource/0/",', v_crlf, + ' "data": {', v_crlf, + ' "para01": "zen13",', v_crlf, + ' "para02": "', v_ver_type, '",', v_crlf, + ' "para03": "', p_ip, '"', v_crlf, + ' },', v_crlf, + ' "dataType": "form"', v_crlf, + ' }', v_crlf, + ' }', v_comma, v_crlf + ); + END IF; + + SET v_y2 = v_y2 + 1; + END WHILE; + + -- 關閉一級選單結構 + SET v_ret_menu = CONCAT(v_ret_menu, + ' ]', v_crlf, + ' }', v_crlf, + ' ]', v_crlf, + ' }' + ); + + -- 加入開發測試區(僅 Wizard 模組的最後一項) + IF v_y1 = v_imax1 AND p_moduleid = v_wizard_model THEN + SET v_ret_menu = CONCAT(v_ret_menu, ',', v_crlf, + ' {', v_crlf, + ' "children": [', v_crlf, + ' {', v_crlf, + ' "label": "開發公測區",', v_crlf, + ' "url": "/dev",', v_crlf, + ' "icon": "fab fa-dev",', v_crlf, + -- ' "visibleOn": "1=0",', v_crlf, + ' "children": [', v_crlf, + ' {', v_crlf, + ' "label": "測試程式01",', v_crlf, + ' "url": "/dev/dev01",', v_crlf, + ' "schemaApi": "get:/pages/dev-test01.json"', v_crlf, + ' },', v_crlf, + ' {', v_crlf, + ' "label": "測試程式02",', v_crlf, + ' "url": "/dev/dev02",', v_crlf, + ' "schemaApi": "get:/pages/dev-test02.json"', v_crlf, + ' },', v_crlf, + ' {', v_crlf, + ' "label": "測試程式03",', v_crlf, + ' "url": "/dev/dev03",', v_crlf, + ' "schemaApi": "get:/pages/dev-test03.json"', v_crlf, + ' }', v_crlf, + ' ]', v_crlf, + ' }', v_crlf, + ' ]', v_crlf, + ' }' + ); + END IF; + + -- 判斷是否為最後一項 + IF v_y1 = v_imax1 THEN + SET v_comma = ''; + ELSE + SET v_comma = ','; + END IF; + + SET v_ret_menu = CONCAT(v_ret_menu, v_comma, v_crlf); + SET v_all_menu = CONCAT(COALESCE(v_all_menu, ''), v_ret_menu); + SET v_y1 = v_y1 + 1; + END WHILE; + + -- 組合最終 JSON + IF v_imax1 <= 0 THEN + -- 移除最後的逗號,保留換行 + IF RIGHT(v_rets, 11) = '},\n\n ]\n}' THEN + SET v_rets = CONCAT(LEFT(v_rets, CHAR_LENGTH(v_rets) - 8), '\n\n ]\n}'); + ELSEIF RIGHT(v_rets, 3) = '},\n' THEN + SET v_rets = CONCAT(LEFT(v_rets, CHAR_LENGTH(v_rets) - 2), '\n ]', v_crlf, '}'); + ELSE + SET v_rets = CONCAT(v_rets, ' ]', v_crlf, '}'); + END IF; + ELSE + SET v_rets = CONCAT(v_rets, v_all_menu, v_crlf, ' ]', v_crlf, '}'); + END IF; + + -- 返回結果 + SELECT 0 AS code, '選單生成成功!' AS msg; + SELECT v_rets AS jsoncode; + + -- 清理臨時表 + DROP TEMPORARY TABLE IF EXISTS tmp_menu00; + DROP TEMPORARY TABLE IF EXISTS tmp_menu99; +END // +DELIMITER ; \ No newline at end of file diff --git a/permission/zen_sync_base_security.txt b/permission/zen_sync_base_security.txt new file mode 100644 index 0000000..c87aba3 --- /dev/null +++ b/permission/zen_sync_base_security.txt @@ -0,0 +1,81 @@ +DELIMITER // + +CREATE PROCEDURE zen_sync_base_security( + IN p_token VARCHAR(100), + IN p_functiontag VARCHAR(100) +) +/* + Function : 在單一資料庫的架構下, 在 Wizard 產生程式後, 直接同步 menu 及基本權限設定 + Description: 目的是產生程式後, 就可以直接在測試環境執行 + Build Date : 2023-12-10 + + Modify History + Item Who Date Modify Docs + ==== ========== ========== ================================================ + 1 Michael 2023-12-10 改寫為 MySQL 版 + +*/ +BEGIN + DECLARE parenttag VARCHAR(100); + DECLARE cnt INT; + DECLARE user_id VARCHAR(100); + DECLARE err_code SMALLINT; + DECLARE err_msg NVARCHAR(100); + + SET err_code = 0; + SET err_msg = '選單及權限設定成功 !!'; + + SELECT userid INTO user_id FROM sys_users WHERE token = p_token; + + IF COALESCE(user_id, '') = '' THEN + SET err_code = 4; + SET err_msg = '原密碼輸入錯誤, 請重新輸入'; + ELSE + -- step 1: 先判斷是否是單一 db 架構 + -- if EXISTS (SELECT * FROM information_schema.tables WHERE table_name = 'sys_menutable') + IF 1 = 1 THEN -- 利用同義字(Synonym) 解決括資料庫問題 20230823 Michael + -- step 2: 根據 zen_function 寫入 menu + -- 如果 parent_menuid 不存在, 要一併自動產生 + SELECT parenttag INTO parenttag FROM zen_function WHERE functiontag = p_functiontag; + IF COALESCE(parenttag, '') = '' THEN + SET parenttag = ''; + END IF; + + SELECT COUNT(*) INTO cnt FROM sys_menutable WHERE menuid = parenttag AND parenttag <> ''; + IF cnt = 0 THEN + INSERT INTO sys_menutable (menuid, parent_menuid, caption, moduleid, seq_no, owned) + SELECT parenttag, '', functionname + '(目錄)', projectid, functiontag, '00' FROM zen_function WHERE functiontag = p_functiontag; + + INSERT INTO sys_rolemenusecurity (roleid, menuid, controlname) + SELECT '00', p_functiontag, 'read'; + END IF; + + SELECT COUNT(*) INTO cnt FROM sys_menutable WHERE menuid = p_functiontag; + IF cnt = 0 THEN + INSERT INTO sys_menutable (menuid, parent_menuid, caption, moduleid, seq_no, owned) + SELECT functiontag, parenttag, functionname, projectid, functiontag, '00' FROM zen_function WHERE functiontag = p_functiontag; + END IF; + + -- step 3: 根據 zen_fields 寫入 security + SELECT COUNT(*) INTO cnt FROM sys_rolemenusecurity WHERE menuid = p_functiontag; + IF cnt = 0 THEN + INSERT INTO sys_rolemenusecurity (roleid, menuid, controlname) + SELECT '00', p_functiontag, 'read' + UNION + SELECT '00', p_functiontag, 'insert' + UNION + SELECT '00', p_functiontag, 'update' + UNION + SELECT '00', p_functiontag, 'delete'; + END IF; + ELSE + SET err_code = 9; + SET err_msg = '必須是單一資料庫架構才能執行 !!'; + END IF; + END IF; + + SELECT err_code AS code, err_msg AS msg; + +END // + +DELIMITER ;