仿花田:相親網站 意中人 已在GitHub上開源


     在園友的強烈呼喚下,我還是負責任的分享給大家,因為對代碼比較熟悉一下,還是有些問題要說明,不然別人看起來會比較費勁。說實話除了這個bootstrap的界面風格和這件事情本身對大家有吸引力之外,內部的邏輯,結構,可能有些捉襟見肘,會讓大家見笑,大牛們完全可以略過.現在源碼已經讓我推到GitHub上面去了。我先從頭到尾的介紹一下,然后說一些存在的問題。也希望大家給出更好的建議。

一、結構說明

    1.MVC 我先說模型,共有20幾張表,支持數據遷移。BaseInfos(基本資料),DetailInfos(詳細資料),LoveViews(戀愛觀) 應該是做到一張User表中的,腦抽的我把他們分成了三張表,因為他們是分別存儲的。下載之后,改成你自己的數據庫,運行就能創建新表了。

using System;
using System.Collections.Generic;
using System.Data.Entity;
using Findlover.Migrations;

namespace Findlover.Models
{
    public class LoveDb:DbContext
    {
        private const string DbNameOrDbConnectionstring =
           
          "Data Source=your-pc;Initial Catalog=LoveDB;User ID=sa;Password=code;Persist Security Info=True";  
        //Persist Security Info=True
        public DbSet<BaseInfo> BaseInfos { get; set; }// 基本資料
        public DbSet<User> Users { get; set; }// 用戶
        public DbSet<Requirement> Requirements { get; set; }//擇偶需求
        public DbSet<DetailInfo> DetailInfos { get; set; }//詳細資料
        public DbSet<LoveView> LoveViews { get; set; }//戀愛觀
        public DbSet<InfoStatistic> InfoStatistics { get; set; }// 信息統計,統計用戶資料的完整度。避免每次都要去三張表數一遍。
        public DbSet<UserHot> UserHots { get; set; }//用戶的人熱度
        public DbSet<Praise> Praises { get; set; }//贊 也就是喜歡
        public DbSet<State> States { get; set; }// 狀態
        public DbSet<Iamgbox> Iamgboxes { get; set; }// 相冊
        public DbSet<Message> Messages { get; set; }//私信
        public DbSet<LoginLog> LoginLogs { get; set; }// 登錄日志記錄
        public DbSet<Role> Roles { get; set; }//角色
        public DbSet<Hello> Hellos { get; set; }//打招呼
        public DbSet<RoleLog> RoleLogs { get; set; }// 角色的日志
        public DbSet<Authority> Authoritys { get; set; }// 權限
        public DbSet<AdminStatistic> AdminStatistics { get; set; }//管理員操作統計 這個功能沒有多大意義 你可拿掉
        public DbSet<VisitLog> VisitLogs { get; set; }// 訪問記錄
        public DbSet<Report> Reports { get; set; }//舉報
        public DbSet<ReportLog> ReportLogs { get; set; }//舉報日志
        public DbSet<MyLove> MyLoves { get; set; }// 我喜歡的人
        public DbSet<DisLove> DisLoves { get; set; }//我不喜歡的人 相當於黑名單
        public DbSet<Topic> Topics { get; set; }// 話題
        public DbSet<Comment> Comments { get; set; }//評論
        public DbSet<EnjoyTopic> EnjoyTopics { get; set; }//感興趣的話題
        public LoveDb() : base(DbNameOrDbConnectionstring)
        {
            Database.SetInitializer(new MigrateDatabaseToLatestVersion<LoveDb, Configuration<LoveDb>>());
        }
    }
}

 2. 控制器: 共有8個控制器,其中BaseController 里面集合一些常用的方法和屬性,其他都繼承這個控制器,其他看名字你也知道是干啥的,Interactive是對應的Topic,本來是打算一個專門用來做交互的控制器。現在只有話題。但可能讓大家惱火的就是,這分的還不細致,不准確。之前自己偷懶,什么方法寫在什么控制器沒有明確的定義清楚,這對以后維護和擴展造成不方便。

   

