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