使用SharePoint Designer定製開發專家庫系統實例!

    將近大半年都沒有更新博客了,趁這段時間不忙,後續會繼續分享一些技術和實際應用。對於Sharepoint的定製開發有不少種方式,對於通常的應用系統,可使用Sharepoint自己自帶的功能,如列表做爲數據源和web服務等,再經過Sharepoint Designer工具能夠快速的定製開發,從效率和可維護性角度來講,這種方式是最高的,且可移植性好。去年本人去上海蔘加了微軟技術大會,根據微軟的介紹,Sharepoint 2013的前端功能支持愈來愈強大,後端的開發會慢慢弱化,能讓更多的前端開發工程師參與到Sharepoint的生態鏈中。對於這方面本人有一些實踐,如本人去年利用Sharepoint Designer的定製開發過公司的移動OA系統(根據訪問日誌統計,運行了一年多,日活躍度仍是不錯的,自認爲這個系統仍是比較成功的),Sharepoint Designer主要是用於前端(基於HTML5)的開發,後端經過VS自定義開發移動OA的Web服務發佈到Sharepoint中進行交互。javascript

     本文介紹一種本人上半年爲公司定製開發的sharepoint專家庫系統實例,原本還想開發移動APP端。但因爲各類緣由,這個系統的沒怎麼用起來,畢竟企業內部信息不是徹底開放的,對於高級人才的信息須要嚴格保密,一旦使用人數少又不是必備的,這樣系統發揮的價值就不大了,但設計和開發的方式相信對各位同窗會有啓發,是一個很好的學習實例,僅供學習參考。經過這種方式開發專家系統投入的時間也很少,大概用了2到3周的時間,成本是很低的。css

     首先進行需求分析,既然咱們專家庫系統是基於Sharepoint平臺的,能不能利用sharepoint自帶的一些功能呢?答案是確定的,由於專家自己也是sharepoint的用戶,熟悉sharepoint的架構都知道,sharepoint每一個用戶都會有本身的我的配置信息,且專家的信息與sharepoint的我的用戶信息不少都是一致的,只要擴展一下sharepoint的我的用戶信息便可,且sharepoint支持對用戶信息進行擴展,因此第一步在sharepoint的後臺管理中心中擴展sharepoint用戶的配置信息(如增長教育經歷、工做經歷、論文、專利等),這個只須要在sharepoint後臺配置用戶信息一下便可,擴展後能夠維護專家我的信息,以下圖:html

    

     其次,創建專家庫管理數據源,自定義一些列表(如專家我的專長及簡介、專家庫專業模塊、專家庫專業模塊領域、專業模塊技術帶頭人等),讓人力資源管理人員能夠自行管理專家庫系統(至關於專家庫的管理後臺,數據能夠動態管理),以下圖:前端

    

   

      最後進行前端系統的開發(主要面向最終用戶),經過Sharepoint Designer工具進行定製開發,界面的UI主要使用Jquery LigerUI(LigerUI是基於jQuery開發的一系列控件組,包括表單、佈局、表格等等經常使用UI控件 使用LigerUI能夠快速建立風格統一的界面效果 LigerUI視圖簡潔明瞭,操做較爲簡便,採用json格式傳遞數據。)。不管是Sharepoint的我的用戶信息仍是列表數據,都是能夠經過Sharepoint的web服務進行調用交互,sharepoint從2007開始,已有不少自帶的sharepoint web服務,考慮到sharepoint的升級和維護,本文使用了,老外封裝好了Sharepoint web服務的基於Jquery的SPServices庫,支持sharepoint 200七、sharepoint 20十、sharepoint 2013,以下圖:java

     

       

     專家庫系統部分界面,以下圖:node

   

   

使用SQL Server Report Builder進行報表開發併發布到Sharepoint後,監控系統使用狀況,以下:jquery

  自定義專家庫首頁完整參考C#代碼以下:web

