```=csharp
protected void Page_Load(object sender, EventArgs e)
{
var sm = ScriptManager.GetCurrent(Page);
if (sm != null) sm.EnablePageMethods = true; // 不用動 MasterPage 標記
}
[System.Web.Services.WebMethod]
public static object Search(string q, int take) { /* 回 { ok,data } */ }
```
```=SQL
-- [Feature] Article Chunked Upload Schema
-- 主表:文章主體 (儲存壓縮後 HTML)
CREATE TABLE fwpdb.article (
article_id VARCHAR2(64 CHAR) NOT NULL,
title VARCHAR2(200 CHAR) NOT NULL,
version_no NUMBER DEFAULT 1 NOT NULL, -- 目前版本號
content_gz BLOB NOT NULL, -- 壓縮後 HTML
created_by VARCHAR2(50 CHAR),
created_at DATE DEFAULT SYSDATE,
updated_at DATE DEFAULT SYSDATE,
CONSTRAINT pk_article_id primary key (article_id)
);
/
--版本交易表:記錄每次上傳的完整版本資訊
CREATE TABLE fwpdb.article_version_tx (
version_id VARCHAR2(64 CHAR) NOT NULL, -- 公開唯一 ID
article_id VARCHAR2(64 CHAR) NOT NULL,
version_no NUMBER NOT NULL, -- 對應主表版本
total_chunks NUMBER NOT NULL, -- 分段總數
received_chunks NUMBER, -- 已上傳段數
chunk_size NUMBER, -- 每段大小
sha256_hex VARCHAR2(64), -- 壓縮內容 Hash
orig_bytes NUMBER, -- 原始大小
gzip_bytes NUMBER, -- 壓縮大小
completed CHAR(1) DEFAULT 'N' CHECK (completed IN ('Y','N')),
uploaded_by VARCHAR2(50 CHAR),
created_at DATE DEFAULT SYSDATE NOT NULL,
updated_at DATE DEFAULT SYSDATE NOT NULL,
CONSTRAINT pk_version_id primary key (version_id),
CONSTRAINT uq_article_version UNIQUE (article_id, version_no),
CONSTRAINT uq_article_version_id UNIQUE (article_id)
)
/
-- 分段紀錄表:追蹤每個上傳分段
CREATE TABLE fwpdb.article_chunk_tx (
chunk_id VARCHAR2(64 CHAR) NOT NULL, -- 公開唯一 ID
article_id VARCHAR2(64 CHAR) NOT NULL,
version_no NUMBER NOT NULL,
chunk_seq NUMBER NOT NULL, -- 第幾段 (1-based)
chunk_data BLOB, -- 暫存上傳分段
chunk_size NUMBER, -- 實際段大小
uploaded_by VARCHAR2(50 CHAR),
created_at DATE DEFAULT SYSDATE,
CONSTRAINT uq_article_chunk UNIQUE (article_id, version_no, chunk_seq),
CONSTRAINT uq_article_chunk_id UNIQUE (chunk_id)
)
/
COMMENT ON TABLE fwpdb.article IS 'HELEPER CENTER 主文章表';
COMMENT ON COLUMN fwpdb.article.article_id IS '文章唯一識別碼 (UUID)';
COMMENT ON COLUMN fwpdb.article.title IS '文章標題';
COMMENT ON COLUMN fwpdb.article.version_no IS '當前版本號';
COMMENT ON COLUMN fwpdb.article.content_gz IS 'Gzip 壓縮 HTML 內容';
COMMENT ON COLUMN fwpdb.article.created_by IS '建立者';
COMMENT ON COLUMN fwpdb.article.created_at IS '建立時間';
COMMENT ON COLUMN fwpdb.article.updated_at IS '更新時間';
/
COMMENT ON TABLE fwpdb.article_version_tx IS '文章版本交易紀錄表';
COMMENT ON COLUMN fwpdb.article_version_tx.version_no IS '版本號';
COMMENT ON COLUMN fwpdb.article_version_tx.total_chunks IS '分段總數';
COMMENT ON COLUMN fwpdb.article_version_tx.received_chunks IS '已上傳段數';
COMMENT ON COLUMN fwpdb.article_version_tx.completed IS '是否完成 (Y/N)';
/
COMMENT ON TABLE fwpdb.article_chunk_tx IS '文章分段上傳紀錄表';
COMMENT ON COLUMN fwpdb.article_chunk_tx.chunk_seq IS '分段順序 (1-based)';
COMMENT ON COLUMN fwpdb.article_chunk_tx.chunk_data IS '分段資料 (BLOB)';
COMMENT ON COLUMN fwpdb.article_chunk_tx.uploaded_by IS '上傳使用者';
/
SELECT * FROM fwpdb.article
/
SELECT * FROM fwpdb.article_version_tx
/
SELECT * FROM fwpdb.article_chunk_tx
```
-------------
```=javaScript
//init
const editor = CKEDITOR.replace('editor1');
const getData = async (apiUrl, payload) => {
try {
const res = await fetch(apiUrl, {
method: "POST",
headers: {
"Content-Type": "application/json; charset=utf-8",
},
body: JSON.stringify(payload),
})
return res?.d
} catch (e) {
console.error(e.errorMessage);
}
}
function htmlToTextWithoutBase64(html) {
const parser = new DOMParser();
const doc = parser.parseFromString(html, 'text/html');
doc.querySelectorAll('script,style,noscript,img[src^="data:image"]').forEach(el => el.remove());
const text = (doc.body.textContent || '').replace(/\u00A0/g, ' ').trim();
return text;
}
// main
const sumbitBtn = document.querySelector('.btn');
// 將 ArrayBuffer 的 SHA-256 轉成 hex 字串
function bytesToHex(buffer) {
return [...new Uint8Array(buffer)]
.map(b => b.toString(16).padStart(2, "0"))
.join("");
}
//加壓Gzip(Binary) 轉 base64
async function compressionStream(html) {
const encoder = new TextEncoder();
const htmlBytes = encoder.encode(html); //轉 Uint8Array
//壓縮
const stream = new Blob([htmlBytes]).stream().pipeThrough(new CompressionStream("gzip"));
//轉 ArrayBuffer
const gzipBytes = await new Response(stream).arrayBuffer();
//將 Uint8Array 轉 base64
const base64 = btoa(String.fromCharCode(...new Uint8Array(gzipBytes)));
// 計算 SHA-256(對 gzip bytes)
const hashBuffer = await crypto.subtle.digest("SHA-256", gzipBytes);
const sha256_hex = bytesToHex(hashBuffer);
return { base64, sha256_hex }
;
}
//切分 base64 chunks
function getUploadChuncks(chunkSize = 512 * KB) {
const KB = 1024;
const MB = 1024 * KB;
const totalChunks = Math.ceil(base64Data.length / chunkSize);
const chunks = [];
for (let i = 0; i < totalChunks; i++) {
const chunk = base64Data.slice(i * chunkSize, (i + 1) * chunkSize);
chunk.push({
article_uid: crypto.randomUUID(),
chunkIndex: i + 1,
totalChunks,
chunkSize,
chunk,
});
}
return { chunks, chunkSize, totalChunks }
}
// 解碼base64
async function ungzipBase64(base64Str) {
const binary = atob(base64Str); //base64 to binary string
const bytes = new Uint8Array(binary.length); //new uint8array
for (let i = 0; i < binary.length; i++) bytes[i] = binary.charCodeAt(i);
const ds = new DecompressionStream("gzip");
const decompressedStream = new Response(
new Blob([bytes]).stream().pipeThrough(ds)
);
return await decompressedStream.text();
}
//base64 to html
function getFormData() {
const title = document.querySelector('.title').textContent;
const html = editor.getData();
const text = htmlToTextWithoutBase64(html);
return {
title, html, text
};
}
sumbitBtn.addEventListener('click', async (e) => {
try {
const formData = getFormData();
//1. 加壓範例
const { base64, sha256_hex } = await compressionStream(formData.html);
console.log('加壓準備傳送Base64:', base64, 'sha-256 給後端驗證文件碼要先轉譯 Gzip:', sha256_hex);
//2. chuncks upload
const { chunks, chunkSize, totalChunks } = getUploadChuncks();
console.log('這裡要寫分段Call API, insert Version Table, 分段上傳chunk size');
console.log(chunks, chunkSize, totalChunks);
//3. call upload api
chunks.forEach(async (chunk) => {
//fetch('/UploadChunck')
});
//4. verify complete api call
//fetch('/VerifyUploadComplete') body: {articleId}
//解壓
const unGzipBase64 = await ungzipBase64(base64);
console.log(unGzipBase64);
//chuncks forEach call api
//const res = getData('Default2.aspx/GetData', {
// data: JSON.stringify(formData)
//});
//console.log(res);
} catch (e) {
console.error(e);
}
});
```
-------------------------------