3.視圖:主要是基於Bootstrap2,Jquery1.7.2.,form.js  注冊的日期控件和Topic的編輯器用的是KendoUi, 小伙伴們可以去換成Ckeditor,而Bootstrap用的地方主要是在

  Layout的導航,后台導航,舉報、私信、圖片上傳的模態對話框,在主頁面使用它的柵格比較少,因為老是和導航對不齊,就放棄了。或許是我用的不對。Jquery用來交互,獲取數據。form.js 用的比較多,很多地方是form提交,沒有用MVC自帶的Create。原因就是不好看,而且不好控制,ie下面會走樣。

 

二、前端特別說明

  這里特別要說明的就是一些函數和窗口的觸發

  1.圖片上傳和舉報框。

 在用戶主頁的視圖和PersonalInfo視圖中會有這兩個相似的html代碼,是用來觸發圖片上傳框的。

  <div class="infopercentright">上傳4張照片,資料完整度+8%  <a class="infotag" id="imgup"  href="#imgupload" data-toggle="modal" title="上傳照片"><i class="icon-camera"></i></a> </div>
   <a class="infotag" id="imgupload"  href="#imgupload" data-toggle="modal" title="上傳照片"><i class="icon-camera"></i></a>  

圖片上傳的模態對話框:

    <div id="imgupload" class="modal hide fade" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
        <div class="modal-header">
            <button type="button" class="close" data-dismiss="modal" aria-hidden="true">&times;</button>
            <h4>上傳圖片</h4>  
        </div>
        <div class="modal-body">
            <div class="uploadbox" data-count="0" style="display: inline;">
                <span class="closespan" title="刪除照片">&times;</span>
                <div class="imgcontainer">
                    <div class="add">+</div>
                    <div class="stt">點擊上傳</div>
                </div>
                <span class="infospan">
                    <img src='../../Content/Photos/loading.gif' />正在上傳...</span>
            </div> 
            <div class="uploadbox" data-count="0"  >
                <span class="closespan" title="刪除照片">&times;</span>
                <div class="imgcontainer">
                    <div class="add">+</div>
                    <div class="stt">點擊上傳</div>
                </div>
                <span class="infospan"> <img src='../../Content/Photos/loading.gif' />正在上傳...</span>
            </div> 
            <div class="uploadbox"data-count="0" >
                <span class="closespan" title="刪除照片">&times;</span>
                <div class="imgcontainer">
                    <div class="add">+</div>
                    <div class="stt">點擊上傳</div>
                </div>
                <span class="infospan"> <img src='../../Content/Photos/loading.gif' />正在上傳...</span>
            </div> 
            <div class="uploadbox"data-count="0"  >
                <span class="closespan" title="刪除照片">&times;</span>
                <div class="imgcontainer">
                    <div class="add">+</div>
                    <div class="stt">點擊上傳</div>
                </div>
                <span class="infospan"> <img src='../../Content/Photos/loading.gif' />正在上傳...</span>
            </div> 
            <div class="inputdiv"><input type="text" disabled="disabled" id="Remark" name="Remark" placeholder="補充說明下~"/></div>
        </div>
        <div class="modal-footer">
            上傳大小在8k-10M之間 <span class="imguploadmessage"></span>
            <button class="btn btn-success "  disabled="disabled"   id="imgsubmit">發布</button>
            <form action="/User/UpLoadPhoto" method="POST" enctype="multipart/form-data" name="ImgForm" id="ImgForm">
                <input type="file" name="file" id="imgFlie"  required="required" />
                <input type="submit" name="subt" value="上傳圖片" />
            </form>
        </div>
    </div>
View Code

生成的圖像如下:

