feat: add installer files & update docker-compose.yaml

This commit is contained in:
xuwei-fit2cloud
2025-08-04 17:27:52 +08:00
parent 0aff8e1d78
commit fdb362d2a9
10 changed files with 1223 additions and 33 deletions

View File

@@ -1,26 +0,0 @@
PROJECT_NAME="SQLBot"
# Backend
BACKEND_CORS_ORIGINS="http://localhost,http://localhost:5173,https://localhost,https://localhost:5173"
SECRET_KEY=y5txe1mRmS_JpOrUzFzHEu-kIQn3lf7ll0AOv9DQh0s
TOKEN_KEY="X-SQLBOT-TOKEN"
DEFAULT_PWD="SQLBot@123456"
ASSISTANT_TOKEN_KEY="X-SQLBOT-ASSISTANT-TOKEN"
LOG_LEVEL="INFO" # DEBUG, INFO, WARNING, ERROR
LOG_DIR="/opt/sqlbot/logs"
LOG_FORMAT="%(asctime)s - %(name)s - %(levelname)s:%(lineno)d - %(message)s"
SQL_DEBUG=False
CACHE_TYPE="memory"
# Postgres
POSTGRES_SERVER=localhost
POSTGRES_PORT=5432
POSTGRES_DB=sqlbot
POSTGRES_USER=root
POSTGRES_PASSWORD=132456 # Change this to your pwd
MCP_IMAGE_PATH=/opt/sqlbot/images
MCP_IMAGE_HOST=http://localhost:3000
SERVER_IMAGE_HOST=https://sqlbot.fit2cloud.cn/images/

View File

@@ -19,19 +19,13 @@ services:
PROJECT_NAME: "SQLBot"
DEFAULT_PWD: "SQLBot@123456"
# MCP settings
MCP_IMAGE_PATH: /opt/sqlbot/images
MCP_IMAGE_HOST: http://localhost:3000
SERVER_IMAGE_HOST: https://sqlbot.fit2cloud.cn/images/
SERVER_IMAGE_HOST: https://YOUR_SERVE_IP:MCP_PORT/images/
# Auth & Security
TOKEN_KEY: "X-SQLBOT-TOKEN"
ASSISTANT_TOKEN_KEY: "X-SQLBOT-ASSISTANT-TOKEN"
SECRET_KEY: y5txe1mRmS_JpOrUzFzHEu-kIQn3lf7ll0AOv9DQh0s
# CORS settings
BACKEND_CORS_ORIGINS: "http://localhost,http://localhost:5173,https://localhost,https://localhost:5173"
# Logging
LOG_LEVEL: "INFO"
LOG_DIR: "/opt/sqlbot/logs"
LOG_FORMAT: "%(asctime)s - %(name)s - %(levelname)s:%(lineno)d - %(message)s"
SQL_DEBUG: False
volumes:
- ./data/sqlbot/excel:/opt/sqlbot/data/excel

View File

@@ -0,0 +1,16 @@
services:
sqlbot-db:
image: registry.cn-qingdao.aliyuncs.com/dataease/postgres:17.5
container_name: sqlbot-db
restart: always
networks:
- sqlbot-network
volumes:
- ./data/postgresql:/var/lib/postgresql/data
env_file:
- conf/sqlbot.conf
healthcheck:
test: ["CMD-SHELL", "pg_isready"]
interval: 3s
timeout: 5s
retries: 5

View File

@@ -0,0 +1,22 @@
services:
sqlbot:
image: registry.cn-qingdao.aliyuncs.com/dataease/sqlbot:v0.9.5
container_name: sqlbot
restart: always
networks:
- sqlbot-network
ports:
- ${SQLBOT_WEB_PORT}:8000
- ${SQLBOT_MCP_PORT}:8001
env_file:
- conf/sqlbot.conf
volumes:
- ./data/sqlbot/excel:/opt/sqlbot/data/excel
- ./data/sqlbot/images:/opt/sqlbot/images
- ./data/sqlbot/logs:/opt/sqlbot/logs
depends_on:
sqlbot-db:
condition: service_healthy
networks:
sqlbot-network:

34
installer/install.conf Normal file
View File

