diff --git a/.gitignore b/.gitignore index fb5700d2..07a87f35 100644 --- a/.gitignore +++ b/.gitignore @@ -9,4 +9,6 @@ Thumbs.db /vendor /.settings /.buildpath -/.project \ No newline at end of file +/.project + +app/index/controller/DataMigration.php \ No newline at end of file diff --git a/app/index/controller/Common.php b/app/index/controller/Common.php new file mode 100644 index 00000000..2e4b8c50 --- /dev/null +++ b/app/index/controller/Common.php @@ -0,0 +1,210 @@ +getLanguages(); + // 输出国家/语言列表 + View::assign('header_languages', $languages); + + // 获取当前语言 + $current_language = $this->getCurrentLanguage($languages); + if (!empty($current_language)) { + $this->lang_id = $current_language['id']; + } + + // 获取产品分类 + $categorys = $this->getProductCategory($this->lang_id); + // 输出产品分类 + View::assign('header_categorys', $categorys); + + // 获取热销产品 + $hot_products = $this->getHotProducts($this->lang_id); + // 输出热销产品 + View::assign('header_hot_products', $hot_products); + + // 输出顶部导航 + View::assign('header_navigation', $this->getNavigation('NAV_67f3701f3e831', $this->lang_id)); + + // 获取系统配置 + $configs = $this->getSysConfig($this->lang_id, ['basic', 'contact', 'media']); + // 输出系统配置 + View::assign('basic_config', $configs['basic']); + View::assign('contact_config', $configs['contact']); + View::assign('media_config', $configs['media']); + + // 获取底部导航 + $footer_navigation = $this->getNavigation('NAV_67f60be43df8d', $this->lang_id); + // 输出底部导航 + View::assign('footer_navigation', $footer_navigation); + } + + // 获取当前语言 + private function getCurrentLanguage($languages) + { + $current_code = Lang::getLangSet(); + foreach ($languages as $item) { + if ($item['lang_code'] == $current_code) { + return $item; + } + } + + return []; + } + + // 获取产品分类 + protected function getProductCategory($language = 1) + { + $categorys = ProductCategoryModel::field([ + 'id', + 'pid', + 'name', + 'icon', + 'level' + ]) + ->language($language) + ->displayed() + ->order(['sort' => 'asc', 'id' => 'desc']) + ->select(); + if ($categorys->isEmpty()) { + return []; + } + + return array_to_tree($categorys->toArray(), 0, 'pid', 1, false); + } + + // 获取顶部导航 + protected function getNavigation($unique_label, $language = 1) + { + $nav = SysNavigationItemModel::hasWhere('navigation', [ + 'unique_label' => $unique_label, + 'language_id' => $language, + 'status' => 1 + ]) + ->order(['sort' => 'asc', 'id' => 'asc']) + ->select(); + if ($nav->isEmpty()) { + return []; + } + + return array_to_tree($nav->toArray(), 0, 'pid', 1, false); + } + + // 获取热销产品 + protected function getHotProducts($language = 1, $limit = 3) + { + $products = ProductModel::field([ + 'id', + 'name', + 'cover_image', + ]) + ->language($language) + ->onSale(true) + ->onShelves(true) + ->hot(true) + ->limit($limit) + ->order(['sort' => 'asc', 'id' => 'desc']) + ->select(); + if ($products->isEmpty()) { + return []; + } + + return $products->toArray(); + } + + // 获取国家/语言列表 + protected function getLanguages() + { + $languages = LanguageModel::alias('l') + ->field([ + 'l.id', + 'l.name' => 'lang_name', + 'l.en_name' => 'lang_en_name', + 'l.code' => 'lang_code', + 'l.icon' => 'lang_icon', + 'l.url' => 'lang_url', + 'c.id' => 'country_id', + 'c.name' => 'country_zh_name', + 'c.en_name' => 'country_en_name', + 'c.code' => 'country_code', + ]) + ->join('sys_country c', 'c.id = l.country_id') + ->where('l.status', '=', 1) + ->where('c.status', '=', 1) + ->order(['l.sort' => 'asc', 'l.id' => 'asc']) + ->select(); + + return $languages; + } + + // 获取系统联系方式配置 + protected function getSysConfig($language, $group = []) + { + $configs = SysConfigModel::alias('c') + ->field([ + 'c.id', + 'c.title', + 'c.name', + 'c.value', + 'c.extra', + 'c.type', + 'g.unique_label' + ]) + ->join('sys_config_group g', 'g.id = c.group_id') + ->where('g.unique_label', 'in', $group) + ->where('g.language_id', '=', $language) + ->order(['c.sort' => 'asc', 'c.id' => 'desc']) + ->select(); + if ($configs->isEmpty()) { + return []; + } + $configs = $configs->toArray(); + $data = []; + foreach ($configs as $cfg) { + $current = &$data; + if (!isset($current[$cfg['unique_label']])) { + $current[$cfg['unique_label']] = []; + } + $current = &$current[$cfg['unique_label']]; + + // 根据name中"."拆分为多维数组 + $parts = explode('.', $cfg['name']); + foreach ($parts as $part) { + if (!isset($current[$part])) { + $current[$part] = []; + } + $current = &$current[$part]; + } + $current = [ + 'title' => $cfg['title'], + 'type' => $cfg['type'], + 'value' => $cfg['value'], + 'extra' => $cfg['extra'], + ]; + } + unset($current); + + return $data; + } +} diff --git a/app/index/controller/Index.php b/app/index/controller/Index.php index 81f7c98f..2eb95687 100644 --- a/app/index/controller/Index.php +++ b/app/index/controller/Index.php @@ -3,10 +3,147 @@ declare (strict_types = 1); namespace app\index\controller; -class Index +use app\index\model\ArticleModel; +use app\index\model\FaqModel; +use app\index\model\ProductModel; +use app\index\model\SysBannerModel; +use think\facade\View; + +/** + * 首页控制器 + */ +class Index extends Common { public function index() { - return '您好!这是一个[' . lang('home') . ']示例应用'; + // 获取banner数据 + $banner = $this->getBannerData(); + View::assign('focus_images', $banner['focus_images']); + View::assign('product_categorys', $banner['product_categorys']); + View::assign('featured_topics', $banner['featured_topics']); + View::assign('video', array_shift($banner['video'])); + View::assign('scenes', $banner['scenes']); + View::assign('brand_story', $banner['brand_story']); + View::assign('data_statistics', $banner['data_statistics']); + + // 获取明星产品/热点产品 + View::assign('featured_products', $this->getFeaturedProducts()); + + // 获取推荐文章 + View::assign('recommend_articles', $this->getRecommendArticles()); + + // 获取常见问题 + View::assign('recommend_faq', $this->getRecommendFAQ()); + + return View::fetch('index'); + } + + // 获取banner数据 + private function getBannerData() + { + $banners = SysBannerModel::with(['items']) + ->uniqueLabel([ + 'BANNER_67f61cd70e8e1', + 'BANNER_67f633023a5b3', + 'BANNER_67f63f8ab5029', + 'BANNER_67f724ed81b1e', + 'BANNER_67f7392b4d83a', + 'BANNER_67f7410e244fb', + 'BANNER_67f76a96545f9', + ]) + ->language($this->lang_id) + ->recommend(true) + ->enabled(true) + ->select(); + $banner_map = []; + foreach ($banners as $v) { + $banner_map[$v->unique_label] = $v; + } + + // 处理焦点轮播图和产品分类 + $data['focus_images'] = []; // 焦点轮播图 + $data['product_categorys'] = []; // 产品分类信息 + $data['featured_topics'] = []; // 特色专题及公司实力 + $data['video'] = []; // 视频 + $data['scenes'] = []; // 场景介绍 + $data['brand_story'] = []; // 品牌故事 + $data['data_statistics'] = []; // 数据统计 + if (!empty($banner_map)) { + $data['focus_images'] = $banner_map['BANNER_67f61cd70e8e1']->items->where('type', '=', 'image')->where('status', '=', 1)->order('sort', 'asc')->toArray(); + $data['product_categorys'] = $banner_map['BANNER_67f633023a5b3']->items->where('type', '=', 'image')->where('status', '=', 1)->order('sort', 'asc')->toArray(); + $data['product_categorys'] = $banner_map['BANNER_67f633023a5b3']->items->where('type', '=', 'image')->where('status', '=', 1)->order('sort', 'asc')->toArray(); + $data['featured_topics'] = $banner_map['BANNER_67f63f8ab5029']->items->where('type', '=', 'image')->where('status', '=', 1)->order('sort', 'asc')->toArray(); + $data['video'] = $banner_map['BANNER_67f724ed81b1e']->items->where('type', '=', 'video')->where('status', '=', 1)->order('sort', 'asc')->toArray(); + $data['scenes'] = $banner_map['BANNER_67f7392b4d83a']->items->where('type', '=', 'image')->where('status', '=', 1)->order('sort', 'asc')->toArray(); + $data['brand_story'] = $banner_map['BANNER_67f7410e244fb']->items->where('type', '=', 'image')->where('status', '=', 1)->order('sort', 'asc')->toArray(); + $data['data_statistics'] = $banner_map['BANNER_67f76a96545f9']->items->where('type', '=', 'image')->where('status', '=', 1)->order('sort', 'asc')->toArray(); + } + + return $data; + } + + // 获取明星/热点产品 + private function getFeaturedProducts() + { + $products = ProductModel::field([ + 'id', + 'name', + 'short_name', + 'cover_image', + ]) + ->language($this->lang_id) + ->enabled(true) + ->onSale(true) + ->onShelves(true) + ->hot(true) + ->order(['sort' => 'asc', 'id' => 'desc']) + ->select(); + if ($products->isEmpty()) { + return []; + } + + return $products->toArray(); + } + + // 获取推荐文章 + private function getRecommendArticles() + { + $articles = ArticleModel::field([ + 'id', + 'title', + 'desc', + 'image' + ]) + ->language($this->lang_id) + ->enabled(true) + ->recommend(true) + ->order(['sort' => 'asc', 'id' => 'desc']) + ->limit(6) + ->select(); + if ($articles->isEmpty()) { + return []; + } + + return $articles->toArray(); + } + + // 获取推荐问题 + private function getRecommendFAQ() + { + $faqs = FaqModel::field([ + 'id', + 'question', + 'image', + 'answer' + ]) + ->language($this->lang_id) + ->recommend(true) + ->order(['sort' => 'asc', 'id' => 'desc']) + ->limit(6) + ->select(); + if ($faqs->isEmpty()) { + return []; + } + return $faqs->toArray(); } } diff --git a/app/index/lang/en-us.php b/app/index/lang/en-us.php index 616c89c0..75fa39c3 100644 --- a/app/index/lang/en-us.php +++ b/app/index/lang/en-us.php @@ -1,5 +1,25 @@ 'Home', + 'header_navigation' => [ + 'product_categorys' => 'Products' + ], + 'header_search' => [ + 'history' => 'Search History', + 'hot_product' => 'Popular Products', + ], + 'footer_navigation' => [ + 'product_categorys' => 'Product' + ], + 'footer_contact' => 'Contact', + 'index' => [ + 'featured_products' => 'Featured Products', + 'view_all' => 'View All', + 'learn_more' => 'Learn More', + 'orico_technology' => 'ORICO Technology', + 'orico_technology_desc' => 'Designed to be just as easy to learn as iPhone.Chatting with friends.', + 'faq' => 'FAQ', + 'faq_short_desc' => 'What are you most concerned about', + 'faq_desc' => 'Our customer support is available Manday to Friday 9am600pmAverage arswer time 24h', + ] ]; \ No newline at end of file diff --git a/app/index/lang/zh-cn.php b/app/index/lang/zh-cn.php index 34c3cb46..3ad53f3b 100644 --- a/app/index/lang/zh-cn.php +++ b/app/index/lang/zh-cn.php @@ -1,5 +1,25 @@ '首页', + 'header_navigation' => [ + 'product_categorys' => '产品列表' + ], + 'header_search' => [ + 'hot_product' => '热销产品', + 'history' => '搜索记录', + ], + 'footer_navigation' => [ + 'product_categorys' => '产品' + ], + 'footer_contact' => '联系我们', + 'index' => [ + 'featured_products' => '明星产品/热点产品', + 'view_all' => '查看所有', + 'learn_more' => '了解更多', + 'orico_technology' => 'ORICO 技术', + 'orico_technology_desc' => '强大功能、简单使用', + 'faq' => '常见问题', + 'faq_short_desc' => '回答您最关心的问题', + 'faq_desc' => '客服团队的工作时间:周一到周五,早9点到晚6点 平均应答时间:24小时内', + ] ]; \ No newline at end of file diff --git a/app/index/model/ArticleCategoryModel.php b/app/index/model/ArticleCategoryModel.php new file mode 100644 index 00000000..0f9d4da4 --- /dev/null +++ b/app/index/model/ArticleCategoryModel.php @@ -0,0 +1,19 @@ +where('language_id', '=', $language); + } + + // 首页推荐状态范围查询 + public function scopeRecommend($query, bool $stat = true) + { + return $query->where('recommend', '=', (int)$stat); + } + + // 启用状态范围查询 + public function scopeEnabled($query, bool $stat = true) + { + return $query->where('enabled', '=', (int)$stat); + } +} diff --git a/app/index/model/CountryModel.php b/app/index/model/CountryModel.php new file mode 100644 index 00000000..58c91ac2 --- /dev/null +++ b/app/index/model/CountryModel.php @@ -0,0 +1,15 @@ +where('language_id', '=', $language); + } + + // 推荐状态范围查询 + public function scopeRecommend($query, bool $stat) + { + return $query->where('recommend', '=', (int)$stat); + } +} diff --git a/app/index/model/LanguageModel.php b/app/index/model/LanguageModel.php new file mode 100644 index 00000000..a907a4e8 --- /dev/null +++ b/app/index/model/LanguageModel.php @@ -0,0 +1,15 @@ +where('language_id', '=', $language); + } + + // 显示的分类范围查询 + public function scopeDisplayed($query) + { + $query->where('is_show', '=', 1); + } +} diff --git a/app/index/model/ProductModel.php b/app/index/model/ProductModel.php new file mode 100644 index 00000000..2bf9fee7 --- /dev/null +++ b/app/index/model/ProductModel.php @@ -0,0 +1,49 @@ +where('language_id', '=', $language); + } + + // 启用状态范围查询 + public function scopeEnabled($query) + { + $query->where('status', '=', 1); + } + + // 在售状态范围查询 + public function scopeOnSale($query, bool $stat = true) + { + $query->where('is_sale', '=', (int)$stat); + } + + // 上架状态范围查询 + public function scopeOnShelves($query, bool $stat = true) + { + $query->where('is_show', '=', (int)$stat); + } + + // 热销状态范围查询 + public function scopeHot($query, bool $stat = true) + { + $query->where('is_hot', '=', (int)$stat); + } +} diff --git a/app/index/model/SysBannerItemModel.php b/app/index/model/SysBannerItemModel.php new file mode 100644 index 00000000..860da226 --- /dev/null +++ b/app/index/model/SysBannerItemModel.php @@ -0,0 +1,25 @@ +where('status', '=', 1); + } +} diff --git a/app/index/model/SysBannerModel.php b/app/index/model/SysBannerModel.php new file mode 100644 index 00000000..0b46819d --- /dev/null +++ b/app/index/model/SysBannerModel.php @@ -0,0 +1,53 @@ +hasMany(SysBannerItemModel::class, 'banner_id', 'id'); + } + + // 唯一标识范围查询 + public function scopeUniqueLabel($query, string|array $unique_label) + { + if (is_array($unique_label)) { + $query->whereIn('unique_label', $unique_label); + return; + } + $query->where('unique_label', '=', $unique_label); + } + + // 所属语言范围查询 + public function scopeLanguage($query, $language) + { + $query->where('language_id', '=', $language); + } + + // 首页推荐状态范围查询 + public function scopeRecommend($query, bool $recommend = true) + { + $query->where('recommend', '=', (int)$recommend); + } + + // 启用状态范围查询 + public function scopeEnabled($query, bool $enabled = true) + { + $query->where('status', '=', (int)$enabled); + } +} diff --git a/app/index/model/SysConfigGroupModel.php b/app/index/model/SysConfigGroupModel.php new file mode 100644 index 00000000..f86be2ca --- /dev/null +++ b/app/index/model/SysConfigGroupModel.php @@ -0,0 +1,19 @@ +belongsTo(SysConfigGroupModel::class, 'group_id', 'id'); + } +} diff --git a/app/index/model/SysNavigationItemModel.php b/app/index/model/SysNavigationItemModel.php new file mode 100644 index 00000000..8bdcf1af --- /dev/null +++ b/app/index/model/SysNavigationItemModel.php @@ -0,0 +1,20 @@ +hasOne(SysNavigationModel::class, 'id', 'nav_id'); + } +} + \ No newline at end of file diff --git a/app/index/model/SysNavigationModel.php b/app/index/model/SysNavigationModel.php new file mode 100644 index 00000000..feb0b18e --- /dev/null +++ b/app/index/model/SysNavigationModel.php @@ -0,0 +1,25 @@ +where('unique_label', '=', $unique_label); + } +} diff --git a/app/index/route/v1.php b/app/index/route/route.php similarity index 62% rename from app/index/route/v1.php rename to app/index/route/route.php index 40a544ab..d89ce17a 100644 --- a/app/index/route/v1.php +++ b/app/index/route/route.php @@ -11,3 +11,15 @@ use think\facade\Route; Route::get('/', 'Index/index'); + +Route::group('product', function() { + // 产品列表页 + Route::get('index/:id', 'Product/index')->name('product_index'); + // 产品详情页 + Route::get('detail/:id', 'Product/detail')->name('product_detail'); + // 产品搜索页 + Route::get('search', 'Product/search')->name('product_search'); +}); + +// 数据迁移 +Route::get('/data/migration', 'DataMigration/index'); diff --git a/app/index/view/index/index.html b/app/index/view/index/index.html new file mode 100644 index 00000000..5f39d797 --- /dev/null +++ b/app/index/view/index/index.html @@ -0,0 +1,382 @@ +{extend name="public/base" /} +{block name="style"} + +{/block} +{block name="main"} +
{$topic.title}
+{$topic.title}
+{:lang('index.featured_products')}
+
+
+ {:lang('index.orico_technology')}
+ {:lang('index.orico_technology_desc')} +
+
+
+
+ {:lang('index.faq_short_desc')}
+{:lang('index.faq_desc')}
+{$faq.answer|raw}
+