舉報也同樣的做法: 但舉報需要提供更多的信息,所以加了很多data屬性。用腳本觸發對話框

  <span class="report" data-reportType="personal" data-relateId="@Model.UserId" data-content="@Model.UserName" data-userId="@Model.UserId" data-userName="@Model.UserName" data-sextag="@ViewBag.Sex">拉黑/舉報</span>    
 //舉報框----------------------report--------------------------------------------
    $(".report").each(function () {
        $(this).click(function () {
            var id = $(this).attr("data-userId");
            var name = $(this).attr("data-userName");
            var sextag = $(this).attr("data-sextag");//對方性別
            var type = $(this).attr("data-reportType");
            var relateId = $(this).attr("data-relateId");
            var content = $(this).attr("data-content");

            $("#reportedname").html(name).attr("data-id", id);//被舉報人id
            $(".reportinfo span").html(sextag);
            $("#reportName").html(name);
            $("#reporttype").val(type);//舉報類型
            $("#reporttype").attr("data-relateId", relateId);
            $("#reporttype").attr("data-content", content);

            //值是舉報或者拉黑這個人 初始化
            $(".divrow:eq(1)").show();
            $("#reportcontent").hide();
            $(".reportmessage").html();
            $("#reportcontent").html(content);
            //不同類型,不同對話
            switch (type) {
                case "personal":
                    $(".divrow:eq(1)").hide();
                    break;
                case "message":
                    $("#reportType").html("發給我的私信");
                    $("#IsReport").attr("checked", "checked");
                    $("#reportcontent").show();
                    break;
                default:
            }

            $("#IsReport").click(function () {
                var ss = $(this).is(':checked');
                if (ss) {
                    $(".divrow:eq(1),#reportcontent").slideDown();
                } else {
                    $(".divrow:eq(1),#reportcontent").slideUp();
                }
            });
           $('#report_box').modal('show');
        });
    });

 舉報框:

 我想大家也明白了,就是這樣的一回事,腳本沒有壓縮,大家可以去看。其他像 喜歡,私信,都是一個道理,定義好一個樣式,主要是樣式名稱,在layout里面寫腳本,這樣就很方便了。

2.form提交:

 用form.js,能很好的控制整個提交過程,BeginForm,隱藏的form,圖片上傳的form。

 編輯基本資料:

 <div class="infoedit hide" >
            @using (Html.BeginForm("UpdateBaseInfo", "User", FormMethod.Post, new { name = "Form1", id = "Form1" }))
            {
                <table class="">
                    <tr>
                        <td>身高:</td>
                        <td>
                            <select name="Height" id="Height"></select></td>
                        <td>學歷:</td>
                        <td>
                            <select name="Education" id="Education"></select></td>
                    </tr>
                    <tr>
                        <td>月收入:</td>
                        <td>
                            <select name="MonthlyIncome" id="MonthlyIncome"></select></td>
                        <td>畢業院校:</td>
                        <td>
                            <input type="text" name="School" id="School" value="@Model.BaseInfo.School"/></td>
                    </tr>
                    <tr>
                        <td>工作單位:</td>
                        <td>
                            <select name="Company" id="Company"></select></td>
                        <td>居住地:</td>
                        <td>
                          <select name="ResidenceProvince" id="ResidenceProvince" style="width: 90px"></select>   <select name="ResidenceCity" id="ResidenceCity" style="width: 90px"></select></td>
                    </tr>
                    <tr>
                        <td>目前職位:</td>
                        <td>
                            <select name="Position" id="Position"></select></td>
                        <td>行業:</td>
                        <td>
                            <input type="text" id="Profession" readonly="readonly" name="Profession" value="生產/工藝/制造"></td>
                    </tr>
                    <tr>
                        <td>當前狀態:</td>
                        <td>
                            <select name="State" id="State"></select></td>
                    </tr>
                </table>
              <button type="submit"  class="btn btn-info"> 保存</button> <span class="cancel-eidt">取消編輯</span>
            }
           
        </div>
View Code

 這樣的方式用了很多,腳本基本上是下面這樣,還可以加上beforeSend,complete. 其他項獲取json數據這些,就是家常便飯了,沒什么說的。

   $('#Form1').submit(function () {
        $(this).ajaxSubmit(options);
        return false;
    });
  var options = {
        dataType: 'json',
        success: processJson,
    };
function processJson(data) {
        // 還是返回json的好,再去更新。
        $(".infowrap").show();
        //......
        $("#sProfession").html(data.Profession);
        $("#sPosition").html(data.Position);
        $("#sSchool").html(data.School);
        $("#sState").html(data.State);
    }

 

二、后台邏輯

 其實這個部分是最沒有含金量的,只要大家清楚業務流程了,邏輯再怎么也能寫出來。我也沒有用AOP來記錄日志或者處理異常,用IOC/DI來解耦。這也是我的弱點。所以我就簡單說明下。

