feat(projects): فیلدهای «نوع پروژه» و «کاربری» + فهرست مشخصات جدید صفحهٔ جزئیات

- دیتابیس/مدل/اسکیما: ستون‌های project_type/usage دوزبانه (مهاجرت DDL
  idempotent — با استارت بک‌اند اعمال می‌شود)
- پنل: کشویر پروژه‌ها دو فیلد تازه گرفت
- صفحهٔ جزئیات: فهرست مشخصات مطابق داده‌های تیم — وضعیت / سال / طبقات /
  واحدها / نوع پروژه / زیربنا / کاربری (ردیف‌های خالی پنهان‌اند)
This commit is contained in:
aramesh-site deploy
2026-09-28 10:17:25 +00:00
parent 5cf7b51686
commit edcbd0dc58
6 changed files with 33 additions and 5 deletions
+4
View File
@@ -29,6 +29,10 @@ EN_COLUMNS: list[tuple[str, str, str]] = [
("projects", "floors_en", "VARCHAR(64)"),
("projects", "units_en", "VARCHAR(64)"),
("projects", "client_en", "VARCHAR(128)"),
("projects", "project_type", "VARCHAR(128)"),
("projects", "project_type_en", "VARCHAR(128)"),
("projects", "usage", "VARCHAR(128)"),
("projects", "usage_en", "VARCHAR(128)"),
("projects", "summary_en", "TEXT"),
("projects", "body_en", "JSON"),
("articles", "title_en", "VARCHAR(256)"),
+5
View File
@@ -76,6 +76,11 @@ class Project(Base):
units_en: Mapped[str] = mapped_column(String(64), default="")
client: Mapped[str] = mapped_column(String(128), default="")
client_en: Mapped[str] = mapped_column(String(128), default="")
# مشخصات تکمیلی پروژه — به درخواست تیم: نوع پروژه و کاربری
project_type: Mapped[str] = mapped_column(String(128), default="")
project_type_en: Mapped[str] = mapped_column(String(128), default="")
usage: Mapped[str] = mapped_column(String(128), default="")
usage_en: Mapped[str] = mapped_column(String(128), default="")
summary: Mapped[str] = mapped_column(Text, default="")
summary_en: Mapped[str] = mapped_column(Text, default="")
body: Mapped[list] = mapped_column(JSON, default=list)
+8
View File
@@ -61,6 +61,10 @@ class ProjectOut(ORMModel):
units_en: str = ""
client: str
client_en: str = ""
project_type: str = ""
project_type_en: str = ""
usage: str = ""
usage_en: str = ""
summary: str
summary_en: str = ""
body: list[str]
@@ -451,6 +455,10 @@ class ProjectIn(BaseModel):
year: str = ""
year_en: str = ""
status: Literal["done", "progress"] = "done"
project_type: str = ""
project_type_en: str = ""
usage: str = ""
usage_en: str = ""
image: str = ""
gallery: list[str] = []
area: str = ""
+2 -1
View File
@@ -69,7 +69,8 @@ export const ENTITIES: Record<string, EntityConfig> = {
F('title', 'عنوان'), F('slug', 'نشانی (slug)', 'text', undefined, true), F('location', 'موقعیت'),
F('year', 'سال'), F('status', 'وضعیت', 'text', 'done یا progress', true),
F('image', 'تصویر شاخص', 'image', undefined, true), F('gallery', 'گالری (هر خط یک URL)', 'list', undefined, true),
F('area', 'زیربنا'), F('floors', 'طبقات'), F('units', 'واحدها'), F('client', 'کارفرما'),
F('area', 'زیربنا'), F('floors', 'طبقات'), F('units', 'واحدها'),
F('project_type', 'نوع پروژه'), F('usage', 'کاربری'), F('client', 'کارفرما'),
F('summary', 'خلاصه', 'textarea'), F('body', 'متن پروژه (هر پاراگراف یک خط)', 'list'),
],
defaults: { title: 'پروژه جدید', slug: `project-${Date.now()}`, location: '', year: '', status: 'done', image: '', gallery: [], area: '', floors: '', units: '', client: '', summary: '', body: [] },
+6
View File
@@ -53,7 +53,10 @@ export const fa = {
projectNotFound: 'این پروژه پیدا نشد',
projectNotFoundText: 'ممکن است نشانی تغییر کرده باشد. فهرست کامل پروژه‌ها را ببینید.',
backToProjects: 'بازگشت به پروژه‌ها',
specStatus: 'وضعیت',
specLocation: 'موقعیت',
specProjectType: 'نوع پروژه',
specUsage: 'کاربری',
specYear: 'سال',
specArea: 'زیربنا',
specFloors: 'تعداد طبقات',
@@ -166,7 +169,10 @@ export const en: Dict = {
projectNotFound: 'Project not found',
projectNotFoundText: 'The address may have changed. Browse the full list of projects.',
backToProjects: 'Back to projects',
specStatus: 'Status',
specLocation: 'Location',
specProjectType: 'Project type',
specUsage: 'Land use',
specYear: 'Year',
specArea: 'Built area',
specFloors: 'Floors',
+8 -4
View File
@@ -49,14 +49,18 @@ export function ProjectDetail() {
const related = projects.filter((p) => p.slug !== project.slug).slice(0, 3)
// مشخصات هر پروژه — همان فهرستی که تیم داده دارد:
// وضعیت / سال / تعداد طبقات / واحدها / نوع پروژه / زیربنا / کاربری
// ردیف‌های خالی نمایش داده نمی‌شوند.
const facts = [
{ label: t('specLocation'), value: project.location },
{ label: t('specStatus'), value: statusLabel },
{ label: t('specYear'), value: project.year },
{ label: t('specArea'), value: project.area },
{ label: t('specFloors'), value: project.floors },
{ label: t('specUnits'), value: project.units },
{ label: t('specClient'), value: project.client },
]
{ label: t('specProjectType'), value: project.project_type },
{ label: t('specArea'), value: project.area },
{ label: t('specUsage'), value: project.usage },
].filter((f) => String(f.value ?? '').trim() !== '')
return (
<>