첫 완료
This commit is contained in:
157
app.ts
Normal file
157
app.ts
Normal file
@@ -0,0 +1,157 @@
|
||||
import prisma from "./src/lib/prisma";
|
||||
import dayjs from "dayjs";
|
||||
import { RankingService } from "./src/services/ranking.service";
|
||||
import { NaverRealEstate } from "./src/services/naver.service";
|
||||
import { realestateTypes, realtorIds } from "./config";
|
||||
|
||||
import {
|
||||
TelegramService,
|
||||
telegramUsers,
|
||||
type TelegramUser,
|
||||
} from "./src/services/telegram.service";
|
||||
import type { RealEstateArticle } from "./src/generated/prisma";
|
||||
import * as XLSX from "xlsx";
|
||||
|
||||
const telegramService = new TelegramService(
|
||||
"233460568:AAHWgRQo5IgcWR0uXdsiMEzNnsmIqjOgk24",
|
||||
false
|
||||
);
|
||||
|
||||
async function main() {
|
||||
await updateRanking();
|
||||
// await sendTelegram();
|
||||
}
|
||||
|
||||
async function sendTelegram() {
|
||||
for (let telegramUser of telegramUsers) {
|
||||
const articles = await prisma.realEstateArticle.findMany({
|
||||
where: {
|
||||
isActive: true,
|
||||
realtorId: telegramUser.realtorId,
|
||||
...(telegramUser.site !== "ALL" && { cpNm: telegramUser.site }),
|
||||
...(telegramUser.site === "부동산포스" && {
|
||||
brokerPhone: telegramUser.phone,
|
||||
}),
|
||||
},
|
||||
});
|
||||
|
||||
const excelFilePath = await createExcelFile(telegramUser, articles);
|
||||
|
||||
await telegramService.sendDocument(
|
||||
telegramUser.chatId,
|
||||
excelFilePath,
|
||||
`네이버 부동산 매물 목록 (${dayjs().format("YYYY-MM-DD")})`
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
async function createExcelFile(
|
||||
telegramUser: TelegramUser,
|
||||
articles: RealEstateArticle[]
|
||||
): Promise<string> {
|
||||
// 데이터를 배열로 변환
|
||||
const data = articles.map((item) => {
|
||||
const getOwnerType = () => {
|
||||
if (["MOBL", "NDOC1", "OWNER"].includes(item.verificationType || "")) {
|
||||
if (
|
||||
["VL", "APT", "OPST", "DDDGG"].includes(item.realEstateType || "")
|
||||
) {
|
||||
return "집주인";
|
||||
} else {
|
||||
return "소유자";
|
||||
}
|
||||
}
|
||||
if (["SITE", "S_VR"].includes(item.verificationType || "")) {
|
||||
return "현장";
|
||||
}
|
||||
return "";
|
||||
};
|
||||
|
||||
const getPrice = () => {
|
||||
return item.prcInfo;
|
||||
};
|
||||
|
||||
return {
|
||||
매물번호: item.articleNumber,
|
||||
바로가기: `https://fin.land.naver.com/articles/${item.articleNumber}`,
|
||||
소유자구분: getOwnerType(),
|
||||
매물형태: item.articleName || "",
|
||||
매매구분: item.tradTpNm || "",
|
||||
주소: `${item.city || ""} ${item.division || ""} ${item.sector || ""}`,
|
||||
상세주소: item.detailAddress || "",
|
||||
층수: item.floorInfo || "",
|
||||
가격: getPrice(),
|
||||
매물특징: item.articleDescription || "",
|
||||
광고사: item.cpNm || "",
|
||||
확인일자: item.articleConfirmDate
|
||||
? dayjs(item.articleConfirmDate).format("YYYY-MM-DD")
|
||||
: "",
|
||||
순위: item.ranking || 9999,
|
||||
};
|
||||
});
|
||||
|
||||
// 워크시트 생성
|
||||
const worksheet = XLSX.utils.json_to_sheet(data);
|
||||
|
||||
// 바로가기 컬럼에 하이퍼링크 추가 (B열, 2번째 컬럼)
|
||||
articles.forEach((item, index) => {
|
||||
const cellAddress = `B${index + 2}`; // 헤더가 1행이므로 데이터는 2행부터
|
||||
const url = `https://fin.land.naver.com/articles/${item.articleNumber}`;
|
||||
worksheet[cellAddress] = {
|
||||
t: "s", // string type
|
||||
v: "열기", // 표시되는 텍스트
|
||||
l: { Target: url }, // hyperlink
|
||||
};
|
||||
});
|
||||
|
||||
// 컬럼 너비 설정
|
||||
worksheet["!cols"] = [
|
||||
{ wch: 12 }, // 매물번호
|
||||
{ wch: 10 }, // 바로가기
|
||||
{ wch: 10 }, // 소유자구분
|
||||
{ wch: 12 }, // 매물형태
|
||||
{ wch: 10 }, // 매매구분
|
||||
{ wch: 30 }, // 주소
|
||||
{ wch: 40 }, // 상세주소
|
||||
{ wch: 8 }, // 층수
|
||||
{ wch: 14 }, // 가격
|
||||
{ wch: 30 }, // 매물특징
|
||||
{ wch: 14 }, // 광고사
|
||||
{ wch: 10 }, // 확인일자
|
||||
{ wch: 6 }, // 순위
|
||||
];
|
||||
|
||||
// 워크북 생성
|
||||
const workbook = XLSX.utils.book_new();
|
||||
XLSX.utils.book_append_sheet(workbook, worksheet, "매물목록");
|
||||
|
||||
// 파일 저장
|
||||
const filePath = `./xlsx/${dayjs().format("YYYY-MM-DD_HH-mm")}_순위_${
|
||||
telegramUser.site
|
||||
}_${telegramUser.realtorId}.xlsx`;
|
||||
|
||||
XLSX.writeFile(workbook, filePath);
|
||||
|
||||
return filePath;
|
||||
}
|
||||
|
||||
async function updateRanking() {
|
||||
const checkDate = dayjs().toDate();
|
||||
for (let realtorId of realtorIds) {
|
||||
const articles = await prisma.realEstateArticle.findMany({
|
||||
where: {
|
||||
isActive: true,
|
||||
realtorId: realtorId,
|
||||
},
|
||||
});
|
||||
|
||||
const rankingService = new RankingService(
|
||||
new NaverRealEstate({
|
||||
realtorId: realtorId,
|
||||
})
|
||||
);
|
||||
await rankingService.updateRanking(articles, checkDate);
|
||||
}
|
||||
}
|
||||
|
||||
main();
|
||||
Reference in New Issue
Block a user