* feat: 添加食物相克检测功能及相关数据支持 * chore: 修改 .gitignore 设置,并删除 recipe.json 的 git 引用 * style: 格式化 incompatible-foods.ts 文件中的代码,修改缩紧为 2 * fix: 修复导入语句,确保正确使用 Vue 的 ref 和 computed * refactor: 优化相克检测逻辑,使用 Set 提高性能 * refactor: 移除不必要的 IncompatibleRule 类型定义 * fix: 添加缺失字段检查,确保不完整数据不会被处理 * style: 使用 eslint 优化代码格式
113 lines
2.9 KiB
TypeScript
113 lines
2.9 KiB
TypeScript
import type { IncompatibleRule, RecipeItem, Recipes } from '../app/types'
|
|
// convert csv to json
|
|
import fs from 'node:fs'
|
|
import consola from 'consola'
|
|
|
|
import { config } from './config'
|
|
|
|
function run() {
|
|
const csvData = fs.readFileSync(config.recipeCsvFile, 'utf-8')
|
|
const lines = csvData.split(/\r?\n/)
|
|
|
|
const headers = 'name,stuff,bv,difficulty,tags,methods,tools,'
|
|
if (lines.length < 2) {
|
|
throw new Error('No data in csv file')
|
|
}
|
|
|
|
if (lines[0]?.trim() !== headers) {
|
|
consola.warn(`Headers Changed: ${lines[0]}`)
|
|
return
|
|
}
|
|
|
|
const recipeJson: Recipes = []
|
|
const sep = '、'
|
|
|
|
lines.slice(1).forEach((line) => {
|
|
if (line) {
|
|
const attrs = line.split(',')
|
|
if (attrs.length < 7) {
|
|
consola.warn(`Invalid line: ${line}`)
|
|
return
|
|
}
|
|
const stuff = attrs[1]?.trim().split(sep) || []
|
|
recipeJson.push({
|
|
name: attrs[0]?.trim() || '',
|
|
stuff,
|
|
// link: attrs[2].trim(),
|
|
// bv id
|
|
bv: attrs[2]?.trim().replace('https://www.bilibili.com/video/', ''),
|
|
difficulty: attrs[3] && attrs[3].trim() as RecipeItem['difficulty'],
|
|
tags: attrs[4] ? attrs[4].trim().split(sep) : [],
|
|
methods: attrs[5] ? (attrs[5].trim().split(sep)) as RecipeItem['methods'] : [],
|
|
tools: attrs[6] ? attrs[6].trim().split(sep) : [],
|
|
})
|
|
}
|
|
})
|
|
|
|
fs.writeFileSync(config.recipeJsonFile, JSON.stringify(recipeJson))
|
|
consola.success(`Generate file: ${config.recipeJsonFile}`)
|
|
}
|
|
|
|
/**
|
|
* 转换食物相克数据
|
|
*/
|
|
function convertIncompatibleFoods() {
|
|
consola.info('---')
|
|
consola.info('Convert Incompatible Foods Data...')
|
|
|
|
try {
|
|
const csvData = fs.readFileSync(config.incompatibleFoodsCsvFile, 'utf-8')
|
|
const lines = csvData.split(/\r?\n/)
|
|
|
|
const headers = 'foodA,foodB,reason'
|
|
if (lines.length < 2) {
|
|
throw new Error('No data in incompatible foods csv file')
|
|
}
|
|
|
|
if (lines[0]?.trim() !== headers) {
|
|
consola.warn(`Headers Changed: ${lines[0]}`)
|
|
return
|
|
}
|
|
|
|
const incompatibleRules: IncompatibleRule[] = []
|
|
|
|
lines.slice(1).forEach((line) => {
|
|
if (line.trim()) {
|
|
const attrs = line.split(',')
|
|
if (attrs.length < 3) {
|
|
consola.warn(`Invalid line: ${line}`)
|
|
return
|
|
}
|
|
|
|
const foodA = attrs[0]?.trim()
|
|
const foodB = attrs[1]?.trim()
|
|
const reason = attrs[2]?.trim()
|
|
|
|
if (!foodA || !foodB || !reason) {
|
|
consola.warn(`Missing required field(s) in line: ${line}`)
|
|
return
|
|
}
|
|
|
|
incompatibleRules.push({
|
|
foodA,
|
|
foodB,
|
|
reason,
|
|
})
|
|
}
|
|
})
|
|
|
|
fs.writeFileSync(config.incompatibleFoodsJsonFile, JSON.stringify(incompatibleRules, null, 2))
|
|
consola.success(`Generate file: ${config.incompatibleFoodsJsonFile}`)
|
|
}
|
|
catch (error) {
|
|
consola.error('Failed to convert incompatible foods data:', error)
|
|
}
|
|
}
|
|
|
|
function main() {
|
|
run()
|
|
convertIncompatibleFoods()
|
|
}
|
|
|
|
main()
|