wujingjing
2025-04-10 007a654f16b56d356d14f781f9f09ada8982393a
scripts/helper.js
@@ -8,14 +8,20 @@
const scriptDir = __dirname;
const rootDir = path.resolve(scriptDir, '..');
const argv2 = process.argv[2];
const arg2 = argv2?.split(' ');
const customerList = arg2?.[0] ? (arg2[0] === 'pro' ? ['ch:pro'] : ['ch']) : ['ch'];
const customerList = argv2?.split(' ') ?? '';
const publicDir = path.join(rootDir, 'public');
const distDir = path.join(rootDir, 'dist');
const customerListDir = path.join(rootDir, 'customer_list');
const customerProjectListDir = path.join(rootDir, 'src', 'views', 'project');
const homeDir = os.homedir();
const firstCustomerName = customerList[0]?.split(':')[0];
/** 公共文件夹,所有客户文件夹共享文件 */
const commonDir = path.join(customerListDir, 'common');
 const item = customerList[0];
const customerSplit = item?.split(':');
const deployEnv = customerSplit?.[1];
// 是否为生产环境
const isPro = deployEnv==='pro';
// const deployEnv = process.argv[3];
const logColor = (text, color) => {
@@ -30,16 +36,27 @@
   logColor(text, 'green');
};
const logWarn = (text) => {
   logColor(text, 'yellow');
};
/**
 * 退出脚本
 */
const exit = () => {
   process.exit(1); // 退出脚本
};
/**
 * 检查文件是否存在
 * @param {*} file
 * @param {*} fileText
 */
