PHP+Mysql+jQuery+fullcalendar实现的微型公司内部订餐系统
需求相关: 公司20人左右, 每天中午, 下午两次订餐, 都是助理在群里说"开始订餐", 然后大家报菜名, 然后助理统计, 打电话. 今天, 助理说"开始订餐, 订什么密聊...", 突然就想做这么个东西....耗时: 4.5小时
评估: 时间太短, 不能做到很好, 没有什么输入验证之类, 就自己公司内部一点人, 用用应该没啥问题.....bug估计很多...应该是没时间改bug的, 不过有不足之处请大家提出, 互相学习.
提醒: 由于我这边和服务器有个时差, 所以, 里面有代码在倒时差.....另外, 13点之前被认为是上午, 之后包括13点被认为是下午, 一天两次.
本文涉及到的插件: jQuery, jQuery.UI, fullcalendar
数据库创建:
CREATE TABLE USER
(
ID INT PRIMARY KEY AUTO_INCREMENT,
NAME VARCHAR(100)
);
CREATE TABLE ITEM
(
ID INT PRIMARY KEY AUTO_INCREMENT,
USER_ID INT,
FOOD TINYBOLB,
ORDER_TIME TIMESTAMP
);
ALTER TABLE ITEM ADD FOREIGN KEY(USER_ID) REFERENCES USER(ID) ON DELETE CASCADE;
一个实体的基类, 封装的不太好...呵呵
<?php/*** 实体基类* @author selfimpr* @blog http://blog.csdn.net/lgg201* @email lgg860911@yahoo.com.cn**/class Entity {protected static $_mapping = array();public static function getField($column_name) {return self::$_mapping[$column_name] ? self::$_mapping[$column_name] : $column_name;}public function set($field, $value) {$method = 'set'.ucwords($field);return $this->$method($value);}public function get() {$method = 'get'.ucwords($field);return $this->$method();}}?>
用户类(这个里面是没有权限, 登录的概念的, 就公司内部一个小东西)
<?phprequire_once './Entity.php';/*** 用户实体类* @author selfimpr* @blog http://blog.csdn.net/lgg201* @email lgg860911@yahoo.com.cn**/class User extends Entity {private $id;private $name;public function User($id = NULL, $name = NULL) {$this->id = $id;$this->name = $name;}public function getId() {return $this->id;}public function setId($id) {$this->id = $id;return $this;}public function getName() {return $this->name;}public function setName($name) {$this->name = $name;return $this;}}?>
订餐订单项类
<?phprequire_once './Entity.php';/*** 订餐订单* @author selfimpr* @blog http://blog.csdn.net/lgg201* @email lgg860911@yahoo.com.cn**/class Item extends Entity {private $id;private $user;private $food;private $orderTime;public function Item($id = NULL, $food = NULL, $orderTime = NULL) {$this->id = $id;$this->food = $food;$this->orderTime = $orderTime;}public function getId() {return $this->id;}public function setId($id) {$this->id = $id;return $this;}public function getUser() {return $this->user;}public function setUser($user) {$this->user = $user;return $this;}public function getFood() {return $this->food;}public function setFood($food) {$this->food = $food;return $this;}public function getOrderTime() {return $this->orderTime;}public function setOrderTime($orderTime) {$this->orderTime = $orderTime;return $this;}}?>
数据库工具类
<?php/*** Mysql工具类* @author selfimpr* @blog http://blog.csdn.net/lgg201* @email lgg860911@yahoo.com.cn**/class Mysql {private $host;private $username;private $password;private $db_name;private $character_set;public function __construct($host = "192.168.2.10",$username = "root", $password = "jhx", $db_name = "eat", $character_set = "GBK") {$this->host = $host;$this->username = $username;$this->password = $password;$this->db_name = $db_name;$this->character_set = $character_set;}public function getConn() {$conn = mysql_connect($this->host, $this->username, $this->password) or die('数据库连接失败');mysql_select_db($this->db_name, $conn);mysql_set_charset($this->character_set, $conn);return $conn;}/*** * @param $sql 查询用的sql* @param $result 查询得到的结果集, 如果UPDATE, INSERT, DELETE 不同提供这个参数* @return SELECT 返回查询得到的条数, UPDATE, INSERT, DELETE返回bool型, 标识是否执行成功.*/public function execute($sql) {$conn = $this->getConn();$resultset = mysql_query($sql, $conn) or die(mysql_error($conn));if(!is_bool($resultset)) {while($line = mysql_fetch_assoc($resultset)) {$result[] = $line;}} else {$result = $resultset;}mysql_close($conn) or die(mysql_error($conn));//echo "【".$sql."】 excute success!<br />";return $result;}}?>
业务逻辑(没时间了就写一个文件里了)
<?phprequire_once './mysql_util.php';require_once './User.php';require_once './Item.php';/*** 获取当前库中所有的用户* @return unknown_type*/function getUsers() {$util = new Mysql();$users_data = $util->execute("SELECT * FROM USER");foreach($users_data as $index => $data) {$user = new User();foreach($data as $column_name => $value) {$user->set(User::getField($column_name), $value);}$users[] = $user;}return $users;}/*** 根据名字增加一个用户* @param $name* @return unknown_type*/function addUser($name) {$util = new Mysql();$name = iconv("UTF-8", "gbk" , $name);return $util->execute("INSERT INTO USER VALUES(NULL, '$name')");}/*** 根据id删除一个用户* @param $id* @return unknown_type*/function deleteUser($id) {$util = new Mysql();return $util->execute("DELETE FROM USER WHERE ID = $id");}/*** 根据id修改姓名* @param $id* @param $name* @return unknown_type*/function updateUser($id, $name) {$util = new Mysql();return $util->execute("UPDATE USER SET NAME = '$name' WHERE ID = $id");}/*** 插入一条订餐记录* @param $user_id* @param $food* @return unknown_type*/function addItem($user_id, $food, $ordertime) {$util = new Mysql();$year = date('Y', $ordertime);$month = date('n', $ordertime);$day = date('j', $ordertime);$hour = (date('G', $ordertime) + 8) % 24;$flag = $hour < 13;$item = getItemByTimeAndUser($year, $month, $day, $flag, $user_id);$ordertime = "$year-$month-$day $hour:00:00";$item && ($item = $item) && ($flag = $flag ? ' < ' : ' >= ');return $item? $util->execute("UPDATE ITEM SET FOOD = '$food' WHERE USER_ID = $user_id AND YEAR(ORDER_TIME) = $year AND MONTH(ORDER_TIME) = $month AND DAY(ORDER_TIME) = $day AND HOUR(ORDER_TIME) $flag 13"): $util->execute("INSERT INTO ITEM(USER_ID, FOOD, ORDER_TIME) VALUES($user_id, '$food', '$ordertime')");}/*** 获取某天上午或下午的订餐* @param $year* @param $month* @param $day* @param $flag 上午true下午false* @return unknown_type*/function getItemsByTime($year, $month, $day, $flag) {$util = new Mysql();$flag = $flag ? ' < ' : ' >= ';$item_datas = $util->execute("SELECT ITEM.*, USER.NAME FROM ITEM JOIN USER ON ITEM.USER_ID = USER.ID WHERE YEAR(ORDER_TIME) = $year AND MONTH(ORDER_TIME) = $month AND DAY(ORDER_TIME) = $day AND HOUR(ORDER_TIME) $flag 13");if(empty($item_datas)) return array();foreach($item_datas as $index => $data) {$item = new Item();$items[$data['USER_ID']] = $item->setId($data['ID'])->setUser(new User($data['USER_ID'], $data['NAME']))->setFood($data['FOOD'])->setOrderTime(date($data['ORDER_TIME']));}return $items;}/*** 根据用户id, 时间, 获取其订饭记录* @param $year* @param $month* @param $day* @param $flag* @param $user_id* @return unknown_type*/function getItemByTimeAndUser($year, $month, $day, $flag, $user_id) {$util = new Mysql();$flag = $flag ? ' < ' : ' >= ';$item_datas = $util->execute("SELECT ITEM.*, USER.NAME FROM ITEM JOIN USER ON ITEM.USER_ID = USER.ID WHERE YEAR(ORDER_TIME) = $year AND MONTH(ORDER_TIME) = $month AND DAY(ORDER_TIME) = $day AND HOUR(ORDER_TIME) $flag 13 AND ITEM.USER_ID = $user_id");echo "SELECT ITEM.*, USER.NAME FROM ITEM JOIN USER ON ITEM.USER_ID = USER.ID WHERE YEAR(ORDER_TIME) = $year AND MONTH(ORDER_TIME) = $month AND DAY(ORDER_TIME) = $day AND HOUR(ORDER_TIME) $flag 13 AND ITEM.USER_ID = $user_id";if(empty($item_datas)) return array();foreach($item_datas as $index => $data) {$item = new Item();$items[] = $item->setId($data['ID'])->setUser(new User($data['USER_ID'], $data['NAME']))->setFood($data['FOOD'])->setOrderTime(date($data['ORDER_TIME']));}return $items;}?>
单元测试
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"><?phprequire_once './mysql_util.php';require_once './bussiness.php';/*** 本程序业务逻辑之下部分的单元测试* @author selfimpr* @blog http://blog.csdn.net/lgg201* @email lgg860911@yahoo.com.cn*//*** 测试用例1: 数据库连接*///$util = new Mysql();//$res = $util->execute('SHOW TABLES');//print_r($res);//echo '<br>==========数据库连接成功===========<br>';/*** 测试用例2: 获取所有用户*///var_dump(getUsers());/*** 测试用例3: 增加用户*///var_dump(addUser("张三"));/*** 测试用例4: 删除用户*///var_dump(deleteUser(4));/*** 测试用例5: 更新用户*///var_dump(updateUser(5, '李四'));/*** 测试用例6: 插入订餐项*///var_dump(addItem(1, '辣子鸡丁'));/*** 测试用例7: 获取某天上午或下午订餐*///var_dump(getItemsByTime(2010, 6, 4, false));/*** 测试用例8: 获取某人某天上午或下午订餐*///var_dump(getItemByTimeAndUser(date('Y'), date('m'), date('d'), date('H') + 8 < 13, 1));?>
添加用户的Ajax接口
<?phprequire_once './bussiness.php';/*** 添加用户ajax请求*/return addUser($_POST['name']);?>
删除用户的ajax接口
<?phprequire_once './bussiness.php';/*** 删除用户ajax请求*/return deleteUser($_POST['id']);?>
提交订餐项的ajax接口
<?phprequire_once './bussiness.php';$userId = $_POST['userId'];$food = $_POST['food'];$t = $_POST['t'];/*** 提交一个订餐请求的ajax地址*/echo (string)addItem($userId, $food, $t);?>
展现订餐项的视图:
<?php/*** 展现某个订餐时间的所有订餐项*/require_once './bussiness.php';$t = $_GET['t'];$year = date('Y', $t);$month = date('n', $t);$day = date('j', $t);$hour = (date('G', $t) + 8) % 24;$flag = $hour < 13;$items = getItemsByTime($year, $month, $day, $flag);$users = getUsers();?><meta http-equiv="Content-Type" content="text/html; charset=UTF-8"><table cellspacing="0"><tr><th colspan="7">谁填谁的, 填完"吃啥"点下后面的"就吃这个"</th></tr><tr align="center"><td>名字</td><td>吃啥</td><td>操作</td><td>分水岭</td><td>名字</td><td>吃啥</td><td>操作</td></tr><?php foreach($users as $index => $user) {if($index % 2 !== 0) continue;?><tr class="ctrl-record" userId="<?php echo $user->getId(); ?>"><td><?php echo iconv('gbk', 'utf-8', $user->getName()); ?></td><td><input class="food-input ctrl-food-input" type="text" value="<?php echo $items[$user->getId()] ? $items[$user->getId()]->getFood() : ''; ?>"></td><td><button class="ctrl-submit">就吃这个</button></td><td>-|分|-</td><td><?php if($users[$index + 1]) echo iconv('gbk', 'utf-8', $users[$index + 1]->getName()); else echo ''; ?></td><td><input class="food-input ctrl-food-input" type="text" value="<?php if($users[$index + 1]) echo $items[$users[$index + 1]->getId()] ? $items[$users[$index + 1]->getId()]->getFood() : ''; else echo ''; ?>"></td><td><button class="ctrl-submit">就吃这个</button></td></tr><?php}?></table>
展现所有用户的视图
<?phprequire_once './bussiness.php';/*** 系统中用户的管理界面* @author selfimpr* @blog http://blog.csdn.net/lgg201* @email lgg860911@yahoo.com.cn*/$users = getUsers();?><meta http-equiv="Content-Type" content="text/html; charset=UTF-8"><input type="text" id="new_user_input" onkeyup="javascript: event.keyCode == 13 && $('#new_user').click();" /><button id="new_user">新增</button><?php if(empty($users)) return ;?><div style="width: 300px; clear: both;"><?php foreach($users as $index => $user) {?><div class="ctrl-record" style="width: 120px; padding: 10px; height: 70px; border: 1px solid #808080; background: #E8E8E8; float: left; display: block; margin: 5px;" userId="<?php echo $user->getId(); ?>"><input type="text" value="<?php echo iconv('gbk', 'utf-8', $user->getName()); ?>" style="display: block; width: 100px; height: 20px; line-height: 20px;"/><button class="ctrl-del-user" style="width: 100px; height: 25px; margin-top: 5px;">删除</button></div></div><?php}?>
系统的入口index.php
<?php /*** 程序入口*/?><!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN""http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"><html><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8"><link rel='stylesheet' type='text/css' href="./styles/ui.all.css" mce_href="styles/ui.all.css" /><link rel='stylesheet' type='text/css' href="./styles/fullcalendar.css" mce_href="styles/fullcalendar.css" /><link rel='stylesheet' type='text/css' href="./styles/eat.css" mce_href="styles/eat.css" /><mce:script type='text/javascript' src="./scripts/jquery.js" mce_src="scripts/jquery.js"></mce:script><mce:script type='text/javascript' src="./scripts/jquery-ui-1.7.2.custom.js" mce_src="scripts/jquery-ui-1.7.2.custom.js"></mce:script><mce:script type='text/javascript' src="./scripts/fullcalendar.js" mce_src="scripts/fullcalendar.js"></mce:script><mce:script type='text/javascript' src="./scripts/eat.js" mce_src="scripts/eat.js"></mce:script></head><body><button id="maintain">加人</button><div id='calendar' class="wrapper"></div></body></html>
系统涉及的javascript: eat.js
$(document).ready(function() {/*** 计算一月有多少天*/function daysInMonth(month,year) {var dd = new Date(year, month, 0);return dd.getDate();} /*** 预置日历初始化使用日期, 当天*/var date = new Date();var d = date.getDate();var m = date.getMonth();var y = date.getFullYear();/*** 初始化日历中每天里面的上下午日程*/var day_nums = daysInMonth(m, y);var events = new Array();for(var i = 1; i < day_nums; i ++) {events.push({title: '上午吃啥', start: new Date(y, m, i, 1), end: new Date(y, m, i, 11)});events.push({title: '下午吃啥', start: new Date(y, m, i, 14), end: new Date(y, m, i, 23)});}/*** 初始化日历*/$('#calendar').fullCalendar({year: y, month: m, day: d, defaultView: 'month', events: events, header: {left: '', center: 'title', right: ''}, aspectRatio: 1.6, weekMode: 'variable', eventClick: function(calEvent, jsEvent, view) {/*** 日程被点击后, 加载该时段的订餐视图*/$('<div>').load('./viewItems.php?t=' + (calEvent.start / 1000), function() {var self= this;/*** 订餐的提交*/$('.ctrl-submit', this).bind('click', function(event) {var record = $(this).parents('tr.ctrl-record').get(0);var userId = $(record).attr('userId');var food = $('.ctrl-food-input', record).val();$(self).dialog('close');$.ajax({type: 'POST', url: './submitItem.php', data:'userId=' + userId + '&food=' + food + '&t=' + (calEvent.start / 1000), async: false,success: function(res) {$('<div>').text('嘿嘿嘿, 吃好喝好啊.').dialog({resizable: false, modal: true, title: '订了, 该干啥干啥吧.', width: 600, close: function() {$(this).dialog('destroy').remove();}, buttons: {'就是关的时候方便点1': function() {$(this).dialog('close');}, '就是关的时候方便点2': function() {$(this).dialog('close');}, '就是关的时候方便点3': function() {$(this).dialog('close');}}});}});});/*** 把加载到的订餐视图预置为jqueryUI.dialog*/var t = new Date(calEvent.start);$(this).css('margin', '0 auto').dialog({resizable: false, modal: true, title: '[' + t.getFullYear() + '年' + (t.getMonth() + 1) + '月' + t.getDay() + '日' + (t.getHours() > 13 ? '下午' : '上午') + ']----你想吃啥啊?', width: 1000, close: function() {$(this).dialog('destroy').remove();}, buttons: {'就是关的时候方便点1': function() {$(this).dialog('close');}, '就是关的时候方便点2': function() {$(this).dialog('close');}, '就是关的时候方便点3': function() {$(this).dialog('close');}}});});}});/*** 修改当天的DOM, 加明显标记*/$('.fc-today').append('<div style="margin-top: 40px; color: #888933; font-size: 20px; font-weight: bold;" mce_style="margin-top: 40px; color: #888933; font-size: 20px; font-weight: bold;">这里是今天</div>');/*** 加人按钮, 用来加载用户管理界面*/$('#maintain').bind('click', function(event) {$('<div>').load('./viewUsers.php', function() {$(this).dialog({resizable: false, modal: true, title: '嘿嘿, 吃着喝着啊', width: 1128,height: 450, close: function() {$(this).dialog('destroy').remove();}, buttons: {'就是关的时候方便点1': function() {$(this).dialog('close');}, '就是关的时候方便点2': function() {$(this).dialog('close');}, '就是关的时候方便点3': function() {$(this).dialog('close');}, '就是关的时候方便点4': function() {$(this).dialog('close');}}});bindMaitainArea(this);});});/*** 用户管理界面加载完毕之后, 对其上的按钮绑定事件*/var bindMaitainArea = (function(context) {/*** 新增用户的事件*/$('#new_user', context).bind('click', function(event) {var self = this;$.ajax({type: 'POST', url: './addUser.php', data:'name=' + $('#new_user_input').val(), timeout:8000,async: false,success: function(res) {$(self).parents('.ui-dialog-content').load('./viewUsers.php', function() {bindMaitainArea();});}});});/*** 删除用户的事件*/$('.ctrl-del-user', context).bind('click', function(event) {var self = this;$.ajax({type: 'POST', url: './delUser.php', data:'id=' + $(self).parents('.ctrl-record').attr('userId'), timeout:8000,async: false,success: function(res) {$(self).parents('.ui-dialog-content').load('./viewUsers.php', function() {bindMaitainArea();});}});});});});
系统涉及的自定义样式eat.css
@CHARSET "UTF-8";body{font-size: 75%;}.wrapper{width: 1024px; margin: 0 auto;}.food-input{width: 300px; border: 1px solid #E0E0E0;}table{border-left: 1px solid #D0D0D0; border-top: 1px solid #D0D0D0;}th, td{border-right: 1px solid #D0D0D0; border-bottom: 1px solid #D0D0D0;}
页:
[1]