<%@ Page Language="C#" masterpagefile="../_catalogs/masterpage/minimal.master" title="無標題 1" inherits="Microsoft.SharePoint.WebPartPages.WebPartPage, Microsoft.SharePoint, Version=14.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" meta:progid="SharePoint.WebPartPage.Document" %>
<asp:Content ID="PageHead" ContentPlaceHolderID="PlaceHolderPageTitleInTitleArea" runat="server">
<link href="../lib/ligerUI/skins/Aqua/css/ligerui-all.css" rel="stylesheet" type="text/css" /> 
<link href="../lib/ligerUI/skins/Gray2014/css/all.css" rel="stylesheet" type="text/css" /> 
<link rel="stylesheet" type="text/css" id="mylink" />   
<script type="text/javascript" src="../js/jquery.1.10.2.min.js"></script>
<script type="text/javascript" src="../js/jquery.SPServices-2013.01.min.js"></script>
<script src="../lib/ligerUI/js/ligerui.all.js" type="text/javascript"></script> 
<script src="../lib/ligerUI/js/plugins/ligerTab.js" type="text/javascript"></script>
<script src="../lib/json2.js" type="text/javascript"></script>
<script type="text/javascript" src="http://pv.sohu.com/cityjson?ie=utf-8" ></script>

 <script type="text/javascript">
 
 function getcurrentusername()
        {
          $.ajax({
                type: "POST",
                url: "http://ZJK/_layouts/SPOAFlowServices/SPOAFlowServices.asmx/GetCurrentUserName",
                cache: false,
                data: "{}",
                contentType: "application/json; charset=utf-8",
                dataType: "json",
                success: function (response) {
                   $('#currentusername').empty();
                  users = jQuery.parseJSON(response.d);
                                                            
                      CreateNewItem(users);                   
                                   
                },

                failure: function (msg) {
                }

            });
                           

        }

	
	
Date.prototype.Format = function (fmt) { //author: meizz 
        var o = {
        "M+": this.getMonth() + 1, //月份 
        "d+": this.getDate(), //日 
        "h+": this.getHours(), //小時 
        "m+": this.getMinutes(), //分 
        "s+": this.getSeconds(), //秒 
        "q+": Math.floor((this.getMonth() + 3) / 3), //季度 
        "S": this.getMilliseconds() //毫秒 
       };
       if (/(y+)/.test(fmt)) fmt = fmt.replace(RegExp.$1, (this.getFullYear() + "").substr(4 - RegExp.$1.length));
        for (var k in o)
        if (new RegExp("(" + k + ")").test(fmt)) fmt = fmt.replace(RegExp.$1, (RegExp.$1.length == 1) ? (o[k]) : (("00" + o[k]).substr(("" + o[k]).length)));
        return fmt;
       }

        function CreateNewItem(user) {
        
        try
        {
        var vpage = window.location.href;
        var cip;
        var city;
        try
        {
         cip= returnCitySN['cip'];
         }
        catch(e){cip= '';}
        
        try
        {
         city= returnCitySN['cname'];
        }
        catch(e){city='內網';}
        
        var useragent = navigator.userAgent;
 
        var Sys = {};  
        var ua = navigator.userAgent.toLowerCase();  
        var brw;  
        (brw = ua.match(/msie ([\d.]+)/)) ? Sys.ie = brw[1] :  
        (brw = ua.match(/firefox\/([\d.]+)/)) ? Sys.firefox = brw[1] :  
        (brw = ua.match(/chrome\/([\d.]+)/)) ? Sys.chrome = brw[1] :  
        (brw = ua.match(/opera.([\d.]+)/)) ? Sys.opera = brw[1] :  
        (brw = ua.match(/version\/([\d.]+).*safari/)) ? Sys.safari = brw[1] : 0;  
     
        
        var time2 = new Date().Format("yyyy-MM-dd hh:mm:ss");  
        var title = "專家庫主頁";
        
        var batch =
        "<Batch OnError=\"Continue\"> \
            <Method ID=\"1\" Cmd=\"New\"> \
              <Field Name=\"Title\">" + user + "</Field> \
                <Field Name=\"UserName\">" + user + "</Field> \
                <Field Name=\"VisitPage\">" + vpage + "</Field> \
                <Field Name=\"VisitTime\">" + time2 + "</Field> \
                <Field Name=\"VisitIPAddress\">" + cip + "</Field> \
                <Field Name=\"VisitIPCity\">" + city + "</Field> \
                <Field Name=\"UserAgent\">" + useragent + "</Field> \
                <Field Name=\"Browser\">" + brw + "</Field> \
                <Field Name=\"VisitPageName\">"+title+"</Field> \
            </Method> \
        </Batch>";


          var soapEnv =
        "<?xml version=\"1.0\" encoding=\"utf-8\"?> \
        <soap:Envelope xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" \
            xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" \
            xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\"> \
          <soap:Body> \
            <UpdateListItems xmlns=\"http://schemas.microsoft.com/sharepoint/soap/\"> \
              <listName>用戶訪問日誌</listName> \
              <updates> \
                " + batch + "</updates> \
            </UpdateListItems> \
          </soap:Body> \
        </soap:Envelope>";


         $.ajax({
        url: "http://ZJK/_vti_bin/lists.asmx",
        beforeSend: function(xhr) {
            xhr.setRequestHeader("SOAPAction",
            "http://schemas.microsoft.com/sharepoint/soap/UpdateListItems");
        },
        type: "POST",
        dataType: "xml",
        data: soapEnv,
        complete: processResult,
        contentType: "text/xml; charset=utf-8"
        });
                 
        }
        catch(e){}
        
        
         }
         
         function processResult(xData, status) {

}