1.符合基本條件的用戶: 因為是相親交友,所以要篩選用戶。在BaseController中有個GetBaseUsers

/// <summary>
        /// 獲取基本的異性集合 不可以允許未審核圖片的人進來! 
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        protected IEnumerable<User> GetBaseUsers(int id)
        {
            var lz = LoveDb.One((User n) => n.UserId == id);
            var dislikelist = GetDislikeList();//過濾的名單。 過掉我不喜歡的人。  //還要過掉不喜歡我的人?
          
            if (lz != null)
            {
                //選出所有異性中圖片審核過的,資料審核過的人,且資料開放,沒有被禁止的人
                return
                    LoveDb.UserAll()
                          .Where(n => n.Sex != lz.Sex  && n.IsVerified && n.IsVerifiedImg && n.IsOpen && n.Enable == 1&&!dislikelist.Contains(n.UserId)) .ToList(); } return null; }

 2.推薦的用戶:推薦,動態,搜索的基本用戶都是來自這里。 你可以稍微改下代碼讓他可以選擇同性。而推薦和動態的用戶 還需要滿足一個用戶的基本擇偶要求。 就是比如我擇偶的要求是

 158以上,江蘇,22歲以上。那出現在這兩個頁面的用戶就必須滿足這三個條件是硬性指標,但學歷,薪水是可以不匹配的。所以在推薦頁面是這樣的:

  public ActionResult RecommendPage()
        {
            var id = CheckValid();
            if (id == -1 || Session["uid"] == null)
            {
                return RedirectToAction("Logon", "User");//不知道有沒有效果
            }
            var require = LoveDb.One((Requirement r) => r.UserId == id);
            var baseusers = GetBaseUsers(id).Where(n => PartMathUser(require, LoveDb.GetUninUser(n.UserId)));//找出所有正規的異性符合需求的。 
            ViewBag.Sex = GetMyself().User.Sex == "man" ? "" : "";
            var userlist = baseusers.Select(baseuser => GetRecommendUser(baseuser.UserId)).ToList();
            return PartialView(userlist.OrderByDescending(n => n.Rate.TotalRate));
        }

partMathUser 就是一個專門用來比對的函數。原理就是撈出來一個一個比對,三個條件全部對了就是true。搜索也是一個道理,前台把條件傳過來,后台來處理。我想這個地方應該是很有優化的空間。

 3.推薦度和熱度

  計算推薦度,就是看兩者資料的匹配度,而熱度大家可以去看模型就知道了,就是統計數據再綜合排名。換成百分率。

        /// <summary>
        /// 用戶熱度,相互符合度,生活觀契合度
        /// </summary>
        /// <param name="selfid">本人</param>
        /// <param name="otherid">比較者</param>
        /// <returns></returns>
        public RecommendRate GetRecommendRate(int selfid, int otherid)
        {
            var usersum = LoveDb.UserAll().Count;
            //得到兩個人的需求表 來計算相互符合度
            var myre = LoveDb.One((Requirement r) => r.UserId == selfid);
            var youre = LoveDb.One((Requirement r) => r.UserId == otherid);
            var yourUnin = LoveDb.GetUninUser(otherid);
            var me = GetMyself();
            var rr = new RecommendRate
            {
                //用戶熱度排名UserHotRate
                UserHotRate = (double)(usersum - LoveDb.UserHotAllDes().FindIndex(n => n.UserId == otherid)) / usersum,
                ForMeRate = TomeRate(yourUnin, myre),
                ForOtherRate = TomeRate(me, youre),
                LoveViwRate = GetLoveViewRate(yourUnin, me)
            };
            rr.TotalRate = (rr.UserHotRate + rr.LoveViwRate + rr.ForMeRate + rr.ForOtherRate) / 4;

            return rr;
        }

其他就沒啥好說的,各種return json,return partview() 我想這個是容易看明白的。

 

