158 lines
4.4 KiB
TypeScript
158 lines
4.4 KiB
TypeScript
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();
|