MachineGuid REG_SZ edafb182-9c50-4cb3-ab8d-7a5b2b1f7bda
## WebFrom
```=HTML
<asp:Content ID="BodyContent" ContentPlaceHolderID="MainContent" runat="server">
<style>
.d-flex {
display: flex;
}
.justify-content-center {
justify-content: center;
}
.align-items-center {
align-items: center;
}
.gap-1 {
gap: 1rem;
}
label {
padding: 8px 16px;
border-radius: 2px;
cursor: pointer;
margin-bottom: 4px;
border:1px solid #d2cece;
}
input[type='radio'] {
display: none;
}
input[type='radio']:checked + label {
background: #0d6efd;
color: white;
}
</style>
<div>
<h1>Test Webfrom form BarCode Demo</h1>
</div>
<!-- Release 選擇項目 -->
<asp:RadioButtonList ID="ReleaseItem" runat="server" RepeatDirection="Horizontal" >
<asp:ListItem Text="LotId" Value="LotId" Selected="True" />
<asp:ListItem Text="MagazineId" Value="MagazineId" />
</asp:RadioButtonList>
<!-- Release 輸入框 -->
<div>
<asp:TextBox CssClass="form-control" ID="ReleaseId" runat="server" placeholder="請輸入LotID" />
<asp:Button ID="ReleaseSearchBtn" Style="display: none" runat="server" Text="查詢" OnClick="ReleaseSearchBtn_Click" />
</div>
<!-- 表格 -->
<asp:GridView ID="GridView1" runat="server" AutoGenerateColumns="False"
OnRowCommand="GridView1_RowCommand" EditRowStyle-HorizontalAlign="Justify">
<Columns>
<asp:TemplateField HeaderText="項目">
<ItemTemplate>
<asp:Label ID="lblSeqNo" runat="server" Text='<%# Container.DataItemIndex + 1 %>' />
</ItemTemplate>
</asp:TemplateField>
<asp:TemplateField HeaderText="選擇">
<ItemTemplate>
<asp:CheckBox ID="chkSelect" runat="server" />
</ItemTemplate>
</asp:TemplateField>
<asp:BoundField DataField="LotId" HeaderText="LotId" />
<asp:BoundField DataField="MagazineId" HeaderText="MagazineId" />
<asp:TemplateField>
<ItemTemplate>
<asp:Button ID="btnDetails" runat="server" Text="詳細" CommandName="Details" CommandArgument='<%# Container.DataItemIndex %>' />
</ItemTemplate>
</asp:TemplateField>
<asp:TemplateField HeaderText="刪除">
<ItemTemplate>
<asp:Button ID="btnDelete" runat="server" Text="刪除" CommandName="Delete" CommandArgument='<%# Container.DataItemIndex %>' />
</ItemTemplate>
</asp:TemplateField>
</Columns>
</asp:GridView>
<script>
const releaseItem = document.querySelector("#<%= ReleaseItem.ClientID%>");
const releaseInput = document.querySelector("#<%= ReleaseId.ClientID%>");
const releaseSearchBtn = document.querySelector("#<%= ReleaseSearchBtn.ClientID%>");
releaseInput.value = "";
releaseItem.addEventListener('click', (e) => {
releaseInput.value = "";
releaseInput.focus();
releaseInput.placeholder = e.target.value === 'LotId' ? '請輸入LotID' : '請輸入MagazinID';
})
releaseSearchBtn.addEventListener("keydown", (e) => {
if (e.keyCode == 13) {
releaseSearchBtn.click();
}
})
</script>
</asp:Content>
```
```=csharp
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Xml.Linq;
public partial class About : Page
{
public static List<ReleaseRow> DataBase = new List<ReleaseRow>() {
new ReleaseRow { LotId = "lotId1", MagazineId = "Magazine1" },
new ReleaseRow { LotId = "lotId2", MagazineId = "Magazine2" }
};
[Serializable]
public class ReleaseRow
{
public string LotId { get; set; }
public string MagazineId { get; set; }
}
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
//UpdateReleaseGridView();
}
}
protected void UpdateReleaseGridView()
{
List<ReleaseRow> updateData = (List<ReleaseRow>)ViewState["releaseData"];
try
{
if (updateData == null || updateData.Count == 0) return;
GridView1.DataSource = updateData;
GridView1.DataBind();
}
catch (Exception ex)
{
}
}
protected void GridView1_RowCommand(object sender, GridViewCommandEventArgs e)
{
if (e.CommandName == "Details")
{
//rowId
int rowIndex = Convert.ToInt32(e.CommandArgument);
// Get rowData
GridViewRow row = GridView1.Rows[rowIndex];
Console.WriteLine(row);
CheckBox chkSelect = (CheckBox)row.FindControl("chkSelect");
string c2 = row.Cells[2].Text;
string c3 = row.Cells[3].Text;
// 測試得到該行數據
string lotId = ((Label)row.FindControl("LotId")).Text;
string magazineId = ((Label)row.FindControl("MagazineId")).Text;
// 顯示詳細資訊
//Response.Write("<script>alert('LotId: " + lotId + ", MagazineId: " + magazineId + "');</script>");
}
}
private void ShowDetails(int id)
{
// 彈窗handler
string message = $"彈窗{id}";
// 測試call bootstrap modal
Response.Write("<script>alert('" + message + "');</script>");
}
protected void btnSubmit_Click(object sender, EventArgs e)
{
// 拿出選中的資料
foreach (GridViewRow row in GridView1.Rows)
{
CheckBox chkSelect = (CheckBox)row.FindControl("chkSelect");
if (chkSelect != null && chkSelect.Checked)
{
// 獲取行ID
int id = Convert.ToInt32(GridView1.DataKeys[row.RowIndex].Value);
// 執行Release Handler
HandleSelectedData(id);
}
}
}
//後端Release處理
private void HandleSelectedData(int id)
{
// 模拟执行处理
Response.Write("<script>alert('處理 " + id + " 的資料');</script>");
}
protected void ReleaseSearchBtn_Click(object sender, EventArgs e)
{
string releaseItem = string.Empty;
try
{
List<ReleaseRow> searchReleaseData = new List<ReleaseRow>();
//DateBase Call
if (ReleaseItem.SelectedItem.ToString() == "LotId")
{
searchReleaseData = DataBase.Where(item => item.LotId == ReleaseId.Text).ToList();
}
if (ReleaseItem.SelectedItem.ToString() == "MagazineId")
{
searchReleaseData = DataBase.Where(item => item.MagazineId == ReleaseId.Text).ToList();
}
List<ReleaseRow> updateData = (List<ReleaseRow>)ViewState["releaseData"] ?? new List<ReleaseRow>();
foreach (ReleaseRow item in searchReleaseData)
{
updateData.Add(item);
}
List<ReleaseRow> distinctList = updateData
.GroupBy(item => new { item.LotId, item.MagazineId })
.Select(group => group.First())
.ToList();
Console.WriteLine(distinctList);
ViewState["releaseData"] = distinctList;
UpdateReleaseGridView();
//var listData = DataBase.Where(item => x.LotId == ReleaseId.Text).ToList();
//ReleaseId.Text
//search DataBase
ReleaseId.Focus();
}
catch (Exception ex)
{
Console.WriteLine(ex);
}
}
}
```
## Demo
```=css
*,
*::after,
*::before {
padding: 0;
margin: 0;
box-sizing: border-box;
font-family: Arial, Helvetica, sans-serif;
}
body::before {
content: '';
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
/* background: linear-gradient(180deg, rgb(21, 19, 59), rgb(132, 130, 209)); */
background-color: #fafbffff;
z-index: -1;
}
/* width */
::-webkit-scrollbar {
width: 0.5rem;
}
/* Track */
::-webkit-scrollbar-track {
box-shadow: inset 0 0 5px grey;
border-radius: 0.25rem;
}
/* Handle */
::-webkit-scrollbar-thumb {
background: rgb(62, 59, 135);
border-radius: 0.25rem;
transition: all 0.3s ease-in;
}
/* Handle on hover */
::-webkit-scrollbar-thumb:hover {
background: rgb(51, 47, 170);
}
ul {
list-style: none;
}
.logo {
display: flex;
align-items: center;
}
.logo-text {
font-size: large;
}
.logo-img {
position: relative;
}
.img-1 {
max-height: 56px;
position: relative;
top: 0;
object-fit: cover;
}
.img-2 {
max-height: 56px;
object-fit: cover;
position: absolute;
left: 50%;
}
.svg {
pointer-events: none;
}
input {
all: unset;
position: relative;
}
input::placeholder {
font-weight: bold;
font-size: large;
}
button {
all: unset;
cursor: pointer;
}
a {
display: block;
}
.ft-white {
color: white;
}
.bg-primary {
background-color: rgb(10, 8, 59);
}
.font-white {
color: white;
}
.log-image {
width: 48px;
height: 48px;
object-fit: cover;
}
.container {
max-width: 95%;
/* padding-left: 12px; */
/* padding-right: 12px; */
margin: 0 auto;
}
.header {
position: sticky;
top: 0;
padding-right: 24px;
padding-left: 24px;
padding-top: 0.5rem;
padding-bottom: 0.5rem;
display: flex;
align-items: center;
gap: 2rem;
box-shadow: 0 4px 8px 0 rgba(0, 0, 0, 0.2), 0 6px 20px 0 rgba(0, 0, 0, 0.19);
}
.btn {
padding: 0.25rem 0.5rem;
border-radius: 0.25rem;
background-color: rgb(62, 59, 135);
}
.btn:hover {
background-color: rgb(51, 47, 170);
}
.nav-bar_list[disabled='true'] {
position: relative;
pointer-events: none;
}
.nav-bar_list[disabled='true']::after {
display: block;
position: absolute;
content: '';
background-color: gray;
border-radius: 0.25rem 0.25rem 0 0;
opacity: 0.8;
top: 0;
right: 0;
bottom: 0;
left: 0;
}
.nav-bar_list[disabled='true'] .list-item input {
color: gray;
}
.nav-bar {
display: flex;
flex-wrap: wrap;
gap: 1rem;
}
.ml-auto {
margin-left: auto;
}
.nav-bar_list {
border-bottom: 2px solid gray;
}
.nav-bar_list:hover {
border-bottom: 2px solid rgb(86, 81, 225);
}
.nav-bar_list .list-item {
background-color: transparent;
border-radius: 0.25rem;
padding: 0.5rem 0.5rem;
transition: all 0.25s ease-in;
cursor: pointer;
}
.nav-bar_list .list-item:hover {
background-color: rgb(62, 59, 135);
}
.input-box {
padding: 0.5rem 0.5rem;
}
.arrow::after {
content: '▼'; /* Unicode 向下箭頭 */
font-size: 12px;
margin-left: 5px;
}
.nav-bar_list {
position: relative;
transition: all 0.25s ease-in;
}
.nav-bar_list ul {
position: absolute;
color: white;
top: 105%;
display: flex;
flex-direction: column;
gap: 0.25rem;
padding: 0.5rem;
list-style: none;
background-color: rgb(10, 8, 59);
box-shadow: 0px 4px 6px rgba(0, 0, 0, 0.1);
border-radius: 5px;
right: 0;
left: 0;
opacity: 0;
transform: translateY(-10px);
transition: all 0.3s ease;
z-index: 20;
visibility: hidden;
max-height: 220px;
overflow-y: scroll;
}
/* 顯示下拉內容 */
.nav-bar_list:hover ul {
opacity: 1;
visibility: visible;
transform: translateY(0);
}
.user-section {
display: flex;
align-items: center;
gap: 0.25rem;
}
.user-section p {
color: white;
}
.avatar {
width: 50px;
height: 50px;
border-radius: 50%;
max-width: 100%;
max-height: 100%;
object-fit: contain;
}
/* navbar-上的按鈕 */
.search-section {
position: relative;
}
.search-btn {
padding: 0.25rem 0.5rem;
border-radius: 0.25rem;
background-color: transparent;
transition: all 0.3 ease;
}
.search-btn:hover {
background-color: rgb(62, 59, 135);
}
.search-btn:hover .search-filter {
background-color: rgb(62, 59, 135);
}
/* btn 叫出視窗效果 */
.search-filter.showFilter {
min-width: 320px;
min-height: 36px;
opacity: 1;
visibility: visible;
}
/* 按下搜索 Btn 的方框 */
.search-filter {
min-width: 0;
min-height: 0;
overflow: hidden;
opacity: 0;
visibility: hidden;
background-color: rgb(10, 8, 59);
position: absolute;
border: 1px solid gray;
padding: 0.5rem;
right: 0;
transition: all 0.75s ease;
}
.search-input {
all: unset;
display: block;
border-bottom: 1px solid white;
width: 100%;
color: white;
font-size: 1.25rem;
}
.search-input-icon {
position: absolute;
right: 0.5rem;
}
/* 機台列表 */
.line-area {
display: flex;
flex-direction: column;
gap: 2rem;
}
.mach-card__List {
display: flex;
gap: 2rem;
box-shadow: 0 20px 25px -5px rgb(0 0 0 / 0.1),
0 8px 10px -6px rgb(0 0 0 / 0.1);
border: 1px solid rgb(233, 233, 233);
border-radius: 0.75rem;
padding: 1rem;
}
.mach-card {
box-shadow: 0 20px 25px -5px rgb(0 0 0 / 0.1),
0 8px 10px -6px rgb(0 0 0 / 0.1);
border: 1px solid rgb(233, 233, 233);
padding: 0.5rem;
}
.line-title {
display: inline-block;
border-radius: 0.25rem;
padding: 0.25rem;
margin-bottom: 0.75rem;
box-shadow: 0 20px 25px -5px rgb(0 0 0 / 0.1),
0 8px 10px -6px rgb(0 0 0 / 0.1);
border: 1px solid rgb(233, 233, 233);
}
.mt-40 {
margin-top: 40px;
}
```
# JS
```
////////utils///////////
//call api
async function getData(methodName, method = 'GET', data = {}) {
if (!methodName) return;
const domain = 'http://localhost:3000/'; //EQP_DashBoard.aspx/
const setting = {
method, //POST
headers: {
'Content-Type': 'application/json',
},
};
if (method === 'POST') {
setting.body = JSON.stringify(data);
}
try {
const res = await fetch(`${domain}${methodName}`, setting);
const data = await res.json();
if (!data?.d) throw Error('找不到data');
return data?.d;
// return JSON.parse(data?.d);
} catch (err) {
console.error(`[${methodName} Error] ${err}`);
}
}
class NavBarDropDownList {
constructor(containerClass, name, initData) {
this.containerClass = containerClass;
this.name = name;
this.state = {};
this.create(initData);
}
init(data) {
this.ItemList.innerHTML = '';
this.input.value = '';
this.disable(false);
if (data) this.setListItems(data);
}
create(initData) {
//createElement
this.container = document.querySelector(`.${this.containerClass}`);
this.machBox = document.createElement('div');
this.inputBox = document.createElement('div');
this.input = document.createElement('input');
this.ItemList = document.createElement('ul');
this.machBox.classList.add('nav-bar_list');
this.inputBox.classList.add('input-box', 'arrow', 'font-white');
//input setting
this.input.type = 'text';
this.input.placeholder = this.name;
this.input.oninput = (e) => this.onInputHandler(e);
this.machBox.onclick = (e) => this.onClickHandler(e);
this.inputBox.append(this.input);
///init item list
this.setListItems(initData);
//append mach component div
this.machBox.append(this.inputBox);
this.machBox.append(this.ItemList);
//final append dom to html
this.container.append(this.machBox);
}
//設定下拉選單顯示data
setListItems(data) {
if (!data?.length) return;
this.ItemList.innerHTML = '';
data?.forEach((mach) => {
const li = document.createElement('li');
li.classList.add('list-item');
li.textContent = mach;
this.ItemList.append(li);
});
this.machBox.append(this.ItemList);
}
addSearchFilter(outFilterData, targetValue) {
this.input.value = targetValue;
this.disable(true);
outFilterData[this.name] = targetValue;
}
//切換 input disable 樣式
disable(isDisable) {
this.machBox.setAttribute('disabled', isDisable);
}
//click callback
onClickHandler = (e) => {
if (this.clickCallBack) {
this.clickCallBack(e);
}
};
onClickHandlerCallBack = (cb) => {
this.clickCallBack = cb;
};
//input callback
onInputHandler = (e) => {
if (this.inputCallback) {
this.inputCallback(e);
}
};
onInputHandlerCallback(cb) {
this.inputCallback = cb;
}
}
//搜索 Array 顯示邏輯
function searchItems(arr, searchWord) {
const filterItems = [...arr].filter((item) =>
item.toUpperCase().includes(searchWord.toUpperCase())
);
if (searchWord.length === 0) {
return arr;
}
return filterItems;
}
//Avatar 頭像區域
async function avatarCreate() {
const empData = await getData('GetEmpData');
const empName = document.querySelector('.empName');
const avatar = document.querySelector('.avatar');
empName.textContent = empData?.empName;
// avatar.setAttribute(
// 'src',
// `https://myvf.kh.asegroup.com/utility/get_emp_photo.asp?emp_no=${empData?.empNo}`
// );
}
////////主程式///////////
async function main() {
//def
let filterData = {}; //[feature] 這裡之後要改成, url search ?=...
const buildDropList = new NavBarDropDownList('mach-list', '棟別');
const floorDropList = new NavBarDropDownList('mach-list', '樓層');
//origin data
const areaData = await getData('initDropDownData');
const buildListData = Object.keys(areaData).map((item) => item);
buildDropList.setListItems(buildListData);
// 搜索邏輯
buildDropList.onInputHandlerCallback((e) => {
const searchWord = e.target.value;
buildDropList.setListItems(searchItems(buildListData, searchWord));
});
buildDropList.onClickHandlerCallBack((e) => {
if (e.target.classList.contains('list-item')) {
const target = e.target.textContent;
buildDropList.addSearchFilter(filterData, target);
floorDropList.setListItems(areaData[target]);
}
});
floorDropList.onInputHandlerCallback((e) => {
const searchWord = e.target.value;
if (areaData[filterData[buildDropList.name]]) {
floorDropList.setListItems(
searchItems(areaData[filterData[buildDropList.name]], searchWord)
);
}
});
floorDropList.onClickHandlerCallBack((e) => {
const target = e.target.textContent;
if (e.target.classList.contains('list-item')) {
floorDropList.addSearchFilter(filterData, target);
}
});
//search 搜索關鍵字Search bar
//search button
document.querySelector('.search-btn').addEventListener('click', (e) => {
const filter = document.querySelector('.search-filter');
filter.classList.toggle('showFilter');
});
// 搜索下方 Tree Table
document.querySelector('.search-input').addEventListener('input', (e) => {
const keyword = e.target.value;
console.log(filterData);
if (
Object.keys(filterData)?.map((item) => filterData?.[item] !== '')
?.length === 2
) {
console.log('call API', filterData);
}
});
//clear filter
document.querySelector('.filterclearBtn').addEventListener('click', (e) => {
buildDropList.init(buildListData);
floorDropList.init();
filterData = {};
});
}
main();
```
```
```
```
```
## NavBar Demo
```
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Demo Navbar</title>
<link rel="stylesheet" href="style.css" />
</head>
<body>
<section class="bg-primary">
<header class="header container">
<!-- Logo -->
<h1 class="font-white">Logo</h1>
<!-- nav list -->
<nav class="nav-bar mach-list"></nav>
<!-- search btn -->
<div class="ml-auto search-section">
<button class="search-btn" type="button">
<!-- 放大鏡ICON -->
<svg
stroke="white"
fill="white"
stroke-width="1"
version="1.1"
id="search"
x="0px"
y="0px"
viewBox="0 0 24 24"
height="24px"
width="24px"
xmlns="http://www.w3.org/2000/svg"
>
<g>
<path
d="M20.031,20.79c0.46,0.46,1.17-0.25,0.71-0.7l-3.75-3.76c1.27-1.41,2.04-3.27,2.04-5.31
c0-4.39-3.57-7.96-7.96-7.96s-7.96,3.57-7.96,7.96c0,4.39,3.57,7.96,7.96,7.96c1.98,0,3.81-0.73,5.21-1.94L20.031,20.79z
M4.11,11.02c0-3.84,3.13-6.96,6.96-6.96c3.84,0,6.96,3.12,6.96,6.96c0,3.84-3.12,6.96-6.96,6.96C7.24,17.98,4.11,14.86,4.11,11.02
z"
></path>
</g>
</svg>
</button>
<div class="search-filter">
<!-- 放大鏡ICON -->
<div class="search-input-icon">
<svg
stroke="white"
fill="white"
stroke-width="1"
version="1.1"
id="search"
x="0px"
y="0px"
viewBox="0 0 24 24"
height="12px"
width="12px"
xmlns="http://www.w3.org/2000/svg"
>
<g>
<path
d="M20.031,20.79c0.46,0.46,1.17-0.25,0.71-0.7l-3.75-3.76c1.27-1.41,2.04-3.27,2.04-5.31
c0-4.39-3.57-7.96-7.96-7.96s-7.96,3.57-7.96,7.96c0,4.39,3.57,7.96,7.96,7.96c1.98,0,3.81-0.73,5.21-1.94L20.031,20.79z
M4.11,11.02c0-3.84,3.13-6.96,6.96-6.96c3.84,0,6.96,3.12,6.96,6.96c0,3.84-3.12,6.96-6.96,6.96C7.24,17.98,4.11,14.86,4.11,11.02
z"
></path>
</g>
</svg>
</div>
<input class="search-input" placeholder="搜索關鍵字" type="text" />
</div>
</div>
<!-- user avatar -->
<section class="user-section">
<img
class="avatar"
src="https://myvf.kh.asegroup.com/utility/get_emp_photo.asp?emp_no=K14814"
alt="user-avatar"
/>
<p>username</p>
</section>
</header>
</section>
<button class="getBtn">setExsample</button>
<button class="clearBtn">clearExsample</button>
<script src="./app.js"></script>
</body>
</html>
```
```
// 各元件產生function
/**
*
* @param {*} className
* @param {*} name
* @param {*} list
* @returns {Array} [HTMLDOM, targetString]
*/
function navDropDownList(className, name, list) {
const container = document.querySelector(`.${className}`);
const machList = document.createElement("div");
const btn = document.createElement("button");
const ul = document.createElement("ul");
let targetItem = { [`${name}`]: "" };
const setValueHandler = (value) => {
if (!value) return targetItem;
targetItem = { [`${name}`]: value };
btn.textContent = value;
return targetItem;
};
const clearValueHandler = () => {
btn.textContent = name;
targetItem = { [`${name}`]: "" };
};
machList.classList.add("nav-bar_list");
btn.classList.add("arrow", "list-item", "font-white");
btn.textContent = name;
list.forEach((mach) => {
const li = document.createElement("li");
li.classList.add("list-item");
li.textContent = mach;
li.onclick = handler;
function handler(e) {
let item = e?.target?.textContent;
btn.textContent = item;
targetItem = item;
targetItem = {
[`${name}`]: item,
};
}
ul.append(li);
});
machList.append(btn);
machList.append(ul);
container.append(machList);
return [setValueHandler, clearValueHandler];
}
////////////////////////////使用範例/////////////////////////////////
// 範例一:產生下拉選單範例
const [setList1Value, clearList1Value] = navDropDownList("mach-list", "區域", [
"test1",
"test2",
]);
const [setList2Value, clearList2Value] = navDropDownList("mach-list", "樓層", [
"test1",
"test2",
]);
const [setList3Value, clearList3Value] = navDropDownList("mach-list", "群組", [
"test1",
"test2",
]);
// 範例二: 拿到下拉選單目前, 選中的值方法
document.querySelector(".getBtn").addEventListener("click", (e) => {
let value1 = setList1Value("123");
let value2 = setList2Value("13123");
let value3 = setList3Value("2222");
console.log(value1, value2, value3);
});
// 範例三: 清除下拉選單的值
document.querySelector(".clearBtn").addEventListener("click", (e) => {
//清除
clearList1Value();
clearList2Value();
clearList3Value();
//單存拿到目前值 不要帶任何參數即可
let value1 = setList1Value();
let value2 = setList2Value();
let value3 = setList3Value();
console.log(value1, value2, value3);
});
//search 搜索關鍵字Search bar
document.querySelector(".search-btn").addEventListener("click", (e) => {
const filter = document.querySelector(".search-filter");
filter.classList.toggle("showFilter");
});
```
```
*,
*::after,
*::before {
padding: 0;
margin: 0;
box-sizing: border-box;
font-family: Arial, Helvetica, sans-serif;
}
svg {
pointer-events: none;
}
button {
all: unset;
cursor: pointer;
}
a {
display: block;
}
.ft-white {
color: white;
}
.bg-primary {
background-color: #3450c1;
}
.font-white {
color: white;
}
.container {
max-width: 1320px;
padding-left: 12px;
padding-right: 12px;
margin: 0 auto;
/* border: 1px solid black; */
}
.header {
padding-top: 0.5rem;
padding-bottom: 0.5rem;
display: flex;
align-items: center;
gap: 2rem;
}
.nav-bar {
display: flex;
gap: 1rem;
}
.ml-auto {
margin-left: auto;
}
.nav-bar_list .list-item {
background-color: transparent;
border-radius: 0.25rem;
padding: 0.5rem 0.5rem;
transition: all 0.25s ease-in;
cursor: pointer;
}
.nav-bar_list .list-item:hover {
background-color: rgba(140, 140, 140, 0.5);
}
.arrow::after {
content: "▼"; /* Unicode 向下箭頭 */
font-size: 12px;
margin-left: 5px;
}
.nav-bar_list {
position: relative;
transition: all 0.25s ease-in;
}
.nav-bar_list ul {
position: absolute;
top: 105%;
display: flex;
flex-direction: column;
gap: 0.25rem;
padding: 0.5rem;
list-style: none;
background-color: white;
box-shadow: 0px 4px 6px rgba(0, 0, 0, 0.1);
border-radius: 5px;
visibility: hidden;
/* overflow: hidden; */
opacity: 0;
transform: translateY(-10px);
transition: all 0.3s ease;
}
/* 顯示下拉內容 */
.nav-bar_list:hover ul {
opacity: 1;
visibility: visible;
transform: translateY(0);
}
.user-section {
display: flex;
align-items: center;
gap: 0.25rem;
}
.user-section p {
color: white;
}
.avatar {
width: 48px;
height: 48px;
border-radius: 100%;
object-fit: cover;
}
/* navbar-上的按鈕 */
.search-section {
position: relative;
}
.search-btn {
padding: 0.25rem 0.5rem;
border-radius: 0.25rem;
transition: all 0.3 ease;
}
.search-btn:hover .search-filter {
background-color: rgba(140, 140, 140, 0.5);
}
/* btn 叫出視窗效果 */
.search-filter.showFilter {
min-width: 320px;
min-height: 36px;
opacity: 1;
visibility: visible;
}
/* 按下搜索 Btn 的方框 */
.search-filter {
min-width: 0;
min-height: 0;
overflow: hidden;
opacity: 0;
visibility: hidden;
background-color: #3450c1;
position: absolute;
border: 1px solid gray;
padding: 0.5rem;
right: 0;
transition: all 0.75s ease;
}
.search-input {
all: unset;
display: block;
border-bottom: 1px solid white;
width: 100%;
color: white;
font-size: 1.25rem;
}
.search-input-icon {
position: absolute;
right: 0.5rem;
}
```
```
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Vite App</title>
<link rel="stylesheet" href="style.css" />
</head>
<body>
<div id="app">
<div class="cardView header"></div>
</div>
<script type="module" src="/main.js"></script>
</body>
</html>
```
```
.container {
max-width: 1140px;
padding-left: 16px;
padding-right: 16px;
margin-right: 8px;
margin-left: 8px;
}
.cardView {
display: flex;
gap: 1.25rem;
flex-wrap: wrap;
}
.card {
cursor: pointer;
max-width: 256px;
}
.list {
max-height: 0;
transform: scaleY(0);
transform-origin: top;
display: flex;
flex-direction: column;
gap: 0.25rem;
overflow: hidden;
border-left: 6px solid #662d8c;
padding-left: 0.8rem;
transition: all 0.15s ease-in;
}
.list-active {
max-height: fit-content;
transform: scaleY(100%);
}
.list li {
list-style: none;
font-size: 1.25rem;
border-radius: 0.25rem;
padding: 0.25rem 0.5rem;
background-color: #ed1e79;
color: white;
}
.btn {
all: unset;
color: white;
font-weight: 700;
font-size: 1.25rem;
position: relative;
background: transparent;
padding: 0.5rem 1rem;
border-radius: 0.15rem;
box-shadow: 10px 10px 20px rgba(0, 0, 0, 0.2);
border-radius: 0.25rem;
background: linear-gradient(45deg, #662d8c, #ed1e79);
}
.btn:hover {
animation: Animation 0.25s ease;
}
```
```
const data = [
{ root: 'root1', machExs: ['item1', 'item2'] },
,
{ root: 'root2', machExs: ['item1', 'item2'] },
{ root: 'root2', machExs: ['item1', 'item2'] },
{ root: 'root2', machExs: ['item1', 'item2'] },
{ root: 'root2', machExs: ['item1', 'item2'] },
{ root: 'root2', machExs: ['item1', 'item2'] },
{ root: 'root2', machExs: ['item1', 'item2'] },
{ root: 'root2', machExs: ['item1', 'item2'] },
{ root: 'root2', machExs: ['item1', 'item2'] },
{ root: 'root2', machExs: ['item1', 'item2'] },
{ root: 'root2', machExs: ['item1', 'item2'] },
{ root: 'root2', machExs: ['item1', 'item2'] },
{ root: 'root2', machExs: ['item1', 'item2'] },
{ root: 'root2', machExs: ['item1', 'item2'] },
{ root: 'root2', machExs: ['item1', 'item2'] },
{ root: 'root2', machExs: ['item1', 'item2'] },
];
function cardView(data) {
const container = document?.querySelector('.cardView');
if (!container) {
throw Error('element class name:cardView, not found!');
}
data.forEach((cardData) => {
const card = document.createElement('div');
const btn = document.createElement('button');
const list = document.createElement('ul');
card.classList.add('card');
btn.classList.add('btn');
list.classList.add('list');
btn.textContent = cardData?.root;
btn.addEventListener('click', (e) => {
const target = e.target.parentElement;
const list = target.children[1];
list.classList.toggle('list-active');
target.classList.toggle('card-active');
});
cardData?.machExs.forEach((it) => {
const listItem = document.createElement('li');
const link = document.createElement('a');
listItem.classList.add('item');
link.classList.add('link');
listItem.textContent = it;
list.append(listItem);
});
card.append(btn, list);
container.append(card);
});
}
cardView(data);
```
windows 11 vb open IE
https://www.perplexity.ai/
https://github.com/jgraph/drawio-desktop/releases/tag/v24.6.1
```
const fs = require('node:fs');
const str = fs.readFileSync('./test.json', 'utf-8', (err) => console.log(err));
const data = JSON.parse(str);
console.log(data?.results[0].columns);
const TABLE_NAME = 'TABLE_NAME';
const columnDefine = data?.results[0].columns;
const dataItems = data?.results[0].items;
dataItems.forEach((it) => {
//Number -> 不用單引號
//DATE -> to_DATE();
//VARCHAR2
switch (key) {
case 'DATE':
break;
case 'VARCHAR2':
break;
case 'NUMBER':
break;
default:
console.error('請檢查JS欄位定義有缺少');
break;
}
});
```
IE11.vbs
```vb=
CreateObject("InternetExplorer.Application").Visible=true
```
```javascript=
$(document).ready(function(){
$("#openModal").click(function(){
$("#myModal").modal({
backdrop: 'static',
keyboard: false
});
});
});
```
```csharp=
ScriptManager.RegisterStartupScript(this, this.GetType(), "model", "window.addEventListener('load', function () {const modal = new bootstrap.Modal(document.getElementById('exampleModal'));modal.show();});", true);
```
```htmlembedded=
<!-- Button trigger modal -->
<asp:Button type="button" class="btn btn-primary" Text="Model" runat="server" OnClick="Unnamed3_Click"/>
<!-- Modal -->
<div class="modal fade" id="exampleModal" tabindex="-1" aria-labelledby="exampleModalLabel" aria-hidden="true">
<div class="modal-dialog modal-dialog-centered">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="exampleModalLabel">Modal title</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">×</span>
</button>
</div>
<div class="modal-body">
<asp:Button type="button" class="btn btn-primary" Text="Q" runat="server"/>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
<button type="button" class="btn btn-primary">Save changes</button>
</div>
</div>
</div>
</div>
```
https://blog.csdn.net/zhu_zhu_xia/article/details/132354488

-------------------------------------------------
JavaScirpt Call C# using PageMethods (ajax)
要確定是否啟用 FriendlyUrlSetting()
RouteConfig.cs -> 看要沒有註解掉它
```csharp=
//routes.EnableFriendlyUrls(settings);
```
-------------------------------------------------
自動化工具筆記 Electron
https://electron-vite.org/guide/
https://tailwindcss.com/docs/installation/using-postcss
https://ui.shadcn.com/docs/installation/vite
-------------------------------------------
myOA -> Self Service -> 居家辦公SSLVPN -> 個人家用電腦
----------------------
## 表達式 目標範例
20240616140200>><S:XXXXXXX><C:XXXXXXXX-WXX> | XXXXXXXXXXX | MESAGE
## 一. 文字辨識
1. 辨認日期
2. Server name
3. Clinet 裝置名稱
4. Sequence(編碼)
5. 訊息
- (Eazy)辨認時間: 取得數字為固定14碼時間
```
\d{14}
```
- (Eazy)辨認Server name
```
(?<=<S:)[^>]+
```
- (Eazy)辨認Client name
```
(?<=<C:)[^>]+
```
- (Hard)辨認Sch: 字串前後為非英文及數字的6 或 9 長度字串
```javascript=
/*
* 這個正則表達式解釋如下:
(?<![a-zA-Z0-9]) 確保字串前不是英文或數字。
(?=\w*[a-zA-Z]) 確保字串中至少包含一個字母。
(?=\w*\d) 確保字串中至少包含一個數字。
\w{6} 或 \w{9} 表示字串長度為6或9。
(?![a-zA-Z0-9]) 確保字串後不是英文或數字。
*
* */
const regex = /(?<![a-zA-Z0-9])(?=\w*[a-zA-Z])(?=\w*\d)\w{6}(?![a-zA-Z0-9])|(?<![a-zA-Z0-9])(?=\w*[a-zA-Z])(?=\w*\d)\w{9}(?![a-zA-Z0-9])/g;
```
## 二. 內部寄信
1. nodemailer
```javascript=
const transporter = nodemailer.createTransport({
host: "smtp.forwardemail.net",
port: 465,
secure: true,
auth: {
// TODO: replace `user` and `pass` values from
//<https://forwardemail.net>
user: 'REPLACE-WITH-YOUR-ALIAS@YOURDOMAIN.COM',
pass: 'REPLACE-WITH-YOUR-GENERATED-PASSWORD'
}
});
```
## 三.Server 資料夾內文件讀寫流程
1. 複製檔案至新資料夾ServerLogBak
2. 建立JSON來讀取, 紀錄上次讀取
- normal -> 依照日期時間排序 整理檔案
- 中途關閉 -> 讀取紀錄為reading 的檔案, 砍掉再來一遍
```json=
[
{
fileName:'XXXXXX.log',
createAt: '',
status:'', // start, reading, end
}
]
```
## 程式執行時間規則
1. 每次執行主程式紀錄起始時間
- Case 1 程式執行完成後總結時間低於1小時, 等待一小時後重新執行
- Case 2 執行程式超過等於1小時直接執行
## 環境變設置
1. 定時多長時間執行一次
2. config.env 若可以跨Server 建立一個做統整
3. 不行by server 放置15個
-----
瘋狂版
```javascript=
const fs = require("node:fs");
const readline = require("node:readline");
const fsWrite = fs.createWriteStream("output.txt");
const fileStream = fs.createReadStream(
"C:\\Users\\s3394\\OneDrive\\桌面\\wirteText\\large_log_file.txt",
{
highWaterMark: 16 * 1024, // 16KB
}
);
const rl = readline.createInterface({
input: fileStream,
crlfDelay: Infinity,
});
rl.on("line", (line) => {
// console.log(`Received: ${line}`);
fsWrite.write(`mod ${line}\n`);
});
rl.on("close", () => {
console.log("File reading completed.");
});
```
CPU 等等版
```javascript=
const fs = require("node:fs");
const readline = require("node:readline");
const fsWrite = fs.createWriteStream("output.txt");
const fileStream = fs.createReadStream(
"C:\\Users\\s3394\\OneDrive\\桌面\\wirteText\\large_log_file.txt",
{
highWaterMark: 16 * 1024, // 16KB
}
);
const rl = readline.createInterface({
input: fileStream,
crlfDelay: Infinity,
});
rl.on("line", (line) => {
rl.pause(); // 暫停接收新的行
setTimeout(() => {
const modifiedLine = `Modified: ${line}\n`;
fsWrite.write(modifiedLine);
rl.resume(); // 繼續接收新的行
}, 10); // 增加延遲以減少 CPU 使用
});
rl.on("close", () => {
console.log("File reading completed.");
});
```
```javascript=
const fs = require('fs');
const path = require('path');
const directoryPath = path.join(__dirname, 'your-directory-name');
fs.readdir(directoryPath, (err, files) => {
if (err) {
console.log('無法讀取目錄: ', err);
return;
}
files.forEach(file => {
console.log(file); // 這裡你可以獲取到檔案名,如果需要完整路徑可以使用 path.join(directoryPath, file)
});
});
```
```javascript=
const fs = require("fs");
const path = require("path");
const directoryPath = "C:\\Users\\s3394\\OneDrive\\桌面\\wirteText";
try {
const files = fs.readdirSync(directoryPath);
files.forEach((item) => {
console.log(item);
fs.stat(path.join(directoryPath, item), (err, stats) => console.log(stats));
});
} catch (err) {
console.log("無法讀取目錄: ", err);
}
```
隨機產生LOG(不考慮中文做判斷), 做單元測試
```javascript=
const fs = require("node:fs");
const fsPromises = require("node:fs/promises");
const readline = require("node:readline");
//20240616140200>><S:XXXXXXX><C:XXXXXXXX-WXX> | XXXXXXXXXXX | MESAGE
//隨機文字
const CH = ["中1文", "中2文", "中3文"];
const ENG_UPPERCASE = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
const ENG_LOWERERCASE = "abcdefghijklmnopqrstuvwxyz";
//隨機數字
const getRadomInt = (len) => Math.floor(Math.random() * len);
//隨機產生Sch
function generateRandomSch(len) {
let result = "";
for (let index of Array.from(Array(len).keys())) {
result +=
getRadomInt(2) > 0
? getRadomInt(10)
: ENG_UPPERCASE[getRadomInt(ENG_UPPERCASE.length)];
}
return result;
}
//Time stemp
function generateTime() {
const date = new Date();
return (
date.toLocaleDateString().split("/").join("") +
date.toTimeString().split(" ")[0].split(":").join("") +
"0"
);
}
function generateTestLog() {
const taskCount = getRadomInt(99);
let msg = "";
for (let index of Array.from(Array(taskCount).keys())) {
getRadomInt(2) > 0
? (msg += ` ${generateRandomSch()} `)
: (msg += `${ENG_UPPERCASE[getRadomInt(ENG_UPPERCASE.length)]}`);
}
return `${generateTime()}>><S:Server${getRadomInt(14)}><C:CLient${getRadomInt(
17
)}> | |${msg}`;
}
console.log(generateTestLog());
console.log(generateTestLog());
```
```javascript=
const fs = require('fs');
const path = require('path');
function generateRandomLogEntry() {
const logLevels = ['INFO', 'WARN', 'ERROR', 'DEBUG'];
const messages = [
'User login successful',
'User login failed',
'Database connection established',
'Database connection failed',
'File not found',
'File uploaded successfully',
'Unauthorized access attempt',
'User password changed',
];
const timestamp = new Date().toISOString();
const logLevel = logLevels[Math.floor(Math.random() * logLevels.length)];
const message = messages[Math.floor(Math.random() * messages.length)];
return `[${timestamp}] ${logLevel}: ${message}\n`;
}
function generateLargeTextFile(filePath, sizeInMB) {
const sizeInBytes = sizeInMB * 1024 * 1024;
let totalWritten = 0;
const stream = fs.createWriteStream(filePath, { flags: 'w' });
function writeChunk() {
if (totalWritten < sizeInBytes) {
let chunk = '';
while (chunk.length < 1024 * 1024 && totalWritten + chunk.length < sizeInBytes) {
chunk += generateRandomLogEntry();
}
stream.write(chunk, () => {
totalWritten += chunk.length;
console.log(`Written ${Math.round(totalWritten / (1024 * 1024))} MB...`);
writeChunk();
});
} else {
stream.end();
console.log(`File ${filePath} generated with size ${Math.round(totalWritten / (1024 * 1024))} MB`);
}
}
writeChunk();
}
const filePath = path.join(__dirname, 'large_log_file.txt');
const sizeInMB = 500; // Set the size in MB
generateLargeTextFile(filePath, sizeInMB);
```
### 要求SRE 也使用 C# 轉譯版本
```csharp=
using System;
using System.IO;
using System.Threading.Tasks;
class Program
{
static async Task Main(string[] args)
{
string inputFilePath = @"C:\Users\s3394\OneDrive\桌面\wirteText\large_log_file.txt";
string outputFilePath = "output.txt";
using (var fsRead = new FileStream(inputFilePath, FileMode.Open, FileAccess.Read, FileShare.Read, 16 * 1024, FileOptions.SequentialScan))
using (var fsWrite = new StreamWriter(outputFilePath))
using (var sr = new StreamReader(fsRead))
{
string line;
while ((line = await sr.ReadLineAsync()) != null)
{
await Task.Delay(10); // 增加延遲以減少 CPU 使用
string modifiedLine = $"Modified: {line}";
await fsWrite.WriteLineAsync(modifiedLine);
}
}
Console.WriteLine("File reading completed.");
}
}
```