| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443 |
- {include file="header" /}
- <link rel="stylesheet" href="/assets/xtu/page-compare.css?v=20260625-1420">
- {php}
- $compareCategory = isset($category) ? $category : getCategory($catid ?? 41);
- $productModelId = 2;
- $catNames = \addons\cms\model\Category::where('modelid', $productModelId)
- ->where('status', 1)
- ->order('listorder DESC,id DESC')
- ->column('catname', 'id');
- $catNames = is_array($catNames) ? $catNames : [];
- $catNames = array_filter($catNames, function ($catName, $catId) {
- return (int)$catId > 0 && trim((string)$catName) !== '';
- }, ARRAY_FILTER_USE_BOTH);
- $productCatIds = array_map('intval', array_keys($catNames));
- $productCatIds = array_filter($productCatIds, function ($catId) {
- return $catId > 0;
- });
- $productWhere = '`status` = 1';
- if (!empty($productCatIds)) {
- $productWhere = "`catid` in(" . implode(',', $productCatIds) . ") AND " . $productWhere;
- }
- $productList = !empty($productCatIds) ? (new \addons\cms\model\Cms())->getList(
- $productModelId,
- $productWhere,
- 1,
- '*',
- 'listorder DESC,id DESC',
- 50,
- false
- ) : [];
- $productList = is_array($productList) ? $productList : [];
- $compareText = function ($key, $default) {
- return function_exists('cms_t') ? cms_t($key, $default) : $default;
- };
- foreach ($productList as &$productItem) {
- $productItem['cat_label'] = $catNames[(int)($productItem['catid'] ?? 0)] ?? '';
- }
- unset($productItem);
- $productMap = [];
- $allowedProductIds = [];
- foreach ($productList as $productItem) {
- $productId = (int)($productItem['id'] ?? 0);
- if ($productId <= 0) {
- continue;
- }
- $productMap[$productId] = $productItem;
- $allowedProductIds[$productId] = true;
- }
- $selectedIds = [];
- $requestSelected = request()->param('compare_ids/a', []);
- if (!empty($requestSelected) && is_array($requestSelected)) {
- foreach ($requestSelected as $selectedId) {
- $selectedId = (int)$selectedId;
- if ($selectedId > 0 && isset($allowedProductIds[$selectedId]) && !in_array($selectedId, $selectedIds, true)) {
- $selectedIds[] = $selectedId;
- }
- if (count($selectedIds) >= 3) {
- break;
- }
- }
- }
- if (empty($selectedIds)) {
- foreach ($productList as $productItem) {
- $selectedId = (int)($productItem['id'] ?? 0);
- if ($selectedId <= 0 || in_array($selectedId, $selectedIds, true)) {
- continue;
- }
- $selectedIds[] = $selectedId;
- if (count($selectedIds) >= 3) {
- break;
- }
- }
- }
- $selectedProducts = [];
- foreach ($selectedIds as $selectedId) {
- if (isset($productMap[$selectedId])) {
- $selectedProducts[] = $productMap[$selectedId];
- }
- }
- if (count($selectedProducts) > 3) {
- $selectedProducts = array_slice($selectedProducts, 0, 3);
- }
- while (count($selectedProducts) < 3 && !empty($productList)) {
- foreach ($productList as $productItem) {
- $exists = false;
- foreach ($selectedProducts as $selectedProduct) {
- if ((int)$selectedProduct['id'] === (int)$productItem['id']) {
- $exists = true;
- break;
- }
- }
- if (!$exists) {
- $selectedProducts[] = $productItem;
- break;
- }
- }
- if (count($selectedProducts) >= count($productList)) {
- break;
- }
- }
- $selectedProducts = array_slice($selectedProducts, 0, 3);
- $selectedIds = array_map(function ($product) {
- return (int)($product['id'] ?? 0);
- }, $selectedProducts);
- $specWhere = "`catid` = 10 AND `status` = 1";
- if (!empty($selectedIds)) {
- $specWhere .= " AND `project_id` in(" . implode(',', $selectedIds) . ")";
- }
- $specRows = (new \addons\cms\model\Cms())->getList(6, $specWhere, 1, '*', 'listorder ASC,id ASC', 500, false);
- $specRows = is_array($specRows) ? $specRows : [];
- $specFieldMeta = cms_cache('ModelField')[6] ?? [];
- $enabledFieldTitles = [];
- foreach ($specFieldMeta as $fieldName => $fieldMeta) {
- if ((int)($fieldMeta['status'] ?? 0) !== 1) {
- continue;
- }
- $enabledFieldTitles[$fieldName] = trim((string)($fieldMeta['title'] ?? $fieldName));
- }
- $compareFieldGroups = [
- $compareText('compare_group_camera', '相机') => [
- ['name' => '__cat_label', 'label' => $compareText('compare_label_category', '所属分类')],
- ['name' => '__sj_status', 'label' => $compareText('compare_label_sale_status', '上架状态')],
- ],
- $compareText('compare_group_general', '通用') => [
- ['name' => 'size', 'label' => $compareText('compare_label_size', '尺寸')],
- ['name' => 'waterproof', 'label' => $compareText('compare_label_waterproof', '防水')],
- ['name' => 'mac', 'label' => $compareText('compare_label_microphone', '麦克风')],
- ['name' => 'weight', 'label' => $compareText('compare_label_weight', '重量')],
- ['name' => 'conn_method', 'label' => $compareText('compare_label_connection_method', '连接方式')],
- ['name' => 'color_ver', 'label' => $compareText('compare_label_color_version', '颜色版本')],
- ['name' => 'vertical_shoot', 'label' => $compareText('compare_label_vertical_shoot', '原生竖拍')],
- ['name' => 'live_stream', 'label' => $compareText('compare_label_live_stream', '直播功能')],
- ],
- $compareText('compare_group_display', '显示屏') => [
- ['name' => 'rear_screen', 'label' => $compareText('compare_label_rear_screen', '后置显示屏')],
- ['name' => 'front_screen', 'label' => $compareText('compare_label_front_screen', '前置显示屏')],
- ['name' => 'main_cpu', 'label' => $compareText('compare_label_main_cpu', '主控CPU')],
- ['name' => 'image_sensor', 'label' => $compareText('compare_label_image_sensor', '影像传感器')],
- ['name' => 'iso_range', 'label' => $compareText('compare_label_iso_range', 'ISO范围')],
- ['name' => 'e_shutter_speed', 'label' => $compareText('compare_label_e_shutter_speed', '电子快门速度')],
- ['name' => 'normal_video', 'label' => $compareText('compare_label_normal_video', '普通录影')],
- ['name' => 'hdr_video', 'label' => $compareText('compare_label_hdr_video', 'HDR录影')],
- ['name' => 'night_mode', 'label' => $compareText('compare_label_night_mode', '夜景模式')],
- ['name' => 'slowmo_video', 'label' => $compareText('compare_label_slowmo_video', '慢动作录影')],
- ['name' => 'raw_photo', 'label' => $compareText('compare_label_raw_photo', 'RAW拍照')],
- ['name' => 'time_lapse', 'label' => $compareText('compare_label_time_lapse', '延时摄影')],
- ['name' => 'pre_record_time', 'label' => $compareText('compare_label_pre_record_time', '预录时长')],
- ['name' => 'horizon_level', 'label' => $compareText('compare_label_horizon_level', '地平线矫正')],
- ['name' => 'stabilization', 'label' => $compareText('compare_label_stabilization', '防抖')],
- ['name' => 'video_max_bitrate', 'label' => $compareText('compare_label_video_max_bitrate', '视频储存最大码流')],
- ['name' => 'file_system', 'label' => $compareText('compare_label_file_system', '支持文件系统')],
- ['name' => 'image_format', 'label' => $compareText('compare_label_image_format', '图片格式')],
- ['name' => 'video_format', 'label' => $compareText('compare_label_video_format', '视频格式')],
- ['name' => 'sd_card_type', 'label' => $compareText('compare_label_sd_card_type', '支持存储卡类型')],
- ['name' => 'audio_record', 'label' => $compareText('compare_label_audio_record', '音频录制')],
- ],
- $compareText('compare_group_battery', '电池') => [
- ['name' => 'battery_type', 'label' => $compareText('compare_label_battery_type', '类型')],
- ['name' => 'battery_cap', 'fallback' => 'battery_capacity', 'label' => $compareText('compare_label_battery_cap', '容量')],
- ['name' => 'battery_energy', 'label' => $compareText('compare_label_battery_energy', '能量')],
- ['name' => 'battery_voltage', 'label' => $compareText('compare_label_battery_voltage', '电压')],
- ['name' => 'work_temp', 'fallback' => 'operating_temperature', 'label' => $compareText('compare_label_work_temp', '使用环境温度')],
- ['name' => 'fast_charge', 'fallback' => 'fast_charging', 'label' => $compareText('compare_label_fast_charge', '是否支持快充')],
- ['name' => 'charge_time', 'fallback' => 'charging_time', 'label' => $compareText('compare_label_charge_time', '充电时间')],
- ['name' => 'battery_life', 'label' => $compareText('compare_label_battery_life', '续航时间')],
- ],
- $compareText('compare_group_connectivity', '连接') => [
- ['name' => 'wifi_freq', 'fallback' => 'wifi_frequency', 'label' => $compareText('compare_label_wifi_freq', 'Wi-Fi 工作频率')],
- ['name' => 'wifi_proto', 'fallback' => 'wifi_protocol', 'label' => $compareText('compare_label_wifi_proto', 'Wi-Fi 协议')],
- ['name' => 'bt_freq', 'fallback' => 'bluetooth_frequency', 'label' => $compareText('compare_label_bt_freq', '蓝牙工作频率')],
- ['name' => 'bt_proto', 'fallback' => 'bluetooth_protocol', 'label' => $compareText('compare_label_bt_proto', '蓝牙协议')],
- ],
- $compareText('compare_group_other_features', '其他功能') => [
- ['name' => 'bt_setup', 'fallback' => 'bluetooth_setup', 'label' => $compareText('compare_label_bt_setup', '蓝牙配网')],
- ['name' => 'rev_charge', 'fallback' => 'reverse_charging', 'label' => $compareText('compare_label_rev_charge', '应急反向充电')],
- ['name' => 'voice_ctrl', 'fallback' => 'voice_control', 'label' => $compareText('compare_label_voice_ctrl', '语音控制')],
- ['name' => 'quick_record', 'fallback' => 'quick_start_recording', 'label' => $compareText('compare_label_quick_record', '快启(快启录像)')],
- ],
- ];
- $specGroups = [];
- $specGroupOrder = [];
- foreach ($compareFieldGroups as $groupName => $groupFields) {
- $rows = [];
- foreach ($groupFields as $fieldDef) {
- $fieldName = $fieldDef['name'];
- $fallbackFieldName = $fieldDef['fallback'] ?? '';
- $fieldLabel = $fieldDef['label'];
- $rowValues = [];
- if ($fieldName === '__cat_label') {
- foreach ($selectedProducts as $product) {
- $rowValues[(int)$product['id']] = (string)($product['cat_label'] ?? '-');
- }
- $rows[] = ['label' => $fieldLabel, 'values' => $rowValues];
- continue;
- }
- if ($fieldName === '__sj_status') {
- foreach ($selectedProducts as $product) {
- $productId = (int)$product['id'];
- $statusText = '';
- foreach ($specRows as $specItem) {
- if ((int)($specItem['project_id'] ?? 0) !== $productId) {
- continue;
- }
- $statusText = trim((string)($specItem['list'] ?? ''));
- break;
- }
- $rowValues[$productId] = $statusText;
- }
- $rows[] = ['label' => $fieldLabel, 'values' => $rowValues];
- continue;
- }
- if (!isset($enabledFieldTitles[$fieldName]) && (!$fallbackFieldName || !isset($enabledFieldTitles[$fallbackFieldName]))) {
- continue;
- }
- foreach ($specRows as $specItem) {
- $projectId = (int)($specItem['project_id'] ?? 0);
- if ($projectId <= 0) {
- continue;
- }
- $rawValue = $specItem[$fieldName] ?? '';
- if (($rawValue === '' || $rawValue === null) && $fallbackFieldName !== '') {
- $rawValue = $specItem[$fallbackFieldName] ?? '';
- }
- if (is_array($rawValue)) {
- $rawValue = implode(' / ', $rawValue);
- }
- $rawValue = preg_replace('/<br\s*\/?>/i', "\n", (string)$rawValue);
- $value = trim(strip_tags($rawValue));
- $rowValues[$projectId] = $value;
- }
- foreach ($selectedProducts as $product) {
- $productId = (int)$product['id'];
- if (!isset($rowValues[$productId])) {
- $rowValues[$productId] = '';
- }
- }
- $rows[] = ['label' => $fieldLabel, 'values' => $rowValues];
- }
- if (!empty($rows)) {
- $specGroups[$groupName] = $rows;
- $specGroupOrder[] = $groupName;
- }
- }
- {/php}
- <main class="compare-page">
- <section class="compare-hero">
- <div class="compare-hero-banner">
- <img class="compare-hero-image" src="{:getCategory(41,'image')}" alt="{:getCategory(41,'catname')}">
- <div class="compare-hero-minimal">
- <div class="compare-shell">
- <div class="compare-hero-copy">
- <span class="compare-hero-overline">{:cms_t('compare_hero_overline','选购指南')}</span>
- <h1>{if getCategory(41,'description')}{:getCategory(41,'description')}{else /}{:getCategory(41,'catname')}{/if}</h1>
- </div>
- </div>
- </div>
- </div>
- </section>
- <section class="compare-main">
- <div class="compare-shell">
- <form class="compare-toolbar" method="get" action="{:getCategory($catid,'url')}" id="compareToolbarForm">
- {volist name="selectedProducts" id="selectedProduct" key="slotIndex"}
- <div class="compare-dropdown" data-compare-dropdown>
- <input type="hidden" name="compare_ids[]" value="{$selectedProduct.id}" data-compare-input>
- <button type="button" class="compare-dropdown-toggle" data-compare-toggle aria-expanded="false">
- <span class="compare-dropdown-text">
- <strong>{$selectedProduct.title}</strong>
- <small>{$selectedProduct.cat_label|default=cms_t('compare_product_series','产品系列')}</small>
- </span>
- <span class="compare-dropdown-icon"></span>
- </button>
- <div class="compare-dropdown-menu" data-compare-menu>
- {volist name="productList" id="option"}
- <button type="button" class="compare-dropdown-item {if $option.id == $selectedProduct.id}is-active{/if}" data-value="{$option.id}" data-label="{$option.title}" data-subtitle="{$option.cat_label|default=cms_t('compare_product_series','产品系列')}">
- <span class="compare-dropdown-item-title">{$option.title}</span>
- <span class="compare-dropdown-item-subtitle">{$option.cat_label|default=cms_t('compare_product_series','产品系列')}</span>
- </button>
- {/volist}
- </div>
- </div>
- {/volist}
- </form>
- <div class="compare-products">
- {volist name="selectedProducts" id="product"}
- <article class="compare-product-card">
- <div class="compare-product-media">
- <img src="{$product.thumb|default=$product.thumb2}" alt="{$product.title}">
- </div>
- <h3 class="compare-product-title">{$product.title}</h3>
- <div class="compare-product-subtitle">{$product.title1|default=$product.title2|default=''}</div>
- <div class="compare-product-actions">
- <a class="compare-buy-btn" href="{$product.url}">{:cms_t('buy_now','立即购买')}</a>
- <a class="compare-more-link" href="{$product.url}">{:cms_t('learn_more','了解更多')} <i class="bi bi-chevron-right"></i></a>
- </div>
- </article>
- {/volist}
- </div>
- <div class="compare-table-wrap">
- {if empty($specGroupOrder)}
- <div class="compare-empty">{:cms_t('compare_empty_desc','当前还没有匹配到参数数据。请确认参数栏目 ID 10 下的内容已启用,并且每条参数内容的 project_id 正确关联到了产品内容 ID。')}</div>
- {else /}
- {volist name="specGroupOrder" id="groupName"}
- <h2 class="compare-group-title">{$groupName}</h2>
- <div class="compare-table-scroll">
- <table class="compare-spec-table">
- <colgroup>
- <col>
- <col>
- <col>
- <col>
- </colgroup>
- <tbody>
- {volist name="specGroups[$groupName]" id="specRow"}
- <tr>
- <th>{$specRow.label}</th>
- {volist name="selectedProducts" id="productForValue"}
- <td>{$specRow.values[$productForValue.id]|default=''}</td>
- {/volist}
- </tr>
- {/volist}
- </tbody>
- </table>
- </div>
- {/volist}
- {/if}
- </div>
- </div>
- </section>
- </main>
- <script>
- document.addEventListener('DOMContentLoaded', function () {
- const form = document.getElementById('compareToolbarForm')
- const dropdowns = document.querySelectorAll('[data-compare-dropdown]')
- let submitTimer = null
- let submitting = false
- const closeAll = () => {
- dropdowns.forEach((dropdown) => {
- dropdown.classList.remove('is-open')
- const toggle = dropdown.querySelector('[data-compare-toggle]')
- if (toggle) toggle.setAttribute('aria-expanded', 'false')
- })
- }
- const markSubmitting = () => {
- submitting = true
- dropdowns.forEach((dropdown) => {
- dropdown.classList.add('is-busy')
- const toggle = dropdown.querySelector('[data-compare-toggle]')
- if (toggle) toggle.disabled = true
- })
- }
- const scheduleSubmit = () => {
- if (!form || submitting) return
- if (submitTimer) window.clearTimeout(submitTimer)
- submitTimer = window.setTimeout(() => {
- markSubmitting()
- form.submit()
- }, 120)
- }
- const getCurrentSelectedValues = () => Array.from(dropdowns).map((dropdown) => {
- const input = dropdown.querySelector('[data-compare-input]')
- return input ? String(input.value || '') : ''
- })
- dropdowns.forEach((dropdown) => {
- const toggle = dropdown.querySelector('[data-compare-toggle]')
- const input = dropdown.querySelector('[data-compare-input]')
- const items = dropdown.querySelectorAll('.compare-dropdown-item')
- if (!toggle || !input) return
- toggle.addEventListener('click', function (event) {
- event.preventDefault()
- if (submitting) return
- const isOpen = dropdown.classList.contains('is-open')
- closeAll()
- if (!isOpen) {
- dropdown.classList.add('is-open')
- toggle.setAttribute('aria-expanded', 'true')
- }
- })
- items.forEach((item) => {
- item.addEventListener('click', function () {
- if (submitting) return
- const nextValue = String(item.dataset.value || '')
- const currentValues = getCurrentSelectedValues()
- const currentValue = String(input.value || '')
- const duplicateUsed = currentValues.some((value, index) => value === nextValue && dropdowns[index] !== dropdown)
- if (duplicateUsed || nextValue === currentValue) {
- closeAll()
- return
- }
- input.value = nextValue
- const titleNode = toggle.querySelector('strong')
- const subtitleNode = toggle.querySelector('small')
- if (titleNode) titleNode.textContent = item.dataset.label || ''
- if (subtitleNode) subtitleNode.textContent = item.dataset.subtitle || ''
- closeAll()
- scheduleSubmit()
- })
- })
- })
- document.addEventListener('click', function (event) {
- if (!event.target.closest('[data-compare-dropdown]')) {
- closeAll()
- }
- })
- document.addEventListener('keydown', function (event) {
- if (event.key === 'Escape') closeAll()
- })
- })
- </script>
- {include file="footer" /}
|