const checkFileExist = (file, fileText) => {
const checkFileExist = (file, fileText = '') => {
   // 验证源文件夹是否存在
   if (!fs.existsSync(file)) {
      console.error(chalk.red(`${fileText} "${file}" 不存在!`));
      process.exit(1); // 退出脚本
      console.error(chalk.red(`${fileText ? fileText + ' ' : ''}"${file}" 不存在!`));
      exit(); // 退出脚本
   }
};
@@ -53,53 +70,127 @@
 * @param {*} command
 * @param {*} customer
 */
const checkCustomer = (command, customer) => {
const checkCustomer = (command, customer = firstCustomerName) => {
   if (!customer) {
      console.error(chalk.red(`请正确使用命令 “${command} [customer]” `));
      process.exit(1); // 退出脚本
      exit(); // 退出脚本
   }
   checkCustomerDirExist(customer);
};
let tmpBakDir = '';
const moveProjectsToBakDir = (command) => {
   const customer = customerList[0]?.split(':')[0];
   checkCustomer(command, customer);
   //#region ====================== 创建备份文件夹 ======================
   let tmpBakRootDir = path.join(homeDir, 'Desktop');
   if (!fs.existsSync(tmpBakRootDir)) {
      tmpBakRootDir = homeDir;
   }
   tmpBakDir = path.join(tmpBakRootDir, 'bak_project_list');
   fs.ensureDirSync(tmpBakDir);
   fs.emptyDirSync(tmpBakDir);
   //#endregion
   const contents = fs.readdirSync(customerProjectListDir);
   for (let index = 0; index < contents.length; index++) {
      const item = contents[index];
      if (item === customer) {
         continue;
      }
      const itemPath = path.join(customerProjectListDir, item);
      const stats = fs.statSync(itemPath);
      if (stats.isDirectory()) {
         const destBakDir = path.join(tmpBakDir, item);
         fs.moveSync(itemPath, destBakDir, { overwrite: true });
      }
   }
const replaceFileContent = (path, callback) => {
   const data = fs.readFileSync(path, 'utf8');
   if (!data) return;
   const newData = callback(data);
   fs.writeFileSync(path, newData, 'utf8');
};
const restoreProjectDir = () => {
   const contents = fs.readdirSync(tmpBakDir);
   for (let index = 0; index < contents.length; index++) {
      const item = contents[index];
      const itemPath = path.join(tmpBakDir, item);
      const destProjectDir = path.join(customerProjectListDir, item);
      fs.moveSync(itemPath, destProjectDir, { overwrite: true });
const replaceGlobImportPattern = /import.meta.glob\s*\((\s*.*\/views\/\*\*.*)\)/;
const matchAllPattern = '../views/**/*.{vue,tsx}';
/**
 * 修改 src/router/backEnd.ts 文件,只导入当前项目文件
 * @param {*} command
 */
const updateImportGlob = () => {
   const backEndFilePath = path.join(rootDir, 'src', 'router', 'backEnd.ts');
   checkFileExist(backEndFilePath, `${backEndFilePath}文件`);
   const subFile = fs.readdirSync(customerListDir);
   const filterSubFile = subFile?.filter((item) => item !== firstCustomerName);
   replaceFileContent(backEndFilePath, (data) => {
      const excludeCustomer = filterSubFile && filterSubFile.length > 0 ? `/(${filterSubFile.join('|')})` : '';
      const excludePattern = `!../views/project${excludeCustomer}/**/*`;
      const replaceStr = `import.meta.glob(['${matchAllPattern}', '${excludePattern}'])`;
      const newData = data.replace(replaceGlobImportPattern, replaceStr);
      return newData;
   });
};
const restoreImportGlob = () => {
   const backEndFilePath = path.join(rootDir, 'src', 'router', 'backEnd.ts');
   checkFileExist(backEndFilePath, `${backEndFilePath}文件`);
   replaceFileContent(backEndFilePath, (data) => {
      const replaceStr = `import.meta.glob('${matchAllPattern}')`;
      const newData = data.replace(replaceGlobImportPattern, replaceStr);
      return newData;
   });
};
/**
 * 获取当前日期是第几周
 * @param dateTime 当前传入的日期值
 * @returns 返回第几周数字值
 */
const getWeek = (dateTime) => {
   const temptTime = new Date(dateTime.getTime());
   // 周几
   const weekday = temptTime.getDay() || 7;
   // 周1+5天=周六
   temptTime.setDate(temptTime.getDate() - weekday + 1 + 5);
   let firstDay = new Date(temptTime.getFullYear(), 0, 1);
   const dayOfWeek = firstDay.getDay();
   let spendDay = 1;
   if (dayOfWeek != 0) spendDay = 7 - dayOfWeek + 1;
   firstDay = new Date(temptTime.getFullYear(), 0, 1 + spendDay);
   const d = Math.ceil((temptTime.valueOf() - firstDay.valueOf()) / 86400000);
   const result = Math.ceil(d / 7);
   return result;
};
/**
 * 时间日期转换
 * @param date 当前时间,new Date() 格式
 * @param format 需要转换的时间格式字符串,默认值YYYY-mm-dd HH:MM:SS
 * @description format 字符串随意,如 `YYYY-mm、YYYY-mm-dd`
 * @description format 季度:"YYYY-mm-dd HH:MM:SS QQQQ"
 * @description format 星期:"YYYY-mm-dd HH:MM:SS WWW"
 * @description format 几周:"YYYY-mm-dd HH:MM:SS ZZZ"
 * @description format 季度 + 星期 + 几周:"YYYY-mm-dd HH:MM:SS WWW QQQQ ZZZ"
 * @returns 返回拼接后的时间字符串
 */
const formatDate = (date, format = 'YYYY-mm-dd HH:MM:SS') => {
   const we = date.getDay(); // 星期
   const z = getWeek(date); // 周
   const qut = Math.floor((date.getMonth() + 3) / 3).toString(); // 季度
   const opt = {
      'Y+': date.getFullYear().toString(), // 年
      'm+': (date.getMonth() + 1).toString(), // 月(月份从0开始,要+1)
      'd+': date.getDate().toString(), // 日
      'H+': date.getHours().toString(), // 时
      'M+': date.getMinutes().toString(), // 分
      'S+': date.getSeconds().toString(), // 秒
      'q+': qut, // 季度
   };
   // 中文数字 (星期)
   const week = {
      0: '日',
      1: '一',
      2: '二',
      3: '三',
      4: '四',
      5: '五',
      6: '六',
   };
   // 中文数字(季度)
   const quarter = {
      1: '一',
      2: '二',
      3: '三',
      4: '四',
   };
   if (/(W+)/.test(format))
      format = format.replace(RegExp.$1, RegExp.$1.length > 1 ? (RegExp.$1.length > 2 ? '星期' + week[we] : '周' + week[we]) : week[we]);
   if (/(Q+)/.test(format)) format = format.replace(RegExp.$1, RegExp.$1.length == 4 ? '第' + quarter[qut] + '季度' : quarter[qut]);
   if (/(Z+)/.test(format)) format = format.replace(RegExp.$1, RegExp.$1.length == 3 ? '第' + z + '周' : z + '');
   for (const k in opt) {
      const r = new RegExp('(' + k + ')').exec(format);
      // 若输入的长度不为1,则前面补零
      if (r) format = format.replace(r[1], RegExp.$1.length == 1 ? opt[k] : opt[k].padStart(RegExp.$1.length, '0'));
   }
   return format;
};
/**
@@ -108,9 +199,7 @@
 * @param {*} command
 * @param {*} customer
 */
function copyFile(command) {
   const customer = customerList[0]?.split(':')[0];
   checkCustomer(command, customer);
function copyFile() {
   // 确保 public 文件,不存在则创建
   fs.ensureDirSync(publicDir);
   // 清空 public 文件夹
@@ -127,10 +216,10 @@
      return true;
   };
   const customerDir = path.join(customerListDir, customer);
   const customerDir = path.join(customerListDir, firstCustomerName);
   // 复制源文件夹中的所有文件到 public 文件夹
   fs.copySync(customerDir, publicDir, { filter });
   fs.copySync(commonDir, publicDir);
}
/**
@@ -150,7 +239,7 @@
      // 读取 JSON 文件
      const config = await fs.readJson(deployJSON).catch((err) => {
         console.error(`读取配置文件“${deployJSON}”出错:`, err);
         process.exit(1);
         exit();
      });
      let deployConfig = null;
@@ -162,7 +251,7 @@
      }
      if (!deployConfig || Object.values(deployConfig).some((item) => !item)) {
         console.error(chalk.red(`${customerName} ${deployEnv} 配置不完整!`));
         process.exit(1); // 退出脚本
         exit(); // 退出脚本
      }
      // 缓存部署配置
      customerConfig[item] = deployConfig;
@@ -208,6 +297,9 @@
         }
         try {
            // 批量备份文件夹到本地
            // FIXME: 文件夹如果是中文,会乱码
            // uploadCommand=`get -r /D:/IStation.SQI.WebAirp E:\\139.224.246.185_bak\\IStation.SQI.WebAirp`
            fs.writeFileSync(uploadScriptFile, uploadCommand);
            const sftpArgs = [
               `${deployConfig.username}@${deployConfig.host} -P ${deployConfig.port} -pw ${deployConfig.password} -b ${uploadScriptFile}`,
@@ -225,11 +317,32 @@
         }
      }
   }
   logSuccess(`🎉🎉🎉【${customerList.join(',')}】项目已成功部署!🎉🎉🎉`);
   logSuccess(`${formatDate(new Date(), 'HH:MM:SS')} > 🎉🎉🎉【${customerList.join(',')}】项目已成功部署!🎉🎉🎉`);
};
/**
 * 切换分支
 */
const changeBranch = () =>{
   return;
   if (isPro) {
      try {
         execSync('git checkout master', { stdio: 'inherit' });
      } catch (error) {}
   } else {
      try {
         execSync('git checkout test', { stdio: 'inherit' });
      } catch (error) {}
   }
}
module.exports = {
   isPro,
   firstCustomerName,
   exit,
   customerList,
   replaceFileContent,
   checkFileExist,
   //#region ====================== 文件路径 ======================
   rootDir,
   scriptDir,
@@ -248,8 +361,12 @@
   //#region ====================== 打印 ======================
   logError,
   logSuccess,
   logWarn,
   //#endregion
   formatDate,
   moveProjectsToBakDir,
   restoreProjectDir,
   updateImportGlob,
   restoreImportGlob,
   deployEnv,
   changeBranch
};