@@ -0,0 +1,34 @@
# 基础配置
## 安装目录
SQLBOT_BASE=/opt
## SQLBot 端口
SQLBOT_WEB_PORT=8000
SQLBOT_MCP_PORT=8001
# 数据库配置
## 是否使用外部数据库
SQLBOT_EXTERNAL_DB=false
## 数据库地址
SQLBOT_DB_HOST=sqlbot-db
## 数据库端口 (仅使用外部数据库时才生效)
SQLBOT_DB_PORT=5432
## SQLBot 数据库库名
SQLBOT_DB_DB=sqlbot
## 数据库用户名
SQLBOT_DB_USER=root
## 数据库密码,密码如包含特殊字符,请用双引号引起来,例如 SQLBOT_DB_PASSWORD="Test@4&^%*^"
SQLBOT_DB_PASSWORD=Password123@pg
# 其他配置
## 普通用户默认密码
SQLBOT_DEFAULT_PWD=SQLBot@123456
## SQLBot Secret Key
SQLBOT_SECRET_KEY=y5txe1mRmS_JpOrUzFzHEu-kIQn3lf7ll0AOv9DQh0s
## Cross-Origin Resource Sharing (CORS) 设置
SQLBOT_CORS_ORIGINS=http://localhost,http://localhost:5173,https://localhost,https://localhost:5173
## 日志级别 DEBUG, INFO, WARNING, ERROR
SQLBOT_LOG_LEVEL="INFO"
## 缓存类型
SQLBOT_CACHE_TYPE="memory"
## MCP 图片存储路径
SQLBOT_SERVER_IMAGE_HOST=https://YOUR_SERVER_IP:MCP_PORT/images/

284
installer/install.sh Normal file
View File