$(document).ready(function () {
getcurrentusername();	

});

indexdata = [];
 var cj;
  
 var myQuery = "<Query><OrderBy><FieldRef Name='ISort' /></OrderBy><Where><Eq><FieldRef Name='IsDisplay' /><Value Type='Boolean'>1</Value></Eq></Where></Query>";
 var arraymdl = new Array(); 
 var mn = new Object();
 mn.Rows = [];

   $().SPServices({
    operation: "GetListItems",
    async: false,
    listName: "專家庫專業模塊",
    CAMLViewFields: "<ViewFields><FieldRef Name='SpecialtyModule' /><FieldRef Name='ID' /></ViewFields>",
    CAMLQuery: myQuery,
    webURL: "http://ZJK",
    completefunc: function (xData, Status) {
   
     var i=-1;
      $(xData.responseXML).SPFilterNode("z:row").each(function() {
   
        
           i++;
           indexdata[i] = new Object();
           indexdata[i].text= $(this).attr("ows_SpecialtyModule");
           indexdata[i].isparent=1;
           indexdata[i].isexpand = false;
           indexdata[i].children = [];
           arraymdl[i]=$(this).attr("ows_ID");
           mn.Rows[i] = new Object();
           mn.Rows[i].CstRowID = i;
           mn.Rows[i].SpmID =$(this).attr("ows_ID");
             });
    }
  });

GetExpertMainCategoryLead();
GetExpertChildCategory();


function GetExpertMainCategoryLead()
{
    var mquery="";
    var myQuery ="<Query><OrderBy><FieldRef Name='ISort' /></OrderBy><Where><And><In><FieldRef Name='SpecialtyModule' LookupId='True' /><Values>";
   
    for(md in arraymdl)
    {
       mquery= mquery+"<Value Type='Lookup'>"+arraymdl[md]+"</Value>";
    }

    
    myQuery=myQuery+mquery+"</Values></In><Eq><FieldRef Name='IsDisplay' /><Value Type='Boolean'>1</Value></Eq></And></Where></Query>";

    var myQueryOptions="<QueryOptions><ExpandUserField>True</ExpandUserField></QueryOptions>";
    $().SPServices({
    operation: "GetListItems",
    async: false,
    listName: "專業模塊技術帶頭人",
    CAMLViewFields: "<ViewFields><FieldRef Name='SpecialtyModule' /> <FieldRef Name='ModuleLead' /></ViewFields>",
    CAMLQuery: myQuery,
    CAMLQueryOptions: myQueryOptions,
    webURL: "http://ZJK",
    completefunc: function (xData, Status) {
   
    var j = -1;
    cj = -1;
         $(xData.responseXML).SPFilterNode("z:row").each(function() {
   
        var arr = $(this).attr("ows_ModuleLead").split("#");
       
        if(arr.length > 2)
        {
           j++;
           cj++;
           var acn =arr[2].replace(',','');
           acn = "AboutExpertW.aspx?accountname="+acn;
           var ld = arr[1].replace(',','');
           ld= ld+"(技術帶頭人)";
           
            for(dd in mn.Rows)
            {
                if(mn.Rows[dd].SpmID ==$(this).attr("ows_SpecialtyModule").split(";#")[0])
                {
                   indexdata[mn.Rows[dd].CstRowID].children[j] = new Object();
                   indexdata[mn.Rows[dd].CstRowID].children[j].text = ld;
                   indexdata[mn.Rows[dd].CstRowID].children[j].url = acn;
                   indexdata[mn.Rows[dd].CstRowID].children[j].isparent=3;
         
                  j=-1;
                  break;
                }
            }

        }
       
    
             });
        
           }
  });

}

