diff --git a/README.md b/README.md new file mode 100644 index 0000000..56288f8 --- /dev/null +++ b/README.md @@ -0,0 +1,67 @@ +

Hướng dẫn

+ +

Link thiết kế: Giao diện Admin

+ +

Repo: https://repo.hurasoft.com/tieptk/bestpc_vn

+ +

Theo dõi tiến độ: https://docs.google.com/spreadsheets/d/1Po3ANsG00pm_Y3dnrwuV81cidTCCqepYmR3yPDlIq6c/edit#gid=0

+ +

Cài đặt hệ thống

+ +

Test và làm việc chính tại web: http://local.bestpc_vn/

+ + + + + +

Cấu trúc thư mục

+ + + +

Cài đặt Composer (dùng tải package của PHP)

+ +

Xem hướng dẫn: https://getcomposer.org/doc/00-intro.md#installation-windows

+ +

Sau khi cài đặt xong. Mở cmd của Windows và thao tác lệnh sau để cài các thư viện code PHP cần cho dự án này.

+ +

+    > cd /thuc-muc-check-out/bestpc_vn/package
+    > composer i 
+
+ + diff --git a/config/constant.php b/config/constant.php new file mode 100644 index 0000000..c7f89cc --- /dev/null +++ b/config/constant.php @@ -0,0 +1,9 @@ + [ + 'module' => 'buildpc', + 'view' => 'home', + 'view_id'=> 0, + 'query' => [], + 'url' => '/buildpc', + ], +]; diff --git a/package/composer.json b/package/composer.json new file mode 100644 index 0000000..abce318 --- /dev/null +++ b/package/composer.json @@ -0,0 +1,8 @@ +{ + "require": { + "liquid/liquid": "1.4.32", + "ext-json": "*", + "ext-mysqli": "*", + "ext-zip": "*" + } +} diff --git a/public_html/.htaccess b/public_html/.htaccess new file mode 100644 index 0000000..a0172c7 --- /dev/null +++ b/public_html/.htaccess @@ -0,0 +1,7 @@ +RewriteEngine on +RewriteCond %{REQUEST_FILENAME} !-f +RewriteCond %{REQUEST_FILENAME} !-d +RewriteCond %{REQUEST_URI} !^/index.php +# prevent rewrite non-existent files +RewriteCond %{REQUEST_URI} !\.(jpg|png|gif|css|js|php|tiff|webp|jpeg|ico)$ +RewriteRule ^(.*)$ /index.php [QSA,L] diff --git a/public_html/_shared.php b/public_html/_shared.php new file mode 100644 index 0000000..5c2a092 --- /dev/null +++ b/public_html/_shared.php @@ -0,0 +1,13 @@ +start(); diff --git a/src/Hura/App.php b/src/Hura/App.php new file mode 100644 index 0000000..f605f28 --- /dev/null +++ b/src/Hura/App.php @@ -0,0 +1,211 @@ + 'home', + "view" => 'home', + "url" => '/admin/product' + ]; + + protected $data = []; + + + public function __construct() + { + + } + + // start the app + public function start() { + $this->getRouter(); + $this->getData(); + echo $this->renderModule(); + } + + + protected function getRouter() { + /*$route = [ + "module" => (isset($_REQUEST['module'])) ? $_REQUEST['module'] : 'home', + "view" => (isset($_REQUEST['view'])) ? $_REQUEST['view'] : 'home', + ];*/ + + $objRouter = new Router(); + $this->current_route_info = $objRouter->getRouting(); + } + + + protected function getData() { + $module_file = $this->getModuleFile(); + + if(!file_exists($module_file)) { + // print_r($this->current_route_info); + die('Page '. $module_file .' not found!'); + } + + $data = include_once $module_file; + + $global_data = [ + "module" => $this->current_route_info['module'], + "view" => $this->current_route_info['view'], + "url" => $this->current_route_info['url'], + ]; + + $this->data = array( + 'global' => $global_data, + // module-specific data, just print {{ page }} to see all available data for the current page!!! + 'page' => (is_array($data)) ? $data : [], + ); + } + + + protected function getModuleFile(): string + { + return SRC_DIR . DIRECTORY_SEPARATOR . join(DIRECTORY_SEPARATOR, [ + "pages", + $this->current_route_info["module"], + str_replace("-", "_", $this->current_route_info["view"]).".php" + ]) ; + } + + + protected function renderModule() { + + if(!$this->current_route_info['module'] || !$this->current_route_info['view']) { + die("Module not exist"); + } + + $template_file_path = $this->tpl_path ."/". $this->current_route_info['module']; + $template_file_name = str_replace("-", '_', $this->current_route_info['view']).".html"; + $template_file_full_path = $template_file_path."/".$template_file_name; + + //check exist + if(!@file_exists( $template_file_full_path)) { + // attempt to auto create first + // todo: this MUST BE TURNED OFF IN PRODUCTION, else many files will be created unintentionally + $module_file = $this->getModuleFile(); + // only create if module file exist + if(file_exists($module_file) && !$this->autoCreateTplFile( $template_file_path, $template_file_name )) { + die("Please manually create template file at: ". $template_file_full_path); + } + } + + $theme_file_path = $this->tpl_path ."/theme.html"; + if( ! @file_exists( $theme_file_path)) { + die("Theme not exist (please create): " . $theme_file_path); + } + + $theme_content = @file_get_contents( $theme_file_path ); + $module_content = @file_get_contents( $template_file_full_path ); + + $page_content_to_parse = preg_replace([ + "/{{(\s+)?page_content(\s+)?}}/" + ], [ + $module_content, + ] , $theme_content ); + + + return $this->parse( + $page_content_to_parse, + $template_file_path + ); + } + + + protected function autoCreateTplFile($file_path, $file_name) : bool { + // create dir if not exist + if(!file_exists($file_path)) { + if(!mkdir($file_path, 0755, true)) { + return false; + } + + if(!file_exists($file_path)) { + return false; + } + } + + //create file + $file_full_path = $file_path . "/". $file_name; + @file_put_contents($file_full_path, $file_full_path); + + return file_exists($file_full_path); + } + + + /* + * 2 ways to render a html template + * 1. Use $html_to_parse, which requires no dependencies + * Example: + * Template::parse(null, 'Age = {{age}}', ['age' => 21], ''); + * + * 2. Use $template_file_path, which requires dependency $path + * Template::parse(Template::$setting_template_path, null, ['age' => 21], 'email/test'); + * */ + protected function parse($html_to_parse = null, $template_file_path = '') { + + if(!$html_to_parse && !$template_file_path) { + return 'Nothing to parse'; + } + + //output to html + Liquid::set('INCLUDE_SUFFIX', 'html'); + Liquid::set('INCLUDE_PREFIX', ''); + //Liquid::set('INCLUDE_ALLOW_EXT', true); + Liquid::set('ESCAPE_BY_DEFAULT', false); + + $enable_cache = false; // default = true, turn this on-off to disable cache while working on local mode + //$enable_cache = true; + + //catch exception and print friendly notice + try { + + $objLiquidTemplate = new LiquidTemplate( $this->tpl_path ); + $objLiquidTemplate->registerFilter( TemplateFilter::class ); + if($enable_cache) { + /*$objLiquidTemplate->setCache(new File([ + 'cache_dir' => self::$cache_dir + ]));*/ + } + + if($html_to_parse) { + $objLiquidTemplate->parse($html_to_parse); + }elseif ($template_file_path) { + $objLiquidTemplate->parseFile($template_file_path); + } + + return $objLiquidTemplate->render($this->data); + + } catch (\Exception $e) { + $result = []; + do { + //printf("%s:%d %s (%d) [%s]\n", $e->getFile(), $e->getLine(), $e->getMessage(), $e->getCode(), get_class($e)); + //echo $e->getTraceAsString(); + //$code = $e->getTrace()[0]['args'][0]; + //if(is_array($code)) $code = serialize($code); + $result[] = sprintf( + " +Lỗi code trong file template html:
+- Chi tiết lỗi: %s
+- File template: %s
+- Hướng dẫn xử lý: Tách từng phần html để kiểm tra và nhấn F5 mỗi lần. Nếu không xuất hiện thông báo này nghĩa là phần đó không tạo lỗi +", + $e->getMessage(), + substr($template_file_path, strrpos($template_file_path, DIRECTORY_SEPARATOR) + 1 ), + //static::$cache_dir + ); + + } while($e = $e->getPrevious()); + + return join(" - ", $result); + } + } + +} diff --git a/src/Hura/Router.php b/src/Hura/Router.php new file mode 100644 index 0000000..48bbc07 --- /dev/null +++ b/src/Hura/Router.php @@ -0,0 +1,78 @@ +path_config = require $path_config_file; + } + + // url: asdas.php?para1=value1 + public function getRouting(): array + { + $parsed = Url::parse($_SERVER['REQUEST_URI']); //abc/product?param1=12¶m2=value2 + //print_r($parsed); + + // home + if($parsed['path'] == '/') { + return [ + 'module' => preg_replace("/[^a-z0-9_\-]/i","", getRequest('module', 'home')), + 'view' => preg_replace("/[^a-z0-9_\-]/i","", getRequest('view', 'home')), + 'view_id'=> 0, + 'query' => $parsed['query'], + 'url' => $_SERVER['REQUEST_URI'], + ]; + } + + // check match pattern in $this->path_config + foreach ($this->path_config as $_config => $_route ) { + if(preg_match("{^".$_config."$}", $parsed['path'], $match )) { + + if(isset($_route['query']) && is_array($_route['query'])) { + $_route['query'] = array_merge($_route['query'], $parsed['query']); + }else{ + $_route['query'] = $parsed['query']; + } + + return array_merge([ + 'path' => $parsed['path'], + 'match' => $match, + ], $_route); + } + } + + // check database + + // else error + return [ + 'module' => "error" , + 'view' => "error" , + 'view_id' => "not_found", + 'query' => $parsed['query'], + 'url' => $_SERVER['REQUEST_URI'], + ]; + + + // auto parse path base on convention: admin/module/view/view_id + /* $ele = explode("/", $parsed['path']); + + $module = $ele[2] ?? 'home'; + $view = isset($ele[3]) ? $ele[3] : getRequest('view', 'home'); + $view_id = isset($ele[4]) ? $ele[4] : getRequest('id', 'view_id'); + + // else error + return [ + 'module' => preg_replace("/[^a-z0-9_\-]/i","", $module ) , + 'view' => preg_replace("/[^a-z0-9_\-]/i","", $view ) , + 'view_id' => preg_replace("/[^a-z0-9_]/i","", $view_id ), + 'query' => $parsed['query'], + 'url' => $_SERVER['REQUEST_URI'], + ];*/ + } + +} diff --git a/src/Hura/TemplateFilter.php b/src/Hura/TemplateFilter.php new file mode 100644 index 0000000..38dcd94 --- /dev/null +++ b/src/Hura/TemplateFilter.php @@ -0,0 +1,256 @@ + '', 'value' => ] from [key1 => value1, key2=>value2, ...] + * + * @param array $key_values [key1 => value1, key2=>value2] + * + * @return array [['key' => 'key1', 'value' => value1], ['key' => 'key2', 'value' => value2]] + */ + public static function to_array(array $key_values) { + $result = []; + foreach ($key_values as $key => $value) { + $result[] = [ + 'key' => $key, + 'value' => $value, + ]; + } + + return $result; + } + + + /** + * split a s by line to create array + * + * @param string $txt + * + * @return array + */ + public static function get_line($txt) { + + if(is_array($txt)) { + return $txt; + } + + $txt = trim($txt); + if( ! $txt ) return []; + + return preg_split("/\n/", $txt); + } + + /** + * Implement strlen + * + * @param string $str + * + * @return int + */ + public static function length($str) { + return strlen(trim($str)); + } + + + /** + * Make number easier to read: 1000 -> 1.000 + * + * @param string $number + * + * @return string + */ + public static function format_number($number) { + if(!$number) return ''; + $number = floatval($number); + + $number = number_format($number, 0, ",", "."); //Vietnamese format with decimals by a coma + + return $number; + } + + public static function format_price($p_price, $currency = ''){ + if(!$p_price) return ''; + if(!$currency) $currency = (defined("DEFAULT_CURRENCY")) ? DEFAULT_CURRENCY : "vnd"; + //if(is_string($p_price)) return 0; + if($currency == 'usd') { + return number_format($p_price,2,".",","); + }else { + return number_format($p_price,0,",","."); + } + } + + /** + * + * Description: get the shop's full asset url for template's images/js/css + * + * //Returns the URL of a file in the "assets" folder of a theme. + // {{ 'shop.css' | asset_url : 'arg1', 'arg2' ...}} -> //cdn.shopify.com/s/files/1/0087/0462/t/394/assets/shop.css?28253 + * + * @param string $file_name + * + * @return string + */ + public static function asset_url($file_name = '') + { + if( !$file_name ) return ''; + + $file_ext = strtolower(strrchr($file_name, ".")); + + // script tags + if(in_array($file_ext, ['.js', '.css'])) return TEMPLATE_ASSET . "/script/" . $file_name; + + // default image + return TEMPLATE_ASSET . "/images/" . $file_name; + } + + + /** + * + * Description: construct a full html tag for images/js/css file + * + * @param string $file_path domain.com/static/style.css?v=3.1.1 + * + * @return string + */ + public static function script_tag($file_path) { + if( ! $file_path ) return ''; + + //check for ? + if(strpos($file_path, "?") !== false) { + $file_ext = str_replace(strrchr($file_path, "?"), "", $file_path); + $file_ext = strtolower(strrchr($file_ext, ".")); + } else { + $file_ext = strtolower(strrchr($file_path, ".")); + } + + $tag_config = [ + ".css" => "", + ".js" => "", + ".jpg" => "\"n\"/", + ".jpeg" => "\"\"/", + ".gif" => "\"\"/", + ".png" => "\"\"/", + ]; + + return (isset($tag_config[$file_ext])) ? $tag_config[$file_ext] : ''; + } + + /** + * {{ product_info.main_image | img_url: '300x300' }} => https://cdn.shopify.com/s/files/1/1183/1048/products/boat-shoes_300x300.jpeg?1459175177 + * @param string $full_path + * @param string $modifier + * $modifier: + * - must be in format: NumberxNumber or Numberx where Number must within 10 -> 9999 + * - or be one of these: small | medium | large + * @return string + */ + public static function img_url($full_path, $modifier) + { + $clean_modifier = ($modifier) ? trim($modifier) : ""; + + // verify $modifier + // must be in format: NumberxNumber or Numberx where Number must within 10 -> 9999 + if($clean_modifier + && !preg_match("/^[0-9]{2,4}x([0-9]{2,4})?$/i", $clean_modifier) + && !in_array($clean_modifier, ["small", "medium", "large"]) + ) { + $clean_modifier = ""; + } + + // return if no valid modifier + if( ! $clean_modifier ) { + return $full_path; + } + + $last_dot_position = strrpos($full_path, "."); + if( ! $last_dot_position ) return $full_path . $clean_modifier; + + return join("", [ + substr($full_path, 0, $last_dot_position), + "_", + $clean_modifier, + substr($full_path, $last_dot_position) + ]); + } + + /** + * //Returns the URL of a file in the Files page of the admin. + //{{ 'size-chart.pdf' | file_url }} -> //cdn.shopify.com/s/files/1/0087/0462/files/size-chart.pdf?28261 + * + * @param string $input + * @param string $string + * + * @return string + */ + public static function file_url($input, $string) + { + return strtoupper($input) . " = " . $string; + } + + /** + * //Returns the asset URL of an image in the Files page of the admin. file_img_url accepts an image size parameter. + //{{ 'logo.png' | file_img_url: '1024x768' }} -> //cdn.shopify.com/s/files/1/0246/0527/files/logo_1024x768.png?42 + * + * @param string $input + * @param string $string + * + * @return string + */ + public static function file_img_url($input, $string) + { + return ''; + } + + + /** + * Show all content of a variable, useful for template development + * + * @param string + * + * @return string + */ + public static function print_r($input) + { + @ob_start(); + print_r($input); + $content = ob_get_contents(); + @ob_end_clean(); + + return join("\r", ['']) ; + } + + /** + * Show all content of a variable, useful for template development + * + * @param string + * + * @return string + */ + public static function show_var($input) + { + @ob_start(); + print_r($input); + $content = ob_get_contents(); + @ob_end_clean(); + + return join("\r", ['']) ; + } +} diff --git a/src/Hura/Url.php b/src/Hura/Url.php new file mode 100644 index 0000000..46e377e --- /dev/null +++ b/src/Hura/Url.php @@ -0,0 +1,47 @@ + '', + 'host' => '', + 'port' => '', + 'user' => '', + 'pass' => '', + 'path' => '', + 'query' => [], + 'fragment' => '', + ]; + foreach ($data as $key => $value) { + if(isset($default[$key])) { + $default[$key] = ($key == 'query') ? self::parsedQuery($value) : $value; + } + } + + return $default; + } + + + public static function parsedQuery($query = '') { + if(!$query) return []; + $result = []; + $parts = explode("&", $query); + + foreach ($parts as $part) { + $el = explode("=", $part); + if(sizeof($el) != 2) continue; + + $cleaned_key = preg_replace("/[^a-z0-9_\-\.]/i", '', $el[0]); + $cleaned_value = preg_replace("/[^a-z0-9_\.\-;&]/i", '', $el[1]); + + $result[$cleaned_key] = $cleaned_value; + } + + return $result; + } +} diff --git a/src/inc/common.php b/src/inc/common.php new file mode 100644 index 0000000..46c1c7f --- /dev/null +++ b/src/inc/common.php @@ -0,0 +1,45 @@ +', $content, '']) ; +} + +function init_autoload(){ + $classLoader = require_once ROOT_DIR . '/package/vendor/autoload.php'; + $classLoader->add("Hura", ROOT_DIR . '/src' ); + + return $classLoader; +} + +//get current paging id +function getPageId(){ + return getRequestInt('page', 1); +} + +function getPageSize($default=10){ + return getRequestInt('pageSize', $default); +} + +//Function to get the post value in submit +function getPost($var, $default="", $encode = false, $keep_tag=""){ + return isset($_POST[$var]) ? $_POST[$var] : $default; +} + +//Function to get the INTERGER request value of a variable +function getRequestInt($var, $min_value = 0){ + $request = isset($_REQUEST[$var]) ? (int) $_REQUEST[$var] : (int) $min_value; + $request = ($request >= $min_value ) ? $request : $min_value; //if user tampers request parameter + return $request; +} + + +//Function to get the request value of a variable +function getRequest($var, $default=""){ + return $_REQUEST[$var] ?? $default; +} + diff --git a/src/inc/fun.db.php b/src/inc/fun.db.php new file mode 100644 index 0000000..c59b662 --- /dev/null +++ b/src/inc/fun.db.php @@ -0,0 +1,16 @@ + [ + [ + 'id' => 1, + 'title' => 'ĐƠN HÀNG MỚI', + 'main_stat' => '1000000', + 'time' => ' 24/11/2023 ', + ], + ], + +]; diff --git a/src/pages/product/addon.php b/src/pages/product/addon.php new file mode 100644 index 0000000..b3d9bbc --- /dev/null +++ b/src/pages/product/addon.php @@ -0,0 +1 @@ +getAllParent(); + +return [ + 'category_list' => get_category_list(0, getRequest("id"), $level=1, $prefix="", $category_collection ) +]; + + +function get_category_list($parentId=0, $currentCat="",$level=1, $prefix="", $category_collection = array()){ + + $categoryTree = ""; + $extra_space = ""; + for($i = 1; $i < $level; $i++){ + $extra_space .= "      "; + } + + $stt = 0; + if(isset($category_collection[$parentId])) { + + foreach($category_collection[$parentId] as $index => $cat_info){ + $cat_id = $cat_info['id']; + + $stt ++; + $imgUrl = (strlen($cat_info["thumbnail"]) > 2) ? " " : ""; + + if($cat_info["status"]) $status = ""; + else $status = ""; + + $edit_link ="/admin/product/category-form?id=".$cat_id; + + $hide_this = ($parentId > 0) ? "style='display: none;'" : ''; + + $show_category_name = $cat_info["title"]; + + if(!IS_DEFAULT_LANGUAGE && isset($cat_info["not_translated"]) && $cat_info["not_translated"]) { + $show_category_name = "[Chưa dịch] ".$cat_info["title"]; + } + + if($cat_info['is_parent']) { + $show_category_name = "".$show_category_name.""; + } + + $categoryTree .= " + + + + + ". $extra_space . $prefix . $stt.". ". $show_category_name . $imgUrl." + + + + Xem trang + + + ".$cat_id." + 413787 + 1292 + + + + + + SP + Danh mục con + + + "; + + if(IS_DEFAULT_LANGUAGE) { + $categoryTree .= " + + Tổng (".$cat_info['attribute_count'].") + + +
+ + + ".$status." + +
+ + "; + + }else{ + $categoryTree .= " + + + + "; + } + + $categoryTree .= " + + "; + + if($cat_info["is_parent"]) $categoryTree .= get_category_list($cat_id, $currentCat, $level + 1, $prefix . $stt.".", $category_collection); + + } + } + + return $categoryTree; +} + diff --git a/src/pages/product/category_form.php b/src/pages/product/category_form.php new file mode 100644 index 0000000..80302f2 --- /dev/null +++ b/src/pages/product/category_form.php @@ -0,0 +1,18 @@ + 0) ? $objAProductCategoryController->getFullInfo($id) : null; +if(!$item_info) $item_info = $objAProductCategoryController->getEmptyInfo([]); + + +return [ + 'item_info' => $item_info, + 'categoryDropBox' => $objAProductCategoryController->getDropBox( $item_info['parent_id'], 0, 1), + 'update_status' => getRequest("us"), +]; diff --git a/src/pages/product/collection.php b/src/pages/product/collection.php new file mode 100644 index 0000000..a814366 --- /dev/null +++ b/src/pages/product/collection.php @@ -0,0 +1 @@ +getFullInfo($product_id); + +$view_part = getRequest("part", "basic"); + +$view_part_file = str_replace("-", "_", $view_part); + +$part_file = __DIR__."/form_components/". $view_part_file .".php"; +if(@file_exists($part_file)) { + include $part_file; +}else{ + die("File: /form_components/". $view_part_file .".php does not exist!"); +} + + +return [ + "product_info" => $product_info, + "product_menu" => _get_product_menu(), + "view_part" => $view_part, +]; + +// helpers + +function _get_product_menu() { + $current_selected = getRequest('part', 'basic'); + $product_menu = array( + array( + 'id' => 'basic', + "name" => "Cơ bản", + ), + + array( + 'id' => 'store', + "name" => "Cửa hàng", + ), + + array( + 'id' => 'category', + "name" => "Danh mục", + ), + + array( + 'id' => 'seo', + "name" => "SEO", + ), + + array( + 'id' => 'description', + "name" => "Mô tả", + ), + + array( + 'id' => 'spec-group', + "name" => "Thông số kỹ thuật",//"Thông số", + ), + + /*"spec" => array( + "name" => "Thông số kỹ thuật nhập text", //"Bộ lọc thuộc tính", //"Thông số", + "must_have_id" => true, + "change_language" => true, + ),*/ + + /*"image-spec" => array( + "name" => "Ảnh thông số", + "must_have_id" => true, + "change_language" => true, + ),*/ + + array( + 'id' => 'instruction', + "name" => "Hướng dẫn sử dụng", + ), + + array( + 'id' => 'image', + "name" => "Ảnh", + ), + + array( + 'id' => 'variant', + "name" => "Cấu hình", + ), + + array( + 'id' => 'accessory', + "name" => "Phụ kiện", + ), + + array( + 'id' => 'addon', + "name" => "Dịch vụ/SP đi kèm", + ), + + array( + 'id' => 'video', + "name" => "Youtube", + ), + + /* "video-list" => array( + "name" => "Thư viện Youtube", + "must_have_id" => true, + "change_language" => false, + ),*/ + + /*"relate-article" => array( + "name" => "Nội dung liên quan", + "must_have_id" => true, + "change_language" => false, + ),*/ + + /*"web-link" => array( + "name" => "So sánh giá", + "must_have_id" => true, + "change_language" => false, + ),*/ + + array( + 'id' => 'tag', + "name" => "Tags", + ), + + array( + 'id' => 'relation', + "name" => "Nội dung liên quan", + ), + + array( + 'id' => 'customer-group', + "name" => "Giá theo nhóm khách hàng", + ), + + array( + 'id' => 'component', + "name" => "Thành phần", + ), + + array( + 'id' => 'configurable', + "name" => "Tùy chọn thành phần", + ), + + array( + 'id' => 'compatible', + "name" => "Sp tương thích", + ), + + array( + 'id' => 'similar', + "name" => "Sp tương tự", + ), + + array( + 'id' => 'combo-set', + "name" => "Combo Set", + ), + + ); + + return array_map(function ($item) use ($current_selected){ + $copy = $item; + $copy['is_current'] = $item['id'] == $current_selected ? 1 : 0; + + return $copy; + + }, $product_menu); +} diff --git a/src/pages/product/form_components/accessory.php b/src/pages/product/form_components/accessory.php new file mode 100644 index 0000000..b3d9bbc --- /dev/null +++ b/src/pages/product/form_components/accessory.php @@ -0,0 +1 @@ + explode("-", getRequest("category", '')), + "brand" => explode("-", getRequest("brand", '')), + "hotType" => explode("-", getRequest("hotType", '')), + "other_filter" => [getRequest("other_filter", '')], + "q" => getRequest("q", ''), + 'numPerPage' => $numPerPage, + 'page' => getPageId(), + 'translated' => getRequestInt('translated', 0), + //... more extended filters +]; +//debug_var($objAProductController->getFilterConditions()); + +$totalResults = $objAProductController->getTotal($conditions); +$item_list = $objAProductController->getList($conditions); + +list($page_collection, $tb_page, $total_pages) = Paging::paging_template($totalResults, $numPerPage); + +return [ + "total" => $totalResults, + "item_list" => $item_list, + "pagination" => [ + 'collection' => $page_collection, + 'html' => $tb_page, + 'total_pages' => $total_pages, + ], + + "list_category" => [ + [ + 'id' => 1, + 'title' => 'Màn hình máy tính', + 'url' => '/admin/product?category=9', + 'parentId' => 0, + 'isParent' => 1, + 'children' => [ + [ + 'id' => 10, + 'title' => 'Màn hình theo khoảng giá', + 'url' => '/admin/product?category=148', + 'parentId' => 1, + 'isParent' => 0, + 'totalProduct' => 0, + 'children' => [ + + ] + ], + [ + 'id' => 11, + 'title' => 'Màn Hình Theo Kích Thước', + 'url' => '/admin/product?category=54', + 'parentId' => 1, + 'isParent' => 0, + 'totalProduct' => 0, + 'children' => [ + [ + 'id' => 148, + 'title' => '17 inch - 21.5 inch', + 'url' => '/admin/product?category=148', + 'parentId' => 11, + 'isParent' => 0, + 'totalProduct' => 5, + ], + [ + 'id' => 66, + 'title' => '22 inch - 24 inch', + 'url' => '/admin/product?category=66', + 'parentId' => 11, + 'isParent' => 0, + 'totalProduct' => 41, + ], + [ + 'id' => 67, + 'title' => '25 inch - 27 inch', + 'url' => '/admin/product?category=67', + 'parentId' => 11, + 'isParent' => 0, + 'totalProduct' => 42, + ], + [ + 'id' => 68, + 'title' => '28 inch - 32 inch', + 'url' => '/admin/product?category=68', + 'parentId' => 11, + 'isParent' => 0, + 'totalProduct' => 11, + ] + ] + ] + + ] + ], + [ + 'id' => 65, + 'title' => 'PC, Workstation', + 'url' => '/admin/product?category=65', + 'parentId' => 0, + 'isParent' => 1, + 'children' => [] + ], + [ + 'id' => 3, + 'title' => 'Gaming Gear', + 'url' => '/admin/product?category=3', + 'parentId' => 0, + 'isParent' => 1, + 'children' => [] + ],[ + 'id' => 4, + 'title' => 'CPU - Bộ Vi Xử Lý', + 'url' => '/admin/product?category=4', + 'parentId' => 0, + 'isParent' => 1, + 'children' => [] + ] + + ], + + "brand_letters" => [ + [ + 'key' => 'A', + 'url' => '/ajax/brand.php?action=show-brand-list&letter=A&popup=1', + 'total' => 13, + ], + [ + 'key' => 'B', + 'url' => '/ajax/brand.php?action=show-brand-list&letter=B&popup=1', + 'total' => 2, + ], + [ + 'key' => 'C', + 'url' => '/ajax/brand.php?action=show-brand-list&letter=C&popup=1', + 'total' => 5, + ] + + ], + + "list_brands" => [ + + 'A' => [ + [ + 'id' => 1, + 'name' => 'ABS', + 'letter' => 'A', + 'url' => '/admin/?brand=83&opt=product', + 'product' => 1, + ], + [ + 'id' => 2, + 'name' => 'ACE GAMING', + 'letter' => 'A', + 'url' => '/admin/?brand=83&opt=product', + 'product' => 6, + ], + [ + 'id' => 3, + 'name' => 'ADATA', + 'letter' => 'A', + 'url' => '/admin/?brand=83&opt=product', + 'product' => 15, + ] + ], + + 'B' => [ + [ + 'id' => 3, + 'name' => 'BE QUIET ', + 'letter' => 'B', + 'url' => '/admin/?brand=83&opt=product', + 'product' => 2, + ], + [ + 'id' => 3, + 'name' => 'BENQ', + 'letter' => 'B', + 'url' => '/admin/?brand=83&opt=product', + 'product' => 6, + ], + ], + + 'C' => [ + [ + 'id' => 3, + 'name' => 'CISCO', + 'letter' => 'C', + 'url' => '/admin/?brand=83&opt=product', + 'product' => 2, + ], + [ + 'id' => 3, + 'name' => 'Colorful', + 'letter' => 'C', + 'url' => '/admin/?brand=83&opt=product', + 'product' => 6, + ], + [ + 'id' => 3, + 'name' => 'COOLER MASTER', + 'letter' => 'C', + 'url' => '/admin/?brand=83&opt=product', + 'product' => 6, + ], + [ + 'id' => 3, + 'name' => 'COOLMOON', + 'letter' => 'C', + 'url' => '/admin/?brand=83&opt=product', + 'product' => 6, + ], + [ + 'id' => 3, + 'name' => 'CORSAIR', + 'letter' => 'C', + 'url' => '/admin/?brand=83&opt=product', + 'product' => 6, + ], + ] + ] + +]; diff --git a/src/pages/product/list_competitor.php b/src/pages/product/list_competitor.php new file mode 100644 index 0000000..a814366 --- /dev/null +++ b/src/pages/product/list_competitor.php @@ -0,0 +1 @@ + +
+
+

+ Đơn + hàng + mới

+ + + + +
+ +

10.000.000

+
+ +
+
+ + 10% +
+ +

Hôm qua

+
+ + +
+
+
+

Khách + hàng + liên hệ qua website

+ + + + +
+ +

10.000.000

+
+ +
+
+ + 10% +
+ +

Hôm qua

+
+
+ +
+
+
+

Đơn + trả + góp

+ + + + +
+ +

10.000.000

+
+ +
+
+ + 10% +
+ +

Hôm qua

+
+
+ +
+
+
+

Đơn + hoàn + trả

+ + + + +
+ +

10.000.000

+
+ +
+
+ + 10% +
+ +

Hôm qua

+
+
+ +
+
+
+
32.4k
+

Doanh thu trong tuần này

+
+ +
+ 12% + +
+
+ +
+ +
+
+ + + + + Users Report + + + +
+
+
+ +
+
+
3.4k
+ +
+

Truy cập web trong tuần này

+ + + + 42.5% + +
+
+ +
+
+
Lượt truy cập: +
+
1.458
+
+ +
+
Người xem:
+
2.130
+
+
+ +
+ +
+
+ + + + Leads Report + + +
+
+
\ No newline at end of file diff --git a/template/home/home.html b/template/home/home.html new file mode 100644 index 0000000..62a97b4 --- /dev/null +++ b/template/home/home.html @@ -0,0 +1,1071 @@ + + + + +
+
+
+
+
+

+ sản phẩm được đánh giá tốt nhất +

+
+
+
+

+ Tổng hợp các sản phẩm hot theo xu hướng và có nhiều lượt review và + đánh giá nhất hiện nay +

+ + + +
+
+
+
+
+ + Laptop Dell +
-20%
+
+
+ Laptop văn phòng Dell RAM 8G Core + i7 +
15.000.000đ
+
+ 16.500.000đ + +
+
+
+

Có 12 cửa hàng bán

+
+
+
+
+
+
+ + Laptop Dell +
-20%
+
+
+ Laptop văn phòng Dell RAM 8G Core + i7 +
15.000.000đ
+
+ 16.500.000đ + +
+
+
+

Có 12 cửa hàng bán

+
+
+
+
+
+
+ + Laptop Dell +
-20%
+
+
+ Laptop văn phòng Dell RAM 8G Core + i7 +
15.000.000đ
+
+ 16.500.000đ + +
+
+
+

Có 12 cửa hàng bán

+
+
+
+
+
+
+ + Laptop Dell +
-20%
+
+
+ Laptop văn phòng Dell RAM 8G Core + i7 +
15.000.000đ
+
+ 16.500.000đ + +
+
+
+

Có 12 cửa hàng bán

+
+
+
+
+
+
+ + Laptop Dell +
-20%
+
+
+ Laptop văn phòng Dell RAM 8G Core + i7 +
15.000.000đ
+
+ 16.500.000đ + +
+
+
+

Có 12 cửa hàng bán

+
+
+
+
+
+
+ + Laptop Dell +
-20%
+
+
+ Laptop văn phòng Dell RAM 8G Core + i7 +
15.000.000đ
+
+ 16.500.000đ + +
+
+
+

Có 12 cửa hàng bán

+
+
+
+
+
+
+ + Laptop Dell +
-20%
+
+
+ Laptop văn phòng Dell RAM 8G Core + i7 +
15.000.000đ
+
+ 16.500.000đ + +
+
+
+

Có 12 cửa hàng bán

+
+
+
+
+
+
+
+
+
+
+
+ +
+
+ + +
+
+
+
+
+

+ Tìm theo danh mục +

+
+
+
+ +
+
+ + + + + +
+
+
+
+
+

+ SẢN PHẨM ĐÃ LƯU +

+
+
+
+
+
+
+
+
+ + Laptop Dell +
+
+
+ Laptop văn phòng Dell RAM 8G Core + i7 +
+
15.000.000đ
+ 16.500.000đ +
+
+
+

Có 12 cửa hàng bán

+
+
+
+
+
+
+ + Laptop Dell +
+
+
+ Laptop văn phòng Dell RAM 8G Core + i7 +
+
15.000.000đ
+ 16.500.000đ +
+
+
+

Có 12 cửa hàng bán

+
+
+
+
+
+
+ + Laptop Dell +
+
+
+ Laptop văn phòng Dell RAM 8G Core + i7 +
+
15.000.000đ
+ 16.500.000đ +
+
+
+

Có 12 cửa hàng bán

+
+
+
+
+
+
+ + Laptop Dell +
+
+
+ Laptop văn phòng Dell RAM 8G Core + i7 +
+
15.000.000đ
+ 16.500.000đ +
+
+
+

Có 12 cửa hàng bán

+
+
+
+
+
+
+
+
+
+
+
+ +
+
+ + + +
+
+
+
+
+

+ THÔNG TIN NGÀNH +

+
+
+
+
+
+ + + +
+ Xu hướng công nghệ nhìn từ CES 2025 +
Loạt sản phẩm trưng bày tại CES 2025 cho thấy AI + là xu hướng chính nhưng được...
+
+
+

12/03/2025

+
+ +
+ Xem thêm +
+
+
+ + + +
+ Xu hướng công nghệ nhìn từ CES 2025 +
Loạt sản phẩm trưng bày tại CES 2025 cho thấy AI + là xu hướng chính nhưng được...
+
+
+

12/03/2025

+
+ +
+ Xem thêm +
+
+
+ + + +
+ Xu hướng công nghệ nhìn từ CES 2025 +
Loạt sản phẩm trưng bày tại CES 2025 cho thấy AI + là xu hướng chính nhưng được...
+
+
+

12/03/2025

+
+ +
+ Xem thêm +
+
+
+ + + +
+ Xu hướng công nghệ nhìn từ CES 2025 +
Loạt sản phẩm trưng bày tại CES 2025 cho thấy AI + là xu hướng chính nhưng được...
+
+
+

12/03/2025

+
+ +
+ Xem thêm +
+
+
+ + + Xem tất cả + + +
+ + +
+
+

+ THÔNG TIN khuyến mãi +

+
+
+
+
+
+ + + +
+ Xu hướng công nghệ nhìn từ CES 2025 +
Loạt sản phẩm trưng bày tại CES 2025 cho thấy AI + là xu hướng chính nhưng được...
+
+
+

12/03/2025

+
+ +
+ Xem thêm +
+
+
+ + + +
+ Xu hướng công nghệ nhìn từ CES 2025 +
Loạt sản phẩm trưng bày tại CES 2025 cho thấy AI + là xu hướng chính nhưng được...
+
+
+

12/03/2025

+
+ +
+ Xem thêm +
+
+
+ + + +
+ Xu hướng công nghệ nhìn từ CES 2025 +
Loạt sản phẩm trưng bày tại CES 2025 cho thấy AI + là xu hướng chính nhưng được...
+
+
+

12/03/2025

+
+ +
+ Xem thêm +
+
+
+ + + +
+ Xu hướng công nghệ nhìn từ CES 2025 +
Loạt sản phẩm trưng bày tại CES 2025 cho thấy AI + là xu hướng chính nhưng được...
+
+
+

12/03/2025

+
+ +
+ Xem thêm +
+
+
+ + + Xem tất cả + +
+ + +
+
+

+ Bản tin rao vặt +

+
+
+
+
+
+ + + +
+ Xu hướng công nghệ nhìn từ CES + 2025 +
Intel Core i5 / 8GB / 256GB / SSD +
+
19.999.000đ
+
+
+ +

Quận thanh xuân

+
+
+ +

30 phút trước

+
+
+

Còn 5 ngày

+
+
+ + avartar + Thanh mai + +
+
+
+ + + +
+ Xu hướng công nghệ nhìn từ CES + 2025 +
Intel Core i5 / 8GB / 256GB / SSD +
+
19.999.000đ
+
+
+ +

Quận thanh xuân

+
+
+ +

30 phút trước

+
+
+

Còn 5 ngày

+
+
+ + avartar + Thanh mai + +
+
+
+ + + +
+ Xu hướng công nghệ nhìn từ CES + 2025 +
Intel Core i5 / 8GB / 256GB / SSD +
+
19.999.000đ
+
+
+ +

Quận thanh xuân

+
+
+ +

30 phút trước

+
+
+

Còn 5 ngày

+
+
+ + avartar + Thanh mai + +
+
+
+ + + +
+ Xu hướng công nghệ nhìn từ CES + 2025 +
Intel Core i5 / 8GB / 256GB / SSD +
+
19.999.000đ
+
+
+ +

Quận thanh xuân

+
+
+ +

30 phút trước

+
+
+

Còn 5 ngày

+
+
+ + avartar + Thanh mai + +
+
+ +
+ + Xem tất cả + +
+ + +
+
+
+ + + + + +
+
+
+
+
+

+ Sự kiện và chương trình khuyến mãi +

+
+
+
+ + + +
+
diff --git a/template/javascript/index.html b/template/javascript/index.html new file mode 100644 index 0000000..a3734ca --- /dev/null +++ b/template/javascript/index.html @@ -0,0 +1,2 @@ + + diff --git a/template/shared/footer.html b/template/shared/footer.html new file mode 100644 index 0000000..1d477a4 --- /dev/null +++ b/template/shared/footer.html @@ -0,0 +1,44 @@ + diff --git a/template/shared/header.html b/template/shared/header.html new file mode 100644 index 0000000..a129a82 --- /dev/null +++ b/template/shared/header.html @@ -0,0 +1,458 @@ + +
+
+
+
+ +
+ +
+ Bạn đang ở +
+ +
+
+
+ +
+
+ + Tài khoản + +
+
+
+
+
+ + +
diff --git a/template/theme.html b/template/theme.html new file mode 100644 index 0000000..d61cd7b --- /dev/null +++ b/template/theme.html @@ -0,0 +1,104 @@ + + + + + + + BESTPC - Trang chủ + + + + + + + +
+ + {% include shared/header %} + + {{ page_content }} + + {% include shared/footer %} + +
+ +{% include javascript/index %} + + + + + + +