@@ -0,0 +1,284 @@
#!/bin/bash
INSTALL_TYPE='install'
title_count=1
CURRENT_DIR=$(
cd "$(dirname "$0")"
pwd
)
function log() {
echo -e "${1}" 2>&1 | tee -a ${CURRENT_DIR}/install.log
}
function log_title () {
log "${title_count}. ${1}"
let title_count++
}
function log_content () {
log "\t${1}"
}
function check_and_prepare_env_params() {
log "当前时间 : $(date)"
log_title "检查安装环境并初始化环境变量"
cd ${CURRENT_DIR}
if [ -f /usr/bin/sctl ]; then
echo "当前版本: $(sctl version | head -n 1)"
# 获取已安装的 SQLBOT 的运行目录
SQLBOT_BASE=$(grep "^SQLBOT_BASE=" /usr/bin/sctl | cut -d'=' -f2)
SQLBOT_BASE_OLD=${SQLBOT_BASE}
sed -i -e "s#SQLBOT_BASE=.*#SQLBOT_BASE_BASE=${SQLBOT_BASE}#g" sctl
\cp sctl /usr/local/bin && chmod +x /usr/local/bin/sctl
log_content "停止 SQLBot 服务"
sctl stop
INSTALL_TYPE='upgrade'
fi
set -a
source ${CURRENT_DIR}/install.conf
if [[ ${SQLBOT_BASE_OLD} ]];then
SQLBOT_BASE=${SQLBOT_BASE_OLD}
export SQLBOT_BASE=${SQLBOT_BASE_OLD}
fi
if [[ -d ${SQLBOT_BASE} ]] && [[ -f ${SQLBOT_BASE}/sqlbot/.env ]]; then
source $SQLBOT_BASE/sqlbot/.env
INSTALL_TYPE='upgrade'
log_content "升级安装"
else
INSTALL_TYPE='install'
mkdir -p ${SQLBOT_BASE}
log_content "全新安装"
fi
set +a
}
function set_run_base_path() {
log_title "设置运行目录"
SQLBOT_RUN_BASE=$SQLBOT_BASE/sqlbot
CONF_FOLDER=${SQLBOT_RUN_BASE}/conf
TEMPLATES_FOLDER=${SQLBOT_RUN_BASE}/templates
log_content "运行目录 $SQLBOT_RUN_BASE"
log_content "配置文件目录 $CONF_FOLDER"
}
function prepare_sqlbot_run_base() {
log_title "初始化运行目录"
cd ${CURRENT_DIR}
mkdir -p ${SQLBOT_RUN_BASE}
log_content "复制安装文件到运行目录"
cp -r ./sqlbot/* ${SQLBOT_RUN_BASE}/
cd ${SQLBOT_RUN_BASE}
env | grep SQLBOT_ >.env
mkdir -p ${SQLBOT_RUN_BASE}/conf
mkdir -p ${SQLBOT_RUN_BASE}/data/sqlbot/{excel,images,logs}
if [ "${SQLBOT_EXTERNAL_DB}" = "false" ]; then
mkdir -p ${SQLBOT_RUN_BASE}/data/postgresql
export SQLBOT_DB_PORT=5432
else
sed -i -e "/^ depends_on/,+2d" docker-compose.yml
fi
log_content "调整配置文件参数"
cd ${SQLBOT_RUN_BASE}
cp -r ${TEMPLATES_FOLDER}/* ${CONF_FOLDER}
cd ${TEMPLATES_FOLDER}
templates_files=( sqlbot.conf )
for i in ${templates_files[@]}; do
if [ -f $i ]; then
envsubst < $i > ${CONF_FOLDER}/$i
fi
done
}
function update_sctl() {
log_title "安装 sctl 命令行工具"
log_content "安装至 /usr/local/bin/sctl & /usr/bin/sctl"
cd ${CURRENT_DIR}
sed -i -e "s#SQLBOT_BASE=.*#SQLBOT_BASE=${SQLBOT_BASE}#g" sctl
\cp sctl /usr/local/bin && chmod +x /usr/local/bin/sctl
if [ ! -f /usr/bin/sctl ]; then
ln -s /usr/local/bin/sctl /usr/bin/sctl 2>/dev/null
fi
}
function prepare_system_settings() {
log_title "修改操作系统相关设置"
if which getenforce >/dev/null 2>&1 && [ $(getenforce) == "Enforcing" ];then
log_content "关闭 SELINUX"
setenforce 0
sed -i "s/SELINUX=enforcing/SELINUX=disabled/g" /etc/selinux/config
fi
if which firewall-cmd >/dev/null 2>&1; then
if systemctl is-active firewalld &>/dev/null ;then
log_content "开启防火墙端口 ${SQLBOT_WEB_PORT}"
firewall-cmd --zone=public --add-port=${SQLBOT_WEB_PORT}/tcp --permanent
log_content "开启防火墙端口 ${SQLBOT_MCP_PORT}"
firewall-cmd --zone=public --add-port=${SQLBOT_MCP_PORT}/tcp --permanent
firewall-cmd --reload
else
log_content "防火墙未开启,忽略端口开放"
fi
fi
}
function install_docker() {
log_title "安装 docker"
#Install docker
##Install Latest Stable Docker Release
cd ${CURRENT_DIR}
if which docker >/dev/null 2>&1; then
log_content "检测到 Docker 已安装,跳过安装步骤"
log_content "启动 Docker "
service docker start >/dev/null 2>&1 | tee -a ${CURRENT_DIR}/install.log
else
if [[ -d docker ]]; then
log_content "离线安装 docker"
cp docker/bin/* /usr/bin/
cp docker/service/docker.service /etc/systemd/system/
chmod +x /usr/bin/docker*
chmod 644 /etc/systemd/system/docker.service
else
log_content "在线安装 docker"
curl -fsSL https://resource.fit2cloud.com/get-docker-linux.sh -o get-docker.sh 2>&1 | tee -a ${CURRENT_DIR}/install.log
if [[ ! -f get-docker.sh ]];then
log_content "docker 在线安装脚本下载失败,请稍候重试"
exit 1
fi
sudo sh get-docker.sh 2>&1 | tee -a ${CURRENT_DIR}/install.log
fi
docker_config_folder="/etc/docker"
if [ ! -d "$docker_config_folder" ];then
mkdir -p "$docker_config_folder"
cat <<EOF> $docker_config_folder/daemon.json
{
"log-driver": "json-file",
"log-opts": {
"max-file": "3",
"max-size": "10m"
}
}
EOF
fi
log_content "启动 docker"
systemctl enable docker >/dev/null 2>&1; systemctl daemon-reload; systemctl start docker 2>&1 | tee -a ${CURRENT_DIR}/install.log
docker version >/dev/null 2>&1
if [ $? -ne 0 ]; then
log_content "docker 安装失败"
exit 1
else
log_content "docker 安装成功"
fi
fi
}
function install_docker_compose() {
log_title "安装 docker-compose"
#Install docker-compose
cd ${CURRENT_DIR}
##Install Latest Stable Docker Compose Release
docker-compose version >/dev/null 2>&1
if [ $? -ne 0 ]; then
docker compose version >/dev/null 2>&1
if [ $? -eq 0 ]; then
echo 'docker compose "$@"' > /usr/bin/docker-compose
chmod +x /usr/bin/docker-compose
else
if [[ -d docker ]]; then
log_content "离线安装 docker-compose"
cp docker/bin/docker-compose /usr/bin/
chmod +x /usr/bin/docker-compose
else
log_content "在线安装 docker-compose"
curl -L https://resource.fit2cloud.com/docker/compose/releases/download/v2.16.0/docker-compose-$(uname -s | tr A-Z a-z)-$(uname -m) -o /usr/local/bin/docker-compose 2>&1 | tee -a ${CURRENT_DIR}/install.log
if [[ ! -f /usr/local/bin/docker-compose ]];then
log_content "docker-compose 下载失败,请稍候重试"
exit 1
fi
chmod +x /usr/local/bin/docker-compose
ln -s /usr/local/bin/docker-compose /usr/bin/docker-compose
fi
fi
docker-compose version >/dev/null
if [ $? -ne 0 ]; then
log_content "docker-compose 安装失败"
exit 1
else
log_content "docker-compose 安装成功"
fi
else
log_content "检测到 Docker Compose 已安装,跳过安装步骤"
fi
export COMPOSE_HTTP_TIMEOUT=180
}
function load_images() {
log_title "加载 SQLBOT 镜像"
cd ${CURRENT_DIR}
for i in $(docker images --format '{{.Repository}}:{{.Tag}}' | grep dataease); do
current_images[${#current_images[@]}]=${i##*/}
done
# 加载镜像
if [[ -d images ]]; then
for i in $(ls images); do
if [[ "${current_images[@]}" =~ "${i%.tar.gz}" ]]; then
log_content "已存在镜像 ${i%.tar.gz}"
else
log_content "加载镜像 ${i%.tar.gz}"
docker load -i images/$i >/dev/null 2>&1 | tee -a ${CURRENT_DIR}/install.log
fi
done
else
SQLBOTVERSION=$(cat ${CURRENT_DIR}/sqlbot/templates/version)
curl -sfL https://resource.fit2cloud.com/installation-log.sh | sh -s sqlbot ${INSTALL_TYPE} ${SQLBOTVERSION}
fi
}
function start_sqlbot() {
log_title "启动 SQLBOT 服务"
sctl reload 2>&1 | tee -a ${CURRENT_DIR}/install.log
if [[ $? -ne 0 ]]; then
log_content "SQLBOT 服务启动失败,请检查日志"
exit 1
fi
echo
if [[ $INSTALL_TYPE != "upgrade" ]];then
echo -e "======================= 安装完成 =======================\n" 2>&1 | tee -a ${CURRENT_DIR}/install.log
echo -e "系统登录信息如下:\n\t访问地址: http://服务器IP:$SQLBOT_WEB_PORT\n\t用户名: admin\n\t初始密码: SQLBot@123456" 2>&1 | tee -a ${CURRENT_DIR}/install.log
else
echo -e "======================= 升级完成 =======================\n" 2>&1 | tee -a ${CURRENT_DIR}/install.log
fi
}
function main() {
check_and_prepare_env_params
set_run_base_path
prepare_sqlbot_run_base
update_sctl
prepare_system_settings
install_docker
install_docker_compose
load_images
start_sqlbot
}
main