三、數據層

 1.LoveDb倉庫,像單例模式,獲取實例,用反射封裝了Add,Delete,One,All等常用方法。  

 public class LoveDbRepository
    {
        private static LoveDbRepository _loveDb;

        private LoveDbRepository()
        {
        }

        public static LoveDbRepository GetIntance()
        {
            return _loveDb ?? (_loveDb = new LoveDbRepository());
        }

        #region  常規方法 Add Delete All One  Ones LastOne

        #region Add
        
        public void Add<T>(T t)
        {
            using (var loveDb = new LoveDb())
            {
                switch (t.GetType().Name)
                {
                    case "User":
                        loveDb.Users.Add(t as User);
                        break;
                    case "BaseInfo":
                        loveDb.BaseInfos.Add(t as BaseInfo);
                        break;
                    case "Requirement":
                        loveDb.Requirements.Add(t as Requirement);
                        break;
                    case "DetailInfo":
                        loveDb.DetailInfos.Add(t as DetailInfo);
                        break;
                    case "LoveView":
                        loveDb.LoveViews.Add(t as LoveView);
                        break;
                    case "InfoStatistic":
                        loveDb.InfoStatistics.Add(t as InfoStatistic);
                        break;
                    case "UserHot":
                        loveDb.UserHots.Add(t as UserHot);
                        break;
                     //..................break;
                }
                loveDb.SaveChanges();
            }
        }
........................

2.數據遷移。修改model,自動更新數據庫。這個也是老生常談了,也可以看博客 http://www.cnblogs.com/stoneniqiu/archive/2013/06/04/3117499.html 

namespace Findlover.Migrations
{
    using System.Data.Entity;
    using System.Data.Entity.Migrations;

    internal sealed class Configuration<TContext> : DbMigrationsConfiguration<TContext> where TContext : DbContext
    {
        public Configuration()
        {
            AutomaticMigrationsEnabled = true;
            AutomaticMigrationDataLossAllowed = true;    
        }

        protected override void Seed(TContext context)
        {
            
        }
    }
}

 再就是Lambda ,linq。到處都是,沒有寫一句sql語句。這個沒什么說的。

 

四、問題和擴展

     大大小小的問題還是蠻多的,兼容性的,腳本的,邏輯的,性能的,結構的。這些都還要慢慢的改。所以有問題不要驚奇,是很正常的。像上傳和文本編輯應該換uploadfy和ckeditor控件。這個版本還么有加入分頁,或者換成流行的滾動加載。增加一些好玩的功能,這些就要看你們的了,盡情的去折騰吧。小丘比特謝謝你!

  祝你幸福~

 

 

 

五、說下開源

 CodePlex和gitHub合作了,CodePlex可以用git上傳,而git也變成了這個windows風格: 方便大方好用。

 

在github的工程名稱叫FindLover(說DreamLover更合適些吧),因為FindLover是先取的,名字想了很久才叫意中人。

 

總結下:現在MVC5已經出來了,我還在看MVC4,EntityFrameWork6也來了,還有VS2013,.NetFrameWork4.5。Bootstrap也到3了。Html5動畫研究的還不咋地,還有各種前端的,后端的框架,目不暇接,人艱不拆啊。

新的技術提供了一些更好的方式,但是你更需要的是一個方向,一個ideal,幾個一條路上的小伙伴。

需要源碼的同學請 猛擊這里!!!! https://github.com/stoneniqiu/FindLover  (幫助文檔還有其他說明)

( 下載后可能又的問題。

    1.缺少引用:請在package1中找缺少的引用。 建議安裝Nuget ,會自動給你還原。

    2.不能生產表格。是因為沒有EntityFramework.  沒有啟用codefirst 功能。可以參考博客:http://www.cnblogs.com/stoneniqiu/archive/2013/06/04/3117499.html

     我晚上再補上創建表的SQL命令。 數據庫我不傳了。

    3.缺少kendo.MVC.dll 這個dll沒有包含在package1中,我也奇怪。漏掉了。可以在http://download.csdn.net/my/uploads 下載。 晚上我也會更新到github上去。

    4.缺少引用的dll中,只有Nlog,kendo.MVC,Web.Provider是有用的,其他的缺少的dll可以移除。是因為之前做過其他的測試留下的。

    還有問題可以給我留言

      )

最新版本:http://pan.baidu.com/s/1pJoiM1P

DB:http://pan.baidu.com/s/1gdkvvu7

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM