tianyun 3 months ago
parent
commit
66a57b120a
1 changed files with 487 additions and 0 deletions
  1. 487 0
      simple-demo/nav.html

+ 487 - 0
simple-demo/nav.html

@@ -0,0 +1,487 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+    <meta charset="UTF-8">
+    <title>导航</title>
+    <script src="https://map.tianyunperfect.cn/common-page.js"></script>
+
+    <script src="js/clipboard.min.js"></script>
+    <script src="js/vue.min.js"></script>
+    <script src="elementUI/index.js"></script>
+    <link rel="stylesheet" href="elementUI/index.css"/>
+    <style>
+        .tab-container {
+            max-width: 1600px;
+            margin: 0 auto;
+            padding: 20px;
+        }
+
+        .tab-content {
+            margin-top: 20px;
+        }
+
+        .content-item {
+            margin: 10px;
+            /*padding: 15px;*/
+            border: 1px solid #ebeef5;
+            border-radius: 4px;
+            transition: all .3s;
+            cursor: pointer;
+            display: inline-block;
+            width: 400px;
+            box-sizing: border-box;
+        }
+
+        .content-item:hover {
+            background-color: #f5f7fa;
+            box-shadow: 0 2px 12px 0 rgba(0, 0, 0, .1);
+        }
+
+        .el-tabs__item.is-active {
+            color: #409EFF !important;
+        }
+
+        .el-tabs__active-bar {
+            background-color: #409EFF;
+        }
+
+        .action-buttons {
+            text-align: right;
+        }
+
+        .item-card {
+            width: 100%;
+            border: none;
+            box-shadow: none;
+        }
+
+        .item-content {
+            display: flex;
+            justify-content: space-between;
+            align-items: center;
+        }
+
+        .item-2 {
+            /*    禁止换行 - */
+            white-space: nowrap;
+            /* 超出部分隐藏 */
+            overflow: hidden;
+            /* 超出部分显示省略号 */
+            text-overflow: ellipsis;
+        }
+
+        .copy-btn {
+            color: #409EFF;
+        }
+
+        .copy-btn:hover {
+            color: #206BC4;
+        }
+
+        .content-item {
+            margin-bottom: 15px;
+        }
+
+        @media (max-width: 768px) {
+            .content-item {
+                width: calc(50% - 20px);
+            }
+        }
+
+        @media (max-width: 480px) {
+            .content-item {
+                width: 100%;
+            }
+        }
+
+        /* 原有样式保留,新增以下样式 */
+        .link-section {
+            margin: 8px 0;
+        }
+
+        .extra-links {
+            margin-top: 8px;
+        }
+
+        .extra-link-tag {
+            margin: 2px;
+            padding: 0 5px;
+        }
+
+        .item-description {
+            color: #666;
+            font-size: 12px;
+            margin-bottom: 8px;
+        }
+
+        .screenshot-section {
+            border-top: 1px solid #eee;
+            margin-top: 8px;
+            padding-top: 8px;
+        }
+
+        .edit-dialog .el-dialog__body {
+            padding: 20px;
+        }
+
+        .dynamic-delete-button {
+            cursor: pointer;
+            color: #F56C6C;
+        }
+    </style>
+    <script src="js/Sortable.min.js"></script>
+    <script src="js/vuedraggable.umd.min.js"></script>
+    <script src="js/axios.min.js"></script>
+</head>
+<body>
+<div id="app" class="tab-container">
+    <el-tabs v-model="activeTab" @tab-click="handleTabClick" type="card" ref="navTabs">
+        <el-tab-pane
+                v-for="(content, tabName) in myObj"
+                :key="tabName"
+                :label="tabName"
+                :name="tabName">
+            <div class="tab-content">
+                <draggable
+                        :disabled="readOnly"
+                        v-model="myObj[tabName]"
+                        tag="div"
+                        @change="onDragChange(tabName)"
+                        handle=".drag-handle"
+                        class="content-list">
+                    <div
+                            v-for="(item, index) in myObj[tabName]"
+                            :key="index"
+                            class="content-item">
+                        <el-card shadow="hover" class="item-card">
+                            <div slot="header" class="item-content">
+                                <el-image
+                                        :src="item.icon"
+                                        style="width: 20px; height: 20px; margin-right: 8px;"
+                                        fit="contain"
+                                ></el-image>
+                                <span>{{ item.title }}</span>
+                                <div class="action-buttons">
+                                    <el-button type="text" class="drag-handle">
+                                        <i class="el-icon-rank"></i>
+                                    </el-button>
+                                    <el-button
+                                            type="text"
+                                            @click.stop="openEditDialog(tabName, index)">
+                                        <i class="el-icon-edit"></i>
+                                    </el-button>
+                                    <el-button
+                                            type="text"
+                                            @click.stop="deleteContentItem(tabName, index)">
+                                        <i class="el-icon-delete"></i>
+                                    </el-button>
+                                </div>
+                            </div>
+                            <div class="item-content">
+                                <div style="width: 100%">
+                                    <div v-if="item.description" class="item-description">{{ item.description }}</div>
+                                    <div class="link-section">
+                                        <el-link
+                                                type="primary"
+                                                :href="item.mainUrl"
+                                                target="_blank">{{ item.mainUrl }}
+                                        </el-link>
+                                    </div>
+                                    <div v-if="item.extraUrls && item.extraUrls.length" class="extra-links">
+                                        <el-tag
+                                                v-for="(url, idx) in item.extraUrls"
+                                                :key="idx"
+                                                type="info"
+                                                class="extra-link-tag">
+                                            <el-link :href="url" target="_blank">{{ url }}</el-link>
+                                        </el-tag>
+                                    </div>
+                                    <div v-if="item.screenshot" class="screenshot-section">
+                                        <el-image
+                                                :src="item.screenshot"
+                                                style="max-width: 100%; max-height: 300px;"
+                                                :preview-src-list="[item.screenshot]"
+                                                fit="contain"></el-image>
+                                    </div>
+                                </div>
+                            </div>
+                        </el-card>
+                    </div>
+                </draggable>
+
+                <!-- 添加新项部分 -->
+                <div v-if="!readOnly">
+                    <el-button type="primary" @click="openAddDialog">添加新项</el-button>
+                    <el-button @click="showTabManage = !showTabManage">
+                        {{ showTabManage ? '隐藏标签管理' : '显示标签管理' }}
+                    </el-button>
+
+                    <!-- 标签管理 -->
+                    <!-- 标签管理部分 -->
+                    <div v-if="showTabManage" style="margin-top: 20px;">
+                        <el-input
+                                v-model="newTabName"
+                                placeholder="新标签页名称"
+                                style="width: 200px; margin-right: 10px;"></el-input>
+                        <el-button
+                                type="primary"
+                                @click="addTab"
+                                :disabled="!newTabName || myObj[newTabName]">
+                            添加标签页
+                        </el-button>
+                        <el-button
+                                type="warning"
+                                @click="editCurrentTabName"
+                                :disabled="!activeTab">
+                            修改当前标签名
+                        </el-button>
+                        <el-button
+                                type="danger"
+                                @click="deleteTab(activeTab)"
+                                :disabled="Object.keys(myObj).length <= 1">
+                            删除当前标签
+                        </el-button>
+                    </div>
+                </div>
+            </div>
+        </el-tab-pane>
+    </el-tabs>
+
+    <!-- 编辑对话框 -->
+    <el-dialog
+            :title="isEditing ? '编辑项目' : '添加新项'"
+            :visible.sync="dialogVisible"
+            width="600px">
+        <el-form :model="currentItem" label-width="80px">
+            <el-form-item label="标题">
+                <el-input v-model="currentItem.title"></el-input>
+            </el-form-item>
+            <el-form-item label="图标URL">
+                <el-input v-model="currentItem.icon"></el-input>
+            </el-form-item>
+            <el-form-item label="主地址">
+                <el-input v-model="currentItem.mainUrl"></el-input>
+            </el-form-item>
+            <el-form-item label="描述">
+                <el-input v-model="currentItem.description" type="textarea"></el-input>
+            </el-form-item>
+            <el-form-item label="附加地址">
+                <div v-for="(url, index) in currentItem.extraUrls" :key="index">
+                    <el-input v-model="currentItem.extraUrls[index]" style="margin-bottom: 5px;">
+                        <el-button
+                                slot="append"
+                                icon="el-icon-remove"
+                                @click="removeExtraUrl(index)"></el-button>
+                    </el-input>
+                </div>
+                <el-button @click="addExtraUrl">添加附加地址</el-button>
+            </el-form-item>
+            <el-form-item label="截图URL">
+                <el-input v-model="currentItem.screenshot"></el-input>
+            </el-form-item>
+            <el-form-item label="所属标签">
+                <el-select v-model="targetTab" placeholder="请选择标签页">
+                    <el-option
+                            v-for="tab in Object.keys(myObj)"
+                            :key="tab"
+                            :label="tab"
+                            :value="tab">
+                    </el-option>
+                </el-select>
+            </el-form-item>
+        </el-form>
+        <span slot="footer" class="dialog-footer">
+            <el-button @click="dialogVisible = false">取 消</el-button>
+            <el-button type="primary" @click="saveItem">确 定</el-button>
+        </span>
+    </el-dialog>
+</div>
+
+<script>
+    let pageManager = new PageManager();
+    pageManager.type = 'nav-page';
+
+    new Vue({
+        el: '#app',
+        data: {
+            all_data: {},
+            activeTab: '常用工具',
+            myObj: {
+                "常用工具": [{
+                    title: "GitHub",
+                    icon: "https://github.githubassets.com/favicons/favicon.svg",
+                    mainUrl: "https://github.com",
+                    description: "代码托管平台",
+                    extraUrls: [
+                        "https://gist.github.com",
+                        "https://pages.github.com"
+                    ],
+                    screenshot: ""
+                }]
+            },
+            newTabName: '',
+            readOnly: false,
+            showTabManage: false,
+            // 对话框相关
+            dialogVisible: false,
+            isEditing: false,
+            currentItem: {
+                title: '',
+                icon: '',
+                mainUrl: '',
+                description: '',
+                extraUrls: [],
+                screenshot: ''
+            },
+            originalTab: '',
+            originalIndex: -1,
+            targetTab: ''
+        },
+        mounted() {
+            pageManager.init().then(res => {
+                this.all_data = res;
+                if (res && res.content) {
+                    let showContent = res.content;
+                    if (pageManager.isBackup) showContent = res.content_back;
+                    this.myObj = JSON.parse(showContent);
+                }
+                this.activeTab = Object.keys(this.myObj)[0] || '';
+                if (pageManager.isReadOnly()) this.readOnly = true;
+
+                this.mouseOver();
+            });
+        },
+        methods: {
+            // 鼠标滑过,切换tabs
+            mouseOver() {
+                this.$nextTick(() => {
+                    this.$refs.navTabs.$refs.nav.$nextTick(() => {
+                        // console.log('$refs.nav', this.$refs.navTabs.$refs.nav.$el)
+                        // 此时tab的nav才渲染dom 否则拿不到el-tabs__item
+                        const target = document.getElementsByClassName('el-tabs__item')
+                        for (let i = 0; i < target.length; i++) {
+                            target[i].addEventListener('mouseover', () => {
+                                target[i].click();
+                            })
+                        }
+                    })
+                });
+            },
+            editCurrentTabName() {
+                this.$prompt('请输入新标签名', '修改标签名称', {
+                    inputValue: this.activeTab,
+                    closeOnClickModal: false,
+                    inputValidator: (value) => {
+                        if (!value) return '标签名不能为空';
+                        if (this.myObj[value] && value !== this.activeTab) return '标签名已存在';
+                        return true;
+                    }
+                }).then(({value}) => {
+                    if (value !== this.activeTab) {
+                        // 创建新标签并转移数据
+                        this.$set(this.myObj, value, this.myObj[this.activeTab]);
+                        delete this.myObj[this.activeTab];
+                        this.activeTab = value;
+                        this.updateData();
+                    }
+                }).catch(() => {
+                });
+            },
+            openAddDialog() {
+                this.isEditing = false;
+                this.currentItem = {
+                    title: '',
+                    icon: '',
+                    mainUrl: '',
+                    description: '',
+                    extraUrls: [],
+                    screenshot: ''
+                };
+                this.targetTab = this.activeTab;
+                this.dialogVisible = true;
+            },
+
+            openEditDialog(tabName, index) {
+                this.isEditing = true;
+                this.originalTab = tabName;
+                this.originalIndex = index;
+                this.currentItem = JSON.parse(JSON.stringify(this.myObj[tabName][index]));
+                this.targetTab = tabName;
+                this.dialogVisible = true;
+            },
+
+            saveItem() {
+                if (!this.currentItem.title || !this.currentItem.mainUrl) {
+                    this.$message.warning('标题和主地址为必填项');
+                    return;
+                }
+
+                // 删除原有项(编辑时)
+                if (this.isEditing) {
+                    this.myObj[this.originalTab].splice(this.originalIndex, 1);
+                }
+
+                // 添加到目标标签
+                if (!this.myObj[this.targetTab]) this.myObj[this.targetTab] = [];
+                this.myObj[this.targetTab].push(this.currentItem);
+
+                this.updateData();
+                this.dialogVisible = false;
+            },
+
+            addExtraUrl() {
+                this.currentItem.extraUrls.push('');
+            },
+
+            removeExtraUrl(index) {
+                this.currentItem.extraUrls.splice(index, 1);
+            },
+
+            addTab() {
+                if (!this.newTabName) return;
+                this.$set(this.myObj, this.newTabName, []);
+                this.activeTab = this.newTabName;
+                this.newTabName = '';
+                this.updateData();
+            },
+
+            deleteTab(tabName) {
+                this.$confirm('确定删除该标签页?', '警告', {
+                    confirmButtonText: '确定',
+                    cancelButtonText: '取消',
+                    type: 'warning'
+                }).then(() => {
+                    delete this.myObj[tabName];
+                    this.activeTab = Object.keys(this.myObj)[0] || '';
+                    this.updateData();
+                });
+            },
+
+            deleteContentItem(tabName, index) {
+                this.$confirm('确定删除该项?', '警告', {
+                    confirmButtonText: '确定',
+                    cancelButtonText: '取消',
+                    type: 'warning'
+                }).then(() => {
+                    this.myObj[tabName].splice(index, 1);
+                    this.updateData();
+                });
+            },
+
+            updateData() {
+                this.all_data.content = JSON.stringify(this.myObj);
+                pageManager.updateData(this.all_data);
+            },
+
+            onDragChange(tabName) {
+                this.updateData();
+            },
+
+            handleTabClick(tab) {
+                this.activeTab = tab.name;
+            }
+        }
+    });
+</script>
+</body>
+</html>