function GetExpertChildCategory()
{
    var mquery="";
    var myQuery ="<Query><OrderBy><FieldRef Name='ISort' /></OrderBy><Where><And><In><FieldRef Name='SpecialtyModule' LookupId='True' /><Values>";
    
    for(md in arraymdl)
    {
       mquery= mquery+"<Value Type='Lookup'>"+arraymdl[md]+"</Value>";
    }

    myQuery=myQuery+mquery+"</Values></In><Eq><FieldRef Name='IsDisplay' /><Value Type='Boolean'>1</Value></Eq></And></Where></Query>";

    var myQueryOptions="<QueryOptions><ExpandUserField>True</ExpandUserField></QueryOptions>";
    $().SPServices({
    operation: "GetListItems",
    async: false,
    listName: "專家庫專業模塊領域",
    CAMLViewFields: "<ViewFields> <FieldRef Name='SpecialtyModule' /><FieldRef Name='SpecialtyModuleArea' /><FieldRef Name='AreaExpert' /></ViewFields>",
    CAMLQuery: myQuery,
    CAMLQueryOptions: myQueryOptions,
    webURL: "http://ZJK",
    completefunc: function (xData, Status) {
   
     var j ;
      $(xData.responseXML).SPFilterNode("z:row").each(function() {
         var r=-1;
           for(dd in mn.Rows)
           {
              if(mn.Rows[dd].SpmID ==$(this).attr("ows_SpecialtyModule").split(";#")[0])
              {
                 j = indexdata[mn.Rows[dd].CstRowID].children.length;
                 indexdata[mn.Rows[dd].CstRowID].children[j] = new Object();
                 indexdata[mn.Rows[dd].CstRowID].children[j].text = $(this).attr("ows_SpecialtyModuleArea");
                 indexdata[mn.Rows[dd].CstRowID].children[j].isparent=2;
                 indexdata[mn.Rows[dd].CstRowID].children[j].isexpand = false;
                 indexdata[mn.Rows[dd].CstRowID].children[j].children = [];
                 r = mn.Rows[dd].CstRowID;
                 break;
              }
           }

        var k =-1;               
        var arr = $(this).attr("ows_AreaExpert").split(";");
        
        for(var key in arr){
          if(arr[key].indexOf(',')>0)
          {
              
                   
              var arrc = arr[key].split("#");
              
               if(arrc.length > 2)
                {
                  k++;
                  var acn =arrc[2].replace(',','');
                  acn = "AboutExpertW.aspx?accountname="+acn;
                  k =  indexdata[r].children[j].children.length;
                  indexdata[r].children[j].children[k] = new Object();
                  indexdata[r].children[j].children[k].url = acn;
                  indexdata[r].children[j].children[k].text= arrc[1].replace(',','');
                  indexdata[r].children[j].children[k].isparent=4;
                }
          }
        }    
              
       });
    }
  });

}
     var tab = null;
            var accordion = null;
            var tree = null;
            var tabItems = [];
            $(function ()
            {
              //佈局
                $("#layout1").ligerLayout({ leftWidth: 190, height: '100%',heightDiff:-34,space:4, onHeightChanged: f_heightChanged });

                var height = $(".l-layout-center").height();

                //Tab
                $("#framecenter").ligerTab({
                    height: height,
                    showSwitchInTab : true,
                    showSwitch: true,
                    onAfterAddTabItem: function (tabdata)
                    {
                        tabItems.push(tabdata);
                        saveTabStatus();
                    },
                    onAfterRemoveTabItem: function (tabid)
                    { 
                        for (var i = 0; i < tabItems.length; i++)
                        {
                            var o = tabItems[i];
                            if (o.tabid == tabid)
                            {
                                tabItems.splice(i, 1);
                                saveTabStatus();
                                break;
                            }
                        }
                    },
                    onReload: function (tabdata)
                    {
                        var tabid = tabdata.tabid;
                        addFrameSkinLink(tabid);
                    }
                });

                //面板
                $("#accordion1").ligerAccordion({ height: height - 32, speed: null });

                $(".l-link").hover(function ()
                {
                    $(this).addClass("l-link-over");
                }, function ()
                {
                    $(this).removeClass("l-link-over");
                });
                //樹
                $("#tree1").ligerTree({
                    data : indexdata,
                    checkbox: false,
                    slide: false,
                    nodeWidth: 120,
                    attribute: ['nodename', 'url'],
                    onSelect: function (node)
                    {
                        if(node.data.isparent ==1)
                        {
                             $('#home').attr("src","ListExpert.aspx?specialtymodule="+node.data.text); 
                        }
                        
                        if(node.data.isparent ==2)
                         {
                            $('#home').attr("src","ListExpert.aspx?specialtymodulearea="+node.data.text);  
                         }   
                         

                       if (!node.data.url) return;
                        
                        var tabid = $(node.target).attr("tabid");
                        if (!tabid)
                        {
                            tabid = new Date().getTime();
                            $(node.target).attr("tabid", tabid)
                        } 
                        f_addTab(tabid, node.data.text, node.data.url);
                     }
                });

                tab = liger.get("framecenter");
                accordion = liger.get("accordion1");
                tree = liger.get("tree1");
                $("#pageloading").hide();
                
                 
                css_init();
                pages_init();
            }

             );
             
         
            function f_heightChanged(options)
            {  
                if (tab)
                    tab.addHeight(options.diff);
                if (accordion && options.middleHeight - 32 > 0)
                    accordion.setHeight(options.middleHeight - 32);
            }
            function f_addTab(tabid, text, url)
            {
                tab.addTabItem({
                    tabid: tabid,
                    text: text,
                    url: url,
                    callback: function ()
                    {
                       addFrameSkinLink(tabid); 
                    }
                });
            }
            function addFrameSkinLink(tabid)
            {
                var prevHref = getLinkPrevHref(tabid) || "";
                var skin = getQueryString("skin");
                if (!skin) return;
                skin = skin.toLowerCase();
                attachLinkToFrame(tabid, prevHref + skin_links[skin]);
            }
            var skin_links = {
			   "aqua": "../lib/ligerUI/skins/Aqua/css/ligerui-all.css",
                "gray": "../lib/ligerUI/skins/Gray/css/all.css",
                "silvery": "../lib/ligerUI/skins/Silvery/css/style.css",
                "gray2014": "../lib/ligerUI/skins/gray2014/css/all.css"               
            };
            function pages_init()
            {
                var tabJson = $.cookie('liger-home-tab'); 
                if (tabJson)
                { 
                    var tabitems = JSON2.parse(tabJson);
                    for (var i = 0; tabitems && tabitems[i];i++)
                    { 
                        f_addTab(tabitems[i].tabid, tabitems[i].text, tabitems[i].url);
                    } 
                }
            }
            function saveTabStatus()
            { 
                $.cookie('liger-home-tab', JSON2.stringify(tabItems));
            }
            function css_init()
            {
                var css = $("#mylink").get(0), skin = getQueryString("skin");
                
                $("#skinSelect").val(skin);
                $("#skinSelect").change(function ()
                { 
                    if (this.value)
                    {
                        location.href = "index.htm?skin=" + this.value;
                    } else
                    {
                        location.href = "index.htm";
                    }
                });

               
                if (!css || !skin) return;
                skin = skin.toLowerCase();
                $('body').addClass("body-" + skin); 
                $(css).attr("href", skin_links[skin]); 
           }
           
            function getQueryString(name)
            {
                var now_url = document.location.search.slice(1), q_array = now_url.split('&');
                for (var i = 0; i < q_array.length; i++)
                {
                    var v_array = q_array[i].split('=');
                    if (v_array[0] == name)
                    {
                        return v_array[1];
                    }
                }
                return false;
            }
            function attachLinkToFrame(iframeId, filename)
            { 
                if(!window.frames[iframeId]) return;
                var head = window.frames[iframeId].document.getElementsByTagName('head').item(0);
                var fileref = window.frames[iframeId].document.createElement("link");
                if (!fileref) return;
                fileref.setAttribute("rel", "stylesheet");
                fileref.setAttribute("type", "text/css");
                fileref.setAttribute("href", filename);
                head.appendChild(fileref);
            }
            function getLinkPrevHref(iframeId)
            {
                if (!window.frames[iframeId]) return;
                var head = window.frames[iframeId].document.getElementsByTagName('head').item(0);
                var links = $("link:first", head);
                for (var i = 0; links[i]; i++)
                {
                    var href = $(links[i]).attr("href");
                    if (href && href.toLowerCase().indexOf("ligerui") > 0)
                    {
                        return href.substring(0, href.toLowerCase().indexOf("lib") );
                    }
                }
            }
     </script> 