210
installer/sctl Normal file
View File

@@ -0,0 +1,210 @@
#!/bin/bash
action=$1
target=$2
SQLBOT_BASE=/opt
SQLBOT_RUNNING_BASE=${SQLBOT_BASE}/sqlbot
SQLBOT_LOG_PATH=${SQLBOT_RUNNING_BASE}/data/sqlbot/logs
compose_files="-f docker-compose.yml"
compose_cmd="docker-compose"
current_version=""
set -a
source ${SQLBOT_RUNNING_BASE}/.env
set +a
export COMPOSE_HTTP_TIMEOUT=180
docker-compose version >/dev/null 2>&1
if [ $? -ne 0 ]; then
docker compose version >/dev/null 2>&1
if [ $? -ne 0 ]; then
compose_cmd="docker compose"
fi
fi
if [[ ! ${SQLBOT_EXTERNAL_DB} ]] || [ "${SQLBOT_EXTERNAL_DB}" = "false" ]; then
compose_files="${compose_files} -f docker-compose-pg.yml"
fi
function usage() {
echo "SQLBot 控制脚本"
echo
echo "Usage: "
echo " ./sctl [COMMAND] [ARGS...]"
echo " ./sctl --help"
echo
echo "Commands: "
echo " status 查看 SQLBot 服务运行状态"
echo " start 启动 SQLBot 服务"
echo " stop 停止 SQLBot 服务"
echo " restart 重启 SQLBot 服务"
echo " reload 重载 SQLBot 服务"
echo " clear-images 清理 SQLBot 旧版本的相关镜像"
echo " clear-logs 清理 SQLBot 历史日志"
echo " version 查看 SQLBot 版本"
}
function _healthcheck() {
echo
container_name=$(grep "container_name" $SQLBOT_RUNNING_BASE/docker-compose.yml | awk -F': ' '{print $2}')
sleep 1
if [ -z '$(docker ps --filter "name=^$container_name$" -q)' ];then
echo "未找到容器 $container_name。"
exit 1
fi
for b in {1..90}
do
sleep 1
read status healthy<<<$(docker inspect $container_name --format '{{.State.Status}} {{.State.Health.Status}}')
if [[ "$healthy" == "starting" ]];then
printf "\rSQLBot 服务状态 : 正在启动 ... %3ds" $b
elif [[ "$status" == "running" ]] && [[ "$healthy" == "healthy" ]];then
printf "\rSQLBot 服务状态 : 正常运行 "
echo
return;
else
echo
echo -e "SQLBot 服务状态 : \033[31m无法访问\033[0m"
exit 1
fi
done
echo
echo "【警告】服务在等待时间内未完全启动!请稍后使用 sctl status 检查服务运行状况。"
echo
}
function _get_current_version() {
sqlbot_current_version=$(grep "^ image:.*sqlbot:" ${SQLBOT_RUNNING_BASE}/docker-compose.yml | awk -F'sqlbot:' '{print $2}')
if test -z $sqlbot_current_version; then
echo "获取当前版本失败,请检查当前版本是否正确"
exit 1
fi
current_version=$sqlbot_current_version
}
function status() {
echo
echo "SQLBot 容器运行状态"
cd ${SQLBOT_RUNNING_BASE}
${compose_cmd} ${compose_files} ps
echo
docker_root_dir=$(docker info | grep "Docker Root Dir" | awk -F': ' '{print $2}')
echo "Docker 目录及文件大小 : "
du -sh $docker_root_dir
echo
echo "Docker 目录所在磁盘使用情况 : "
df -H $docker_root_dir
echo
echo "日志文件大小 : "
du -Sh ${SQLBOT_RUNNING_BASE}/logs/
echo
echo "SQLBot 运行目录及文件大小 : "
du -sh ${SQLBOT_BASE}
echo
echo "SQLBot 运行目录使用情况 : "
df -H ${SQLBOT_BASE}
_healthcheck
}
function start() {
echo
cd ${SQLBOT_RUNNING_BASE}
${compose_cmd} ${compose_files} up -d
_healthcheck
}
function stop() {
echo
cd ${SQLBOT_RUNNING_BASE}
${compose_cmd} ${compose_files} down -v ${target}
}
function restart() {
stop
start
}
function reload() {
start
}
function version() {
echo
_get_current_version
echo "current version is $current_version"
}
function clear_images() {
echo
for f in $SQLBOT_RUNNING_BASE/*.yml; do
[[ -e "$f" ]] || break
grep "^ image:.*:" "$f" | uniq | while read -r component_image_defined; do
component_version=$(echo ${component_image_defined} | awk -F":" '{print $3}' | uniq)
component_image=$(echo ${component_image_defined} | awk -F'image: ' '{print $2}' | awk -F':' '{print $1}')
if [[ $(docker images | grep "$component_image[[:space:]]" | grep -v " $component_version " | wc -l) == 0 ]]; then
echo "$component_image 不存在旧版本镜像"
else
echo "存在非当前版本镜像 : "
docker images | grep "$component_image[[:space:]]" | grep -v " $component_version "
echo "清理${component}镜像"
docker rmi $(docker images | grep "$component_image[[:space:]]" | grep -v " $component_version " | awk -F' ' '{print $1":"$2}')
echo "清理完毕"
fi
done
done
if [ $(docker images -f dangling=true -q | wc -l) -gt 0 ]; then
echo "清理虚悬镜像"
docker rmi $(docker images -f dangling=true -q)
echo "清理完毕"
fi
}
function clear_logs() {
echo "开始清理 SQLBot 历史日志"
rm -rf ${SQLBOT_LOG_PATH}/*.*.*
echo "" > ${SQLBOT_LOG_PATH}/info.log
echo "" > ${SQLBOT_LOG_PATH}/debug.log
echo "" > ${SQLBOT_LOG_PATH}/error.log
echo "清理完毕"
}
function main() {
case "${action}" in
status)
status
;;
start)
start
;;
stop)
stop
;;
restart)
restart
;;
reload)
reload
;;
clear-images)
clear_images
;;
clear-logs)
clear_logs
;;
version)
version
;;
help)
usage
;;
--help)
usage
;;
"")
usage
;;
*)
echo "不支持的参数,请使用 help 或 --help 参数获取帮助"
;;
esac
}
main

View File

@@ -0,0 +1,20 @@
PROJECT_NAME="SQLBot"
# Backend
BACKEND_CORS_ORIGINS=${SQLBOT_CORS_ORIGINS}
SECRET_KEY=${SQLBOT_SECRET_KEY}
DEFAULT_PWD=${SQLBOT_DEFAULT_PWD}
LOG_LEVEL=${SQLBOT_LOG_LEVEL} # DEBUG, INFO, WARNING, ERROR
SQL_DEBUG=False
CACHE_TYPE=${SQLBOT_CACHE_TYPE}
# Postgres
POSTGRES_SERVER=${SQLBOT_DB_HOST}
POSTGRES_PORT=${SQLBOT_DB_PORT}
POSTGRES_DB=${SQLBOT_DB_DB}
POSTGRES_USER=${SQLBOT_DB_USER}
POSTGRES_PASSWORD=${SQLBOT_DB_PASSWORD} # Change this to your pwd
SERVER_IMAGE_HOST=${SQLBOT_SERVER_IMAGE_HOST}

43
installer/uninstall.sh Normal file
View File

@@ -0,0 +1,43 @@
#!/bin/bash
SQLBOT_BASE=/opt
read -r -p "即将卸载 SQLBot 服务,包括删除运行目录、数据及相关镜像,是否继续? [Y/n] " input
case $input in
[yY][eE][sS]|[yY])
echo "Yes"
;;
[nN][oO]|[nN])
echo "No"
exit 1
;;
*)
echo "无效输入..."
exit 1
;;
esac
echo "停止 SQLBot 服务"
sctl stop >/dev/null 2>&1
if [ -f /usr/bin/sctl ]; then
# 获取已安装的 SQLBot 的运行目录
SQLBOT_BASE=$(grep "^SQLBOT_BASE=" /usr/bin/sctl | cut -d'=' -f2)
fi
# 清理 SQLBot 相关镜像
if test ! -z "$(docker images -f dangling=true -q)"; then
echo "清理虚悬镜像"
docker rmi $(docker images -f dangling=true -q)
fi
if test -n "$(docker images | grep 'registry.cn-qingdao.aliyuncs.com/dataease/sqlbot')"; then
echo "清理 SQLBot 镜像"
docker rmi $(docker images | grep "registry.cn-qingdao.aliyuncs.com/dataease/sqlbot" | awk -F' ' '{print $1":"$2}')
fi
# 清理 SQLBot 运行目录及命令行工具 sctl
rm -rf ${SQLBOT_BASE}/sqlbot /usr/bin/sctl
echo "SQLBot 服务卸载完成"

593
sqlbot-assistant-demo.html Normal file
View File

@@ -0,0 +1,593 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>优购电商 - 您的一站式购物平台</title>
<style>
/* 全局样式 */
* {
margin: 0;
padding: 0;
box-sizing: border-box;
font-family: "Arial", "Microsoft YaHei", sans-serif;
}
/* 滚动条样式 */
::-webkit-scrollbar {
width: 8px;
height: 8px;
background-color: transparent;
}
::-webkit-scrollbar-thumb {
background-color: rgba(255, 107, 107, 0.5);
border-radius: 4px;
opacity: 0;
transition: opacity 0.3s;
}
:hover::-webkit-scrollbar-thumb,
:focus::-webkit-scrollbar-thumb,
:active::-webkit-scrollbar-thumb {
opacity: 1;
}
::-webkit-scrollbar-thumb:hover {
background-color: #ff6b6b;
}
body {
color: #333;
line-height: 1.6;
scrollbar-width: thin;
scrollbar-color: rgba(255, 107, 107, 0.5) transparent;
}
a {
text-decoration: none;
color: inherit;
}
.container {
width: 100%;
max-width: 1200px;
margin: 0 auto;
padding: 0 15px;
}
/* 导航栏 */
header {
background-color: #fff;
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
position: sticky;
top: 0;
z-index: 100;
}
.navbar {
display: flex;
justify-content: space-between;
align-items: center;
padding: 15px 0;
}
.logo {
font-size: 24px;
font-weight: bold;
color: #ff6b6b;
}
.nav-links {
display: flex;
list-style: none;
}
.nav-links li {
margin-left: 30px;
}
.nav-links a:hover {
color: #ff6b6b;
}
.mobile-menu {
display: none;
font-size: 24px;
cursor: pointer;
}
/* 英雄区域 */
.hero {
background: linear-gradient(135deg, #f6d365 0%, #fda085 100%);
color: white;
padding: 80px 0;
text-align: center;
}
.hero h1 {
font-size: 48px;
margin-bottom: 20px;
}
.hero p {
font-size: 20px;
max-width: 700px;
margin: 0 auto 30px;
}
.btn {
display: inline-block;
background-color: #ff6b6b;
color: white;
padding: 12px 30px;
border-radius: 30px;
font-weight: bold;
transition: all 0.3s;
}
.btn:hover {
background-color: #ff5252;
transform: translateY(-3px);
}
/* 特色服务 */
.features {
padding: 80px 0;
}
.section-title {
text-align: center;
margin-bottom: 50px;
}
.section-title h2 {
font-size: 36px;
color: #333;
}
.features-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
gap: 30px;
}
.feature-card {
background-color: white;
border-radius: 10px;
padding: 30px;
box-shadow: 0 5px 15px rgba(0, 0, 0, 0.05);
text-align: center;
transition: transform 0.3s;
}
.feature-card:hover {
transform: translateY(-10px);
}
.feature-icon {
font-size: 50px;
color: #ff6b6b;
margin-bottom: 20px;
}
.feature-card h3 {
margin-bottom: 15px;
font-size: 22px;
}
/* 热门产品 */
.products {
padding: 80px 0;
background-color: #f9f9f9;
}
.product-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
gap: 30px;
}
.product-card {
background-color: white;
border-radius: 10px;
overflow: hidden;
box-shadow: 0 5px 15px rgba(0, 0, 0, 0.05);
transition: all 0.3s;
}
.product-card:hover {
box-shadow: 0 10px 25px rgba(0, 0, 0, 0.1);
}
.product-img {
height: 200px;
overflow: hidden;
}
.product-img img {
width: 100%;
height: 100%;
object-fit: cover;
transition: transform 0.5s;
}
.product-card:hover .product-img img {
transform: scale(1.1);
}
.product-info {
padding: 20px;
}
.product-info h3 {
margin-bottom: 10px;
}
.price {
color: #ff6b6b;
font-weight: bold;
font-size: 18px;
margin: 15px 0;
}
/* 客户评价 */
.testimonials {
padding: 80px 0;
}
.testimonial-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
gap: 30px;
}
.testimonial-card {
background-color: white;
border-radius: 10px;
padding: 30px;
box-shadow: 0 5px 15px rgba(0, 0, 0, 0.05);
}
.testimonial-text {
font-style: italic;
margin-bottom: 20px;
}
.client-info {
display: flex;
align-items: center;
}
.client-img {
width: 50px;
height: 50px;
border-radius: 50%;
overflow: hidden;
margin-right: 15px;
}
.client-img img {
width: 100%;
height: 100%;
object-fit: cover;
}
/* 页脚 */
footer {
background-color: #333;
color: white;
padding: 60px 0 20px;
}
.footer-content {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
gap: 40px;
margin-bottom: 40px;
}
.footer-column h3 {
margin-bottom: 20px;
font-size: 18px;
}
.footer-links {
list-style: none;
}
.footer-links li {
margin-bottom: 10px;
}
.footer-links a:hover {
color: #ff6b6b;
}
.social-links {
display: flex;
gap: 15px;
}
.social-links a {
display: inline-block;
width: 40px;
height: 40px;
background-color: rgba(255, 255, 255, 0.1);
border-radius: 50%;
text-align: center;
line-height: 40px;
transition: all 0.3s;
}
.social-links a:hover {
background-color: #ff6b6b;
transform: translateY(-5px);
}
.copyright {
text-align: center;
padding-top: 20px;
border-top: 1px solid rgba(255, 255, 255, 0.1);
font-size: 14px;
}
/* 响应式设计 */
@media (max-width: 768px) {
.nav-links {
display: none;
}
.mobile-menu {
display: block;
}
.hero h1 {
font-size: 36px;
}
.hero p {
font-size: 18px;
}
}
</style>
<script
async
defer
id="sqlbot-assistant-float-script-7356228649239973888"
src="https://sqlbot.fit2cloud.cn/assistant.js?id=7356228649239973888"></script>
</head>
<body>
<!-- 导航栏 -->
<header>
<div class="container">
<nav class="navbar">
<a href="#" class="logo">优购电商</a>
<ul class="nav-links">
<li><a href="#">首页</a></li>
<li><a href="#">商品分类</a></li>
<li><a href="#">热销商品</a></li>
<li><a href="#">关于我们</a></li>
<li><a href="#">联系我们</a></li>
</ul>
<div class="mobile-menu"></div>
</nav>
</div>
</header>
<!-- 英雄区域 -->
<section class="hero">
<div class="container">
<h1>发现优质商品,享受便捷购物</h1>
<p>
优购电商为您提供海量正品商品全场包邮7天无理由退换货让您购物无忧
</p>
<a href="#" class="btn">立即购物</a>
</div>
</section>
<!-- 特色服务 -->
<section class="features">
<div class="container">
<div class="section-title">
<h2>我们的优势</h2>
</div>
<div class="features-grid">
<div class="feature-card">
<div class="feature-icon">🚚</div>
<h3>快速配送</h3>
<p>全国300+城市次日达,部分地区可实现当日送达</p>
</div>
<div class="feature-card">
<div class="feature-icon">🔒</div>
<h3>正品保障</h3>
<p>所有商品100%正品,假一赔十,购物更放心</p>
</div>
<div class="feature-card">
<div class="feature-icon">💯</div>
<h3>无忧售后</h3>
<p>7天无理由退换货专业客服团队24小时在线服务</p>
</div>
</div>
</div>
</section>
<!-- 热门产品 -->
<section class="products">
<div class="container">
<div class="section-title">
<h2>热门商品</h2>
</div>
<div class="product-grid">
<div class="product-card">
<div class="product-img">
<img
src="https://images.unsplash.com/photo-1523275335684-37898b6baf30?ixlib=rb-1.2.1&auto=format&fit=crop&w=500&q=80"
alt="智能手表"
/>
</div>
<div class="product-info">
<h3>智能手表 Pro</h3>
<p>多功能健康监测,超长续航</p>
<div class="price">¥899</div>
<a href="#" class="btn">加入购物车</a>
</div>
</div>
<div class="product-card">
<div class="product-img">
<img
src="https://images.unsplash.com/photo-1505740420928-5e560c06d30e?ixlib=rb-1.2.1&auto=format&fit=crop&w=500&q=80"
alt="无线耳机"
/>
</div>
<div class="product-info">
<h3>无线降噪耳机</h3>
<p>主动降噪Hi-Fi音质</p>
<div class="price">¥599</div>
<a href="#" class="btn">加入购物车</a>
</div>
</div>
<div class="product-card">
<div class="product-img">
<img
src="https://images.unsplash.com/photo-1561154464-82e9adf32764?ixlib=rb-1.2.1&auto=format&fit=crop&w=500&q=80"
alt="投影仪"
/>
</div>
<div class="product-info">
<h3>便携式投影仪</h3>
<p>1080P高清内置电池</p>
<div class="price">¥1299</div>
<a href="#" class="btn">加入购物车</a>
</div>
</div>
<div class="product-card">
<div class="product-img">
<img
src="https://images.unsplash.com/photo-1561154464-82e9adf32764?ixlib=rb-1.2.1&auto=format&fit=crop&w=500&q=80"
alt="空气炸锅"
/>
</div>
<div class="product-info">
<h3>智能空气炸锅</h3>
<p>无油健康烹饪,大容量</p>
<div class="price">¥399</div>
<a href="#" class="btn">加入购物车</a>
</div>
</div>
</div>
</div>
</section>
<!-- 客户评价 -->
<section class="testimonials">
<div class="container">
<div class="section-title">
<h2>客户评价</h2>
</div>
<div class="testimonial-grid">
<div class="testimonial-card">
<div class="testimonial-text">
"在优购电商购物体验非常好,商品质量有保障,物流速度也很快,客服态度也很专业,会继续支持!"
</div>
<div class="client-info">
<div class="client-img">
<img
src="https://randomuser.me/api/portraits/women/44.jpg"
alt="张女士"
/>
</div>
<div>
<h4>张女士</h4>
<p>上海</p>
</div>
</div>
</div>
<div class="testimonial-card">
<div class="testimonial-text">
"第一次在优购买东西就爱上了这个平台,价格实惠,经常有活动,退换货也很方便,强烈推荐!"
</div>
<div class="client-info">
<div class="client-img">
<img
src="https://randomuser.me/api/portraits/men/32.jpg"
alt="李先生"
/>
</div>
<div>
<h4>李先生</h4>
<p>北京</p>
</div>
</div>
</div>
<div class="testimonial-card">
<div class="testimonial-text">
"对比了好几个电商平台,最后还是选择优购,商品种类齐全,售后服务有保障,购物很放心。"
</div>
<div class="client-info">
<div class="client-img">
<img
src="https://randomuser.me/api/portraits/women/65.jpg"
alt="王小姐"
/>
</div>
<div>
<h4>王小姐</h4>
<p>广州</p>
</div>
</div>
</div>
</div>
</div>
</section>
<!-- 页脚 -->
<footer>
<div class="container">
<div class="footer-content">
<div class="footer-column">
<h3>关于优购</h3>
<ul class="footer-links">
<li><a href="#">公司简介</a></li>
<li><a href="#">招贤纳士</a></li>
<li><a href="#">联系我们</a></li>
<li><a href="#">隐私政策</a></li>
</ul>
</div>
<div class="footer-column">
<h3>购物指南</h3>
<ul class="footer-links">
<li><a href="#">购物流程</a></li>
<li><a href="#">会员介绍</a></li>
<li><a href="#">常见问题</a></li>
<li><a href="#">联系客服</a></li>
</ul>
</div>
<div class="footer-column">
<h3>配送方式</h3>
<ul class="footer-links">
<li><a href="#">上门自提</a></li>
<li><a href="#">211限时达</a></li>
<li><a href="#">配送服务查询</a></li>
<li><a href="#">配送费收取标准</a></li>
</ul>
</div>
<div class="footer-column">
<h3>关注我们</h3>
<p>订阅我们的电子报,获取最新优惠信息</p>
<div class="social-links">
<a href="#"></a>
<a href="#"></a>
<a href="#"></a>
<a href="#"></a>
</div>
</div>
</div>
<div class="copyright">
<p>© 2023 优购电商 版权所有 | ICP备案号京ICP备XXXXXXXX号</p>
</div>
</div>
</footer>
</body>
</html>