<style type="text/css"> 
    body,html{height:100%;}
    body{ padding:0px; margin:0;   overflow:hidden;
	text-align: left;
}  
    .l-link{ display:block; height:26px; line-height:26px; padding-left:10px; text-decoration:underline; color:#333;}
    .l-link2{text-decoration:underline; color:white; margin-left:2px;margin-right:2px;}
    .l-layout-top{background:#102A49; color:White;}
    .l-layout-bottom{ background:#E5EDEF; text-align:center;}
    #pageloading{position:absolute; left:0px; top:0px; background:white url('loading.gif') no-repeat center; width:100%; height:100%;z-index:99999;}
    .l-link{ display:block; line-height:22px; height:22px; padding-left:16px;border:1px solid white; margin:4px;}
    .l-link-over{ background:#FFEEAC; border:1px solid #DB9F00;} 
    .l-winbar{ background:#2B5A76; height:30px; position:absolute; left:0px; bottom:0px; width:100%; z-index:99999;}
    .space{ color:#E7E7E7;}
    /* 頂部 */ 
    .l-topmenu{ margin:0; padding:0; height:31px; line-height:31px; background:url('lib/images/top.jpg') repeat-x bottom;  position:relative; border-top:1px solid #1D438B;  }
    .l-topmenu-logo{ color:#E7E7E7; padding-left:35px; line-height:26px;background:url('lib/images/topicon.gif') no-repeat 10px 5px;}
    .l-topmenu-welcome{  position:absolute; height:24px; line-height:24px;  right:30px; top:2px;color:#070A0C;}
    .l-topmenu-welcome a{ color:#E7E7E7; text-decoration:underline} 
     .body-gray2014 #framecenter{
        margin-top:3px;
    }
      .viewsourcelink {
         background:#B3D9F7;  display:block; position:absolute; right:10px; top:3px; padding:6px 4px; color:#333; text-decoration:underline;
    }
    .viewsourcelink-over {
        background:#81C0F2;
    }
    .l-topmenu-welcome label {color:white;
    }
    #skinSelect {
        margin-right: 6px;
    }
 </style>
</asp:Content>
<asp:Content ContentPlaceHolderId="PlaceHolderMain" runat="server">
	<div id="layout1" style="width:99.2%; margin:0 auto; margin-top:0px; "> 
        <div position="left"  title="專家數據庫" id="accordion1" > 
                     <div title="專業領域" class="l-scroll"  >
                         <ul id="tree1" style="margin-top:3px;" />
                    </div>
		 </div>
        <div position="center" id="framecenter"> 
            <div tabid="home" title="專家列表" style="height:300px" >
                <iframe frameborder="0" name="home" id="home" src="ListExpert.aspx"></iframe>
             </div> 
        </div> 
        
    </div>
    <div  style="height:32px; line-height:32px; text-align:center;">
            XX公司 版權全部 2014-2015 技術支持:軟件人生(http://www.cnblogs.com/nbpowerboy)
    </div>
    <div style="display:none"></div>
</asp:Content>

   同時歡迎關注本人的微信號QYXXHQY,不按期更新企業信息化前沿相關技術和應用,歡迎掃描關注,二維碼以下:ajax

   

本博客爲軟件人生原創,歡迎轉載,轉載請標明出處:http://www.cnblogs.com/nbpowerboy/p/4166836.html 。演繹或用於商業目的,可是必須保留本文的署名軟件人生(包含連接)。如您有任何疑問或者受權方面的協商,請給我留言。chrome

相關文章
相